Skip to content

Commit a612489

Browse files
committed
console: add trace-events for time and count
Add the `node.console` trace event category to capture `console.count()`, `console.countReset()`, `console.time()`, `console.timeLog()`, and `console.timeEnd()` to the trace event log. PR-URL: #23703 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com>
1 parent 6c8a96f commit a612489

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

doc/api/tracing.md

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ The available categories are:
1818
The [`async_hooks`] events have a unique `asyncId` and a special `triggerId`
1919
`triggerAsyncId` property.
2020
* `node.bootstrap` - Enables capture of Node.js bootstrap milestones.
21+
* `node.console` - Enables capture of `console.time()` and `console.count()`
22+
output.
2123
* `node.environment` - Enables capture of Node.js Environment milestones.
2224
* `node.fs.sync` - Enables capture of trace data for file system sync methods.
2325
* `node.perf` - Enables capture of [Performance API] measurements.

lib/console.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
'use strict';
2323

24+
const { trace } = internalBinding('trace_events');
2425
const {
2526
isStackOverflowError,
2627
codes: {
@@ -37,6 +38,12 @@ const {
3738
} = util.types;
3839
const kCounts = Symbol('counts');
3940

41+
const kTraceConsoleCategory = 'node,node.console';
42+
const kTraceCount = 'C'.charCodeAt(0);
43+
const kTraceBegin = 'b'.charCodeAt(0);
44+
const kTraceEnd = 'e'.charCodeAt(0);
45+
const kTraceInstant = 'n'.charCodeAt(0);
46+
4047
const {
4148
keys: ObjectKeys,
4249
values: ObjectValues,
@@ -232,13 +239,15 @@ Console.prototype.time = function time(label = 'default') {
232239
process.emitWarning(`Label '${label}' already exists for console.time()`);
233240
return;
234241
}
242+
trace(kTraceBegin, kTraceConsoleCategory, `time::${label}`, 0);
235243
this._times.set(label, process.hrtime());
236244
};
237245

238246
Console.prototype.timeEnd = function timeEnd(label = 'default') {
239247
// Coerces everything other than Symbol to a string
240248
label = `${label}`;
241249
const hasWarned = timeLogImpl(this, 'timeEnd', label);
250+
trace(kTraceEnd, kTraceConsoleCategory, `time::${label}`, 0);
242251
if (!hasWarned) {
243252
this._times.delete(label);
244253
}
@@ -248,6 +257,7 @@ Console.prototype.timeLog = function timeLog(label, ...data) {
248257
// Coerces everything other than Symbol to a string
249258
label = `${label}`;
250259
timeLogImpl(this, 'timeLog', label, data);
260+
trace(kTraceInstant, kTraceConsoleCategory, `time::${label}`, 0);
251261
};
252262

253263
// Returns true if label was not found
@@ -308,6 +318,7 @@ Console.prototype.count = function count(label = 'default') {
308318
else
309319
count++;
310320
counts.set(label, count);
321+
trace(kTraceCount, kTraceConsoleCategory, `count::${label}`, 0, count);
311322
this.log(`${label}: ${count}`);
312323
};
313324

@@ -318,7 +329,7 @@ Console.prototype.countReset = function countReset(label = 'default') {
318329
process.emitWarning(`Count for '${label}' does not exist`);
319330
return;
320331
}
321-
332+
trace(kTraceCount, kTraceConsoleCategory, `count::${label}`, 0, 0);
322333
counts.delete(`${label}`);
323334
};
324335

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cp = require('child_process');
5+
const path = require('path');
6+
const fs = require('fs');
7+
const tmpdir = require('../common/tmpdir');
8+
9+
// Tests that node.console trace events for counters and time methods are
10+
// emitted as expected.
11+
12+
const names = [
13+
'time::foo',
14+
'count::bar'
15+
];
16+
const expectedCounts = [ 1, 2, 0 ];
17+
const expectedTimeTypes = [ 'b', 'n', 'e' ];
18+
19+
if (process.argv[2] === 'child') {
20+
// The following console outputs exercise the test, causing node.console
21+
// trace events to be emitted for the counter and time calls.
22+
console.count('bar');
23+
console.count('bar');
24+
console.countReset('bar');
25+
console.time('foo');
26+
setImmediate(() => {
27+
console.timeLog('foo');
28+
setImmediate(() => {
29+
console.timeEnd('foo');
30+
});
31+
});
32+
} else {
33+
tmpdir.refresh();
34+
35+
const proc = cp.fork(__filename,
36+
[ 'child' ], {
37+
cwd: tmpdir.path,
38+
execArgv: [
39+
'--trace-event-categories',
40+
'node.console'
41+
]
42+
});
43+
44+
proc.once('exit', common.mustCall(async () => {
45+
const file = path.join(tmpdir.path, 'node_trace.1.log');
46+
47+
assert(fs.existsSync(file));
48+
const data = await fs.promises.readFile(file, { encoding: 'utf8' });
49+
JSON.parse(data).traceEvents
50+
.filter((trace) => trace.cat !== '__metadata')
51+
.forEach((trace) => {
52+
assert.strictEqual(trace.pid, proc.pid);
53+
assert(names.includes(trace.name));
54+
if (trace.name === 'count::bar')
55+
assert.strictEqual(trace.args.data, expectedCounts.shift());
56+
else if (trace.name === 'time::foo')
57+
assert.strictEqual(trace.ph, expectedTimeTypes.shift());
58+
});
59+
assert.strictEqual(expectedCounts.length, 0);
60+
assert.strictEqual(expectedTimeTypes.length, 0);
61+
}));
62+
}

0 commit comments

Comments
 (0)