Skip to content
This repository has been archived by the owner on Mar 15, 2024. It is now read-only.

Commit

Permalink
feat: tweak the API and update the reference doc
Browse files Browse the repository at this point in the history
  • Loading branch information
lachrist committed Feb 7, 2022
1 parent 2fcebda commit c518b17
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 41 deletions.
113 changes: 106 additions & 7 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const appmap = createAppmap(
);
// NB: An appmap can create multiple (concurrent) tracks
const track = "my-identifier";
appmap.start(track, {
appmap.startTrack(track, {
app: "my-app-name",
name: "my-appmap-name",
pruning: true,
Expand All @@ -139,13 +139,112 @@ appmap.recordScript(
"(function main () { return 123; } ());",
"path/to/main.js",
);
const trace = appmap.stop(track, {
const trace = appmap.stopTrack(track, {
status: 0,
errors: []
errors: []
});
console.log(JSON.stringify(trace, null, 2));
```

### `createAppmap(home, configuration, base)`

* `home <string>` The file url of the project. Default: file url of the current working directory.
* `configuration <object>` Root configuration. Default: `{}`.
* `base <string>` The file url of the directory to resolve the relative paths of the configuration argument.
* Returns `<appmap>` an appmap instance and start recording.

### `appmap.terminate()`

Stop recording. Subsequent method invocations will throw exception.

### `appmap.startTrack(track, configuration, base)`

* `track <string> | null` An identifier for the track. Default: `null`, a random string will be used
* `configuration <object>` Configuration for extending the configuration of the appmap instance. Default: `{}`.
* `base <string> | null`: The file url of the directory to resolve the relative paths of the configuration argument. Default: `null`, the presence of relative paths will throw an error.
* Returns `<string>` the identifier for the track. This is useful when providing `null` for the `track` argument.

### `appmap.stopTrack(track, status, errors)`

* `track <string>`
* `status <number>` Exit status code. Default: `[]`.
* `errors <Errors[]>` List of errors that happened during the track lifetime. Default: `[]`.
* Returns `<object>` the recorded trace in the appmap format -- ie: a JSON object.

### `appmap.recordScript(content, url)`

* `content <string>` Script content.
* `url <string>` Script location.
* Returns `<any>` the completion value of the script.

### `appmap.instrumentScript(content, url)`

* `content <string>` Script content.
* `url <string>` Script location.
* Returns `<string>` the instrumented code to run as a module.

### `appmap.instrumentModule(content, url)`

* `content <string>` Script content.
* `url <string>` Script location.
* Returns `<string>` the instrumented code to run as a script.

### `appmap.recordBeginBundle()`

* Returns `recordEndBundle()`
* Returns `undefined`.

This methods record an anonymous bundle. This event does not appear in the generated appmap but is useful to bundle events together. `appmap.recordApply` and `appmap.recordServerRequest` are also bundle operations.

### `appmap.recordApply(input)`

* `input <object>` The input of the application. We are still figuring out a way to manually define the called function.
* `this <any>` The `this` argument. Default: `undefined`.
* `arguments <any[]>` The list of arguments. Default: `[]`.
* Returns `recordReturn(output)`
* `output <object>` The output of the application. One and only one the two properties must be defined.
* `error: <any>` The thrown value of application (if present).
* `result: <any>` The returned value of the application (if present).
* Returns `undefined`.

### `appmap.recordServerRequest(request)`

* `request <object>` The head of the incoming HTTP request
* `protocol <string>` The HTTP protocol. Default: `"HTTP/1.1"`.
* `method <string>` The HTTP method. Default: `"GET"`.
* `url <string>` The requested URL. Default: `"/"`.
* `headers <object>` The HTTP headers. Default: `{}`.
* `route <string> | null` The normalized requested URL (ie stripped of dynamic data). Default: `"null"`.
* Returns `recordServerResponse(response)`
* `response <object>` The head of the outgoing HTTP response.
* `status <number>` The HTTP status code. Default: `200`.
* `message <string>` The HTTP status message. Default: `"OK"`.
* `headers <object>` The HTTP headers. Default: `{}`.
* Returns `undefined`.

### `appmap.recordBeforeJump()`

* Returns `recordAfterJump()`
* Returns `undefined`.

This methods record an anonymous jump. This event does not appear in the generated appmap but is useful link events togethers. `appmap.recordQuery` and `appmap.recordClientRequest` are also jump operations.

### `appmap.recordQuery(query)`

* `query <object>`
* `database <string>` Name of the database service. Default: `"unknown"`.
* `version <string>` Version of the database service. Default: `"unknown"`.
* `sql <string>` SQL query string. Default: `"unknown"`.
* `parameters <any[]> | <object>` Parameters to replace in placeholders. If placeholders are anonymous, then `parameters` should be an array. If placeholders are named, then `parameters` should be a mapping object. Default: `[]`.
* Returns `recordResult(result)`
* `result <object>`
* `error <Error>` Potential error while processing the query.
* Returns `undefined`.

### `appmap.recordClientRequest(request)`

Same type signature as `appmap.recordServerResponse` but without `route` property. Note that this method records a jump whereas `appmap.recordServerResponse` records a bundle.

## Configuration

The actual format requirements for configuration can be found as a json-schema [here](build/schema/schema.yml).
Expand Down Expand Up @@ -210,7 +309,7 @@ The agent filter code objects (functions or objects/classes) based on a format c
* `<string>` Shorthand, `"test/**/*.mjs"` is the same as `{glob:"test/**/*.mjs", enabled:true}`.
* `<object>`
* `enabled <boolean>` Indicates whether whitelisted files are enabled or not. *Default*: `true`.
* `... <Specifier>` Extends from any specifier format.
* `... <Specifier>` Extends from any specifier format.
*Default*: `[]` -- ie: the agent will be enabled for every process whose entry script resides in the repository directory.
* `scenarios <Configuration[]>` An array of child configuration.
* `scenario <string>` A regular expression to whitelist scenarios for execution. If the root configuration contains a command, it will always be executed. *Default*: `"^"` (every scenario will be executed).
Expand All @@ -228,11 +327,11 @@ The agent filter code objects (functions or objects/classes) based on a format c
* `<string>`: Glob shorthand, `"lib/**/*.js"` is the same as `{glob: "lib/**/*.js"}`.
* `<object>`
* `enabled <boolean>` Indicates whether the filtered file should be instrumented or not. *Default*: `true`.
* `shallow <boolean>` Indicates whether the filtered file should
* `shallow <boolean>` Indicates whether the filtered file should
* `exclude <Exclusion[]>` Additional code object filtering for the matched file.
* `... <Specifier>` Extends from any specifier format.
* `exclude <Exclusion[]>` Code object filtering to apply to every file.
* `source <boolean>` Indicates whether to include source code in the appmap file. *Default* `false`.
* `source <boolean>` Indicates whether to include source code in the appmap file. *Default* `false`.
* `hooks <object>` Flags controlling what the agent intercepts.
* `cjs <boolean>` Indicates whether commonjs modules should be instrumented to record function applications. *Default*: `true`.
* `esm <boolean>` Indicates whether native modules should be instrumented to record function applications. *Default*: `true` for the CLI and `false` for the API.
Expand Down Expand Up @@ -291,7 +390,7 @@ function main () {
name: main
children:
- type: function
name: "()"
name: "()"
- type: class
name: Class
children: []
Expand Down
35 changes: 17 additions & 18 deletions components/recorder-api/default/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ export default (dependencies) => {
},
} = dependencies;
const {
recordBundle,
recordBeginBundle,
recordApply,
recordResponse,
recordJump,
recordServerRequest,
recordBeforeJump,
recordQuery,
recordRequest,
recordClientRequest,
} = Record(dependencies);
let global_running = false;
const makeFile = (type, content, url = "file:///") => {
Expand Down Expand Up @@ -68,7 +68,7 @@ export default (dependencies) => {
expectRunning(this.hooking);
return runScript(this.instrumentScript(content, url));
}
startTrack(track, initialization) {
startTrack(track, conf = {}, base = null) {
expectRunning(this.hooking);
if (track === null) {
track = getUUID();
Expand All @@ -80,21 +80,20 @@ export default (dependencies) => {
);
this.tracks.add(track);
startTrack(this.agent, track, {
path: null,
data: {},
...initialization,
path: base,
data: conf,
});
return track;
}
stopTrack(track, termination) {
stopTrack(track, status = 0, errors = []) {
expectRunning(this.hooking);
expect(
this.tracks.has(track),
"Cannot stop track %j because it is missing.",
track,
);
this.tracks.delete(track);
stopTrack(this.agent, track, { errors: [], status: 0, ...termination });
stopTrack(this.agent, track, { errors, status });
return takeLocalAgentTrace(this.agent, track);
}
terminate() {
Expand All @@ -110,29 +109,29 @@ export default (dependencies) => {
expectRunning(this.hooking);
return getSerializationEmptyValue(this.agent);
}
recordBundle(data) {
recordBeginBundle(data) {
expectRunning(this.hooking);
return recordBundle(this.agent, data);
return recordBeginBundle(this.agent, data);
}
recordApply(data) {
expectRunning(this.hooking);
return recordApply(this.agent, data);
}
recordResponse(data) {
recordServerRequest(data) {
expectRunning(this.hooking);
return recordResponse(this.agent, data);
return recordServerRequest(this.agent, data);
}
recordJump(data) {
recordBeforeJump(data) {
expectRunning(this.hooking);
return recordJump(this.agent, data);
return recordBeforeJump(this.agent, data);
}
recordQuery(data) {
expectRunning(this.hooking);
return recordQuery(this.agent, data);
}
recordRequest(data) {
recordClientRequest(data) {
expectRunning(this.hooking);
return recordRequest(this.agent, data);
return recordClientRequest(this.agent, data);
}
/* c8 ignore stop */
}
Expand Down
4 changes: 2 additions & 2 deletions components/recorder-api/default/index.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ assertEqual(
"string",
);

const track = appmap.startTrack(null, { path: null, data: { name: "name2" } });
const track = appmap.startTrack(null, { name: "name2" }, null);
assertEqual(appmap.recordScript("123;", "file:///base/main.js"), 123);
assertDeepEqual(appmap.stopTrack(track, { status: 123, errors: [] }), {
assertDeepEqual(appmap.stopTrack(track, 123, []), {
configuration: {
...configuration,
name: "name2",
Expand Down
8 changes: 4 additions & 4 deletions components/recorder-api/default/record.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export default (dependencies) => {
};
};
return {
recordBundle: generateRecord(
recordBeginBundle: generateRecord(
recordBeginBundle,
sanitizeNull,
recordEndBundle,
Expand Down Expand Up @@ -133,13 +133,13 @@ export default (dependencies) => {
return data;
},
),
recordResponse: generateRecord(
recordServerRequest: generateRecord(
recordBeginResponse,
generateSanitizeRequest("BeginResponseEvent"),
recordEndResponse,
generateSanitizeResponse("EndResponseEvent"),
),
recordJump: generateRecord(
recordBeforeJump: generateRecord(
recordBeforeJump,
sanitizeNull,
recordAfterJump,
Expand Down Expand Up @@ -168,7 +168,7 @@ export default (dependencies) => {
return data;
},
),
recordRequest: generateRecord(
recordClientRequest: generateRecord(
recordBeforeRequest,
generateSanitizeRequest("BeforeRequestEvent"),
recordAfterRequest,
Expand Down
18 changes: 9 additions & 9 deletions components/recorder-api/default/record.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import Record from "./record.mjs";

const dependencies = await buildTestDependenciesAsync(import.meta.url);
const {
recordBundle,
recordBeginBundle,
recordApply,
recordResponse,
recordJump,
recordServerRequest,
recordBeforeJump,
recordQuery,
recordRequest,
recordClientRequest,
} = Record(dependencies);
const { openAgent, closeAgent, startTrack, stopTrack, takeLocalAgentTrace } =
await buildTestComponentAsync("agent");
Expand Down Expand Up @@ -48,7 +48,7 @@ const test = (
};

test(
recordBundle,
recordBeginBundle,
null,
null,
"begin",
Expand Down Expand Up @@ -77,7 +77,7 @@ test(
);

test(
recordResponse,
recordServerRequest,
null,
null,
"begin",
Expand All @@ -94,7 +94,7 @@ test(
);

test(
recordJump,
recordBeforeJump,
null,
null,
"before",
Expand Down Expand Up @@ -122,7 +122,7 @@ test(
);

test(
recordRequest,
recordClientRequest,
null,
null,
"before",
Expand All @@ -139,7 +139,7 @@ test(
);

test(
recordRequest,
recordClientRequest,
{ headers: { key: "value" }, route: "route" },
null,
"before",
Expand Down
2 changes: 1 addition & 1 deletion test/system/api/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const appmap = createAppmap(
directory,
);

appmap.startTrack("track", { path: null, data: {} });
appmap.startTrack("track");

await writeFileAsync(
new URL(`${directory}/common.js`),
Expand Down

0 comments on commit c518b17

Please sign in to comment.