Skip to content

Commit

Permalink
lib: add diagnostics_channel events to module loading
Browse files Browse the repository at this point in the history
This commit adds a tracing channel for module loading
through `import()` and `require()`.

Co-Authored-By: Stephen Belanger <[email protected]>
PR-URL: nodejs#44340
Reviewed-By: Geoffrey Booth <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Gerhard Stöbich <[email protected]>
  • Loading branch information
2 people authored and bmeck committed Jun 22, 2024
1 parent 2aa9438 commit 7392aa2
Show file tree
Hide file tree
Showing 25 changed files with 398 additions and 37 deletions.
52 changes: 52 additions & 0 deletions doc/api/diagnostics_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,58 @@ Emitted when server receives a request.

Emitted when server sends a response.

#### Modules

`module.require.start`

* `event` {Object} containing the following properties
* `id` - Argument passed to `require()`. Module name.
* `parentFilename` - Name of the module that attempted to require(id).

Emitted when `require()` is executed. See [`start` event][].

`module.require.end`

* `event` {Object} containing the following properties
* `id` - Argument passed to `require()`. Module name.
* `parentFilename` - Name of the module that attempted to require(id).

Emitted when a `require()` call returns. See [`end` event][].

`module.require.error`

* `event` {Object} containing the following properties
* `id` - Argument passed to `require()`. Module name.
* `parentFilename` - Name of the module that attempted to require(id).
* `error` {Error}

Emitted when a `require()` throws an error. See [`error` event][].

`module.import.asyncStart`

* `event` {Object} containing the following properties
* `id` - Argument passed to `import()`. Module name.
* `parentURL` - URL object of the module that attempted to import(id).

Emitted when `import()` is invoked. See [`asyncStart` event][].

`module.import.asyncEnd`

* `event` {Object} containing the following properties
* `id` - Argument passed to `import()`. Module name.
* `parentURL` - URL object of the module that attempted to import(id).

Emitted when `import()` has completed. See [`asyncEnd` event][].

`module.import.error`

* `event` {Object} containing the following properties
* `id` - Argument passed to `import()`. Module name.
* `parentURL` - URL object of the module that attempted to import(id).
* `error` {Error}

Emitted when a `import()` throws an error. See [`error` event][].

#### NET

