Skip to content

Commit

Permalink
trace_events: export v8 trace api
Browse files Browse the repository at this point in the history
export v8 trace api, so user can use it to trace custom events
and collect the data by using inspector or the
trace_events.createTracing method
  • Loading branch information
theanarkh committed Mar 27, 2022
1 parent 934a3aa commit 46314ef
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 14 deletions.
55 changes: 55 additions & 0 deletions doc/api/tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,61 @@ t2.enable();
console.log(trace_events.getEnabledCategories());
```

### `trace_events.trace(phase, category, name, id, data)`

<!-- YAML
added: REPLACEME
-->

use `trace_events.trace` to product trace events data, then this data can be
collected by the `inspector` module or the `trace_events.createTracing` method.

The following example is used to product custom trace event, and collect
the data by using the inspector.

```js
'use strict';

const {
trace,
events: {
TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN: kBeforeEvent
},
} = require('trace_events');

const { Session } = require('inspector');

const session = new Session();

function post(message, data) {
return new Promise((resolve, reject) => {
session.post(message, data, (err, result) => {
if (err)
reject(new Error(JSON.stringify(err)));
else
resolve(result);
});
});
}

async function test() {
session.connect();
const events = [];
session.on('NodeTracing.dataCollected', (n) => {
events.push(...n.params.value.filter((v) => v.cat !== '__metadata'));
});
session.on('NodeTracing.tracingComplete', () => console.log(events));

const traceConfig = { includedCategories: ['custom'] };
await post('NodeTracing.start', { traceConfig });
trace(kBeforeEvent, 'custom', 'hello', 0, 'world');
await post('NodeTracing.stop', { traceConfig });
session.disconnect();
}

test();
```

[Performance API]: perf_hooks.md
[V8]: v8.md
[`Worker`]: worker_threads.md#class-worker
Expand Down
9 changes: 6 additions & 3 deletions lib/trace_events.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const { hasTracing } = internalBinding('config');
const kHandle = Symbol('handle');
const kEnabled = Symbol('enabled');
const kCategories = Symbol('categories');

const { isMainThread } = require('worker_threads');
const kMaxTracingCount = 10;

const {
Expand All @@ -24,7 +24,8 @@ const { ownsProcessState } = require('internal/worker');
if (!hasTracing || !ownsProcessState)
throw new ERR_TRACE_EVENTS_UNAVAILABLE();

const { CategorySet, getEnabledCategories } = internalBinding('trace_events');
const { CategorySet, getEnabledCategories, trace } = internalBinding('trace_events');
const constants = internalBinding('constants');
const { customInspectSymbol } = require('internal/util');
const { format } = require('internal/util/inspect');
const {
Expand Down Expand Up @@ -98,5 +99,7 @@ function createTracing(options) {

module.exports = {
createTracing,
getEnabledCategories
getEnabledCategories,
trace: isMainThread ? trace : null,
events: constants.trace
};
54 changes: 54 additions & 0 deletions test/parallel/test-trace-events-api-trace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict';

const common = require('../common');
common.skipIfWorker(); // https://github.com/nodejs/node/issues/22767

const assert = require('assert');
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
const tmpdir = require('../common/tmpdir');

if (process.argv[2] === 'isChild') {
const {
createTracing,
trace,
events: {
TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN: kBeforeEvent,
TRACE_EVENT_PHASE_NESTABLE_ASYNC_END: kEndEvent
},
} = require('trace_events');

const tracing = createTracing({ categories: [ 'custom' ] });
tracing.enable();
trace(kBeforeEvent, 'custom', 'hello', 0, 'world');
setTimeout(() => {
trace(kEndEvent, 'custom', 'hello', 0, 'world');
tracing.disable();
}, 1);
} else {
tmpdir.refresh();
const parentDir = process.cwd();
process.chdir(tmpdir.path);
const proc = cp.fork(__filename, ['isChild'], {
execArgv: [
'--trace-event-categories',
'custom',
]
});

proc.once('exit', common.mustCall(() => {
const file = path.join(tmpdir.path, 'node_trace.1.log');
assert(fs.existsSync(file));
fs.readFile(file, { encoding: 'utf-8' }, common.mustSucceed((data) => {
const traces = JSON.parse(data).traceEvents.filter((trace) => trace.cat !== '__metadata');
assert.strictEqual(traces.length, 2);
traces.forEach((trace) => {
assert.strictEqual(trace.cat, 'custom');
assert.strictEqual(trace.name, 'hello');
assert.strictEqual(trace.args.data, 'world');
});
}));
process.chdir(parentDir);
}));
}
18 changes: 7 additions & 11 deletions test/parallel/test-trace-events-dynamic-enable.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
// Flags: --expose-internals
'use strict';

const common = require('../common');

common.skipIfInspectorDisabled();
common.skipIfWorker(); // https://github.com/nodejs/node/issues/22767

const { internalBinding } = require('internal/test/binding');

const {
trace: {
trace,
events: {
TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN: kBeforeEvent
}
} = internalBinding('constants');

const { trace } = internalBinding('trace_events');
},
} = require('trace_events');

const assert = require('assert');
const { Session } = require('inspector');
Expand All @@ -37,11 +33,11 @@ async function test() {

const events = [];
let tracingComplete = false;
session.on('NodeTracing.dataCollected', (n) => {
session.on('NodeTracing.dataCollected', common.mustCallAtLeast((n) => {
assert.ok(n && n.params && n.params.value);
events.push(...n.params.value); // append the events.
});
session.on('NodeTracing.tracingComplete', () => tracingComplete = true);
}));
session.on('NodeTracing.tracingComplete', common.mustCall(() => tracingComplete = true));

trace(kBeforeEvent, 'foo', 'test1', 0, 'test');

Expand Down

0 comments on commit 46314ef

Please sign in to comment.