`net.client.socket`
Expand Down
19 changes: 11 additions & 8 deletions lib/diagnostics_channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@ function tracingChannelFrom(nameOrChannels, name) {

class TracingChannel {
constructor(nameOrChannels) {
for (const eventName of traceEvents) {
for (let i = 0; i < traceEvents.length; ++i) {
const eventName = traceEvents[i];
ObjectDefineProperty(this, eventName, {
__proto__: null,
value: tracingChannelFrom(nameOrChannels, eventName),
Expand All @@ -278,15 +279,16 @@ class TracingChannel {
}

get hasSubscribers() {
return this.start.hasSubscribers ||
this.end.hasSubscribers ||
this.asyncStart.hasSubscribers ||
this.asyncEnd.hasSubscribers ||
this.error.hasSubscribers;
return this.start?.hasSubscribers ||
this.end?.hasSubscribers ||
this.asyncStart?.hasSubscribers ||
this.asyncEnd?.hasSubscribers ||
this.error?.hasSubscribers;
}

subscribe(handlers) {
for (const name of traceEvents) {
for (let i = 0; i < traceEvents.length; ++i) {
const name = traceEvents[i];
if (!handlers[name]) continue;

this[name]?.subscribe(handlers[name]);
Expand All @@ -296,7 +298,8 @@ class TracingChannel {
unsubscribe(handlers) {
let done = true;

for (const name of traceEvents) {
for (let i = 0; i < traceEvents.length; ++i) {
const name = traceEvents[i];
if (!handlers[name]) continue;

if (!this[name]?.unsubscribe(handlers[name])) {
Expand Down
9 changes: 8 additions & 1 deletion lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ let { startTimer, endTimer } = debugWithTimer('module_timer', (start, end) => {
endTimer = end;
});

const { tracingChannel } = require('diagnostics_channel');
const onRequire = getLazy(() => tracingChannel('module.require'));

const isWindows = process.platform === 'win32';

const relativeResolveCache = { __proto__: null };
Expand All @@ -209,7 +212,11 @@ function wrapModuleLoad(request, parent, isMain) {
startTimer(logLabel, traceLabel);

try {
return Module._load(request, parent, isMain);
return onRequire().traceSync(Module._load, {
__proto__: null,
parentFilename: parent?.filename,
id: request,
}, Module, request, parent, isMain);
} finally {
endTimer(logLabel, traceLabel);
}
Expand Down
30 changes: 23 additions & 7 deletions lib/internal/modules/esm/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ const {
} = require('internal/modules/helpers');
let defaultResolve, defaultLoad, defaultLoadSync, importMetaInitializer;

const { tracingChannel } = require('diagnostics_channel');
const onImport = tracingChannel('module.import');

/**
* @typedef {import('url').URL} URL
*/
Expand Down Expand Up @@ -210,10 +213,17 @@ class ModuleLoader {
return compileSourceTextModule(url, source, this);
};
const { ModuleJob } = require('internal/modules/esm/module_job');
const job = new ModuleJob(
this, url, undefined, evalInstance, false, false);
this.loadCache.set(url, undefined, job);
const { module } = await job.run(isEntryPoint);
const module = await onImport.tracePromise(async () => {
const job = new ModuleJob(
this, url, undefined, evalInstance, false, false);
this.loadCache.set(url, undefined, job);
const { module } = await job.run(isEntryPoint);
return module;
}, {
__proto__: null,
parentURL: '<eval>',
url,
});

return {
__proto__: null,
Expand Down Expand Up @@ -470,9 +480,15 @@ class ModuleLoader {
* @returns {Promise<ModuleExports>}
*/
async import(specifier, parentURL, importAttributes, isEntryPoint = false) {
const moduleJob = await this.getModuleJob(specifier, parentURL, importAttributes);
const { module } = await moduleJob.run(isEntryPoint);
return module.getNamespace();
return onImport.tracePromise(async () => {
const moduleJob = await this.getModuleJob(specifier, parentURL, importAttributes);
const { module } = await moduleJob.run(isEntryPoint);
return module.getNamespace();
}, {
__proto__: null,
parentURL,
url: specifier,
});
}

/**
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/console/console.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ Trace: foo
at *
at *
at *
at *
1 change: 1 addition & 0 deletions test/fixtures/errors/force_colors.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ Error: Should include grayed stack trace
 at *
 at *
 at *
 at *

Node.js *
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
at *
at *
at *
at *
(Use `node --trace-warnings ...` to show where the warning was created)
(node:*) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https:*nodejs.org*api*cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
at *
at *
at *
at *
(node:*) Error: This was rejected
at *
at *
Expand All @@ -20,6 +21,7 @@
at *
at *
at *
at *
(node:*) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
at *
at *
Expand Down
1 change: 1 addition & 0 deletions test/message/assert_throws_stack.out
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
at *
at *
at *
at *
at * {
generatedMessage: true,
code: 'ERR_ASSERTION',
Expand Down
1 change: 1 addition & 0 deletions test/message/internal_assert.out
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Please open an issue with this stack trace at https://github.com/nodejs/node/iss
at *
at *
at *
at *
at * {
code: 'ERR_INTERNAL_ASSERTION'
}
Expand Down
1 change: 1 addition & 0 deletions test/message/internal_assert_fail.out
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Please open an issue with this stack trace at https://github.com/nodejs/node/iss
at *
at *
at *
at *
at * {
code: 'ERR_INTERNAL_ASSERTION'
}
Expand Down
30 changes: 20 additions & 10 deletions test/message/util-inspect-error-cause.out
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Error: Number error cause
at *
at *
at *
at *
at * {
[cause]: 42
}
Expand All @@ -17,6 +18,7 @@ Error: Object cause
at *
at *
at *
at *
at * {
[cause]: {
message: 'Unique',
Expand All @@ -33,6 +35,7 @@ Error: undefined cause
at *
at *
at *
at *
at * {
[cause]: undefined
}
Expand All @@ -44,6 +47,7 @@ Error: cause that throws
at *
at *
at *
at *
at * {
[cause]: [Getter]
}
Expand All @@ -53,7 +57,7 @@ RangeError: New Stack Frames
[cause]: FoobarError: Individual message
at *
*[90m at *[39m
*[90m ... 5 lines matching cause stack trace ...*[39m
*[90m ... 6 lines matching cause stack trace ...*[39m
*[90m at *[39m {
status: *[32m'Feeling good'*[39m,
extraProperties: *[32m'Yes!'*[39m,
Expand All @@ -66,17 +70,18 @@ RangeError: New Stack Frames
*[90m at *[39m
*[90m at *[39m
*[90m at *[39m
*[90m at *[39m
}
}
Error: Stack causes
at *
*[90m at *[39m
*[90m ... 5 lines matching cause stack trace ...*[39m
*[90m ... 6 lines matching cause stack trace ...*[39m
*[90m at *[39m {
[cause]: FoobarError: Individual message
at *
*[90m at *[39m
*[90m ... 5 lines matching cause stack trace ...*[39m
*[90m ... 6 lines matching cause stack trace ...*[39m
*[90m at *[39m {
status: *[32m'Feeling good'*[39m,
extraProperties: *[32m'Yes!'*[39m,
Expand All @@ -89,6 +94,7 @@ Error: Stack causes
*[90m at *[39m
*[90m at *[39m
*[90m at *[39m
*[90m at *[39m
}
}
RangeError: New Stack Frames
Expand All @@ -97,12 +103,12 @@ RangeError: New Stack Frames
[cause]: Error: Stack causes
at *
*[90m at *[39m
*[90m ... 5 lines matching cause stack trace ...*[39m
*[90m ... 6 lines matching cause stack trace ...*[39m
*[90m at *[39m {
[cause]: FoobarError: Individual message
at *
*[90m at *[39m
*[90m ... 5 lines matching cause stack trace ...*[39m
*[90m ... 6 lines matching cause stack trace ...*[39m
*[90m at *[39m {
status: *[32m'Feeling good'*[39m,
extraProperties: *[32m'Yes!'*[39m,
Expand All @@ -115,6 +121,7 @@ RangeError: New Stack Frames
*[90m at *[39m
*[90m at *[39m
*[90m at *[39m
*[90m at *[39m
}
}
}
Expand All @@ -124,7 +131,7 @@ RangeError: New Stack Frames
[cause]: FoobarError: Individual message
at *
at *
... 5 lines matching cause stack trace ...
... 6 lines matching cause stack trace ...
at * {
status: 'Feeling good',
extraProperties: 'Yes!',
Expand All @@ -137,17 +144,18 @@ RangeError: New Stack Frames
at *
at *
at *
at *
}
}
Error: Stack causes
at *
at *
... 5 lines matching cause stack trace ...
... 6 lines matching cause stack trace ...
at * {
[cause]: FoobarError: Individual message
at *
at *
... 5 lines matching cause stack trace ...
... 6 lines matching cause stack trace ...
at *
status: 'Feeling good',
extraProperties: 'Yes!',
Expand All @@ -160,6 +168,7 @@ Error: Stack causes
at *
at *
at *
at *
}
}
RangeError: New Stack Frames
Expand All @@ -168,12 +177,12 @@ RangeError: New Stack Frames
[cause]: Error: Stack causes
at *
at *
... 5 lines matching cause stack trace ...
... 6 lines matching cause stack trace ...
at * {
[cause]: FoobarError: Individual message
at *
at *
... 5 lines matching cause stack trace ...
... 6 lines matching cause stack trace ...
at * {
status: 'Feeling good',
extraProperties: 'Yes!',
Expand All @@ -186,6 +195,7 @@ RangeError: New Stack Frames
at *
at *
at *
at *
}
}
}
Loading

0 comments on commit 7392aa2

Please sign in to comment.