Skip to content

Commit e95af74

Browse files
RafaelGSSQard
authored andcommitted
lib: add diagnostics_channel events to module loading
This commit adds a tracing channel for module loading through `import()` and `require()`. Co-Authored-By: Stephen Belanger <admin@stephenbelanger.com> PR-URL: #44340 Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
1 parent 49cfb9d commit e95af74

25 files changed

Lines changed: 398 additions & 37 deletions

‎doc/api/diagnostics_channel.md‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,58 @@ Emitted when server receives a request.
11171117

11181118
Emitted when server sends a response.
11191119

1120+
#### Modules
1121+
1122+
`module.require.start`
1123+
1124+
*`event` {Object} containing the following properties
1125+
*`id` - Argument passed to `require()`. Module name.
1126+
*`parentFilename` - Name of the module that attempted to require(id).
1127+
1128+
Emitted when `require()` is executed. See [`start` event][].
1129+
1130+
`module.require.end`
1131+
1132+
*`event` {Object} containing the following properties
1133+
*`id` - Argument passed to `require()`. Module name.
1134+
*`parentFilename` - Name of the module that attempted to require(id).
1135+
1136+
Emitted when a `require()` call returns. See [`end` event][].
1137+
1138+
`module.require.error`
1139+
1140+
*`event` {Object} containing the following properties
1141+
*`id` - Argument passed to `require()`. Module name.
1142+
*`parentFilename` - Name of the module that attempted to require(id).
1143+
*`error` {Error}
1144+
1145+
Emitted when a `require()` throws an error. See [`error` event][].
1146+
1147+
`module.import.asyncStart`
1148+
1149+
*`event` {Object} containing the following properties
1150+
*`id` - Argument passed to `import()`. Module name.
1151+
*`parentURL` - URL object of the module that attempted to import(id).
1152+
1153+
Emitted when `import()` is invoked. See [`asyncStart` event][].
1154+
1155+
`module.import.asyncEnd`
1156+
1157+
*`event` {Object} containing the following properties
1158+
*`id` - Argument passed to `import()`. Module name.
1159+
*`parentURL` - URL object of the module that attempted to import(id).
1160+
1161+
Emitted when `import()` has completed. See [`asyncEnd` event][].
1162+
1163+
`module.import.error`
1164+
1165+
*`event` {Object} containing the following properties
1166+
*`id` - Argument passed to `import()`. Module name.
1167+
*`parentURL` - URL object of the module that attempted to import(id).
1168+
*`error` {Error}
1169+
1170+
Emitted when a `import()` throws an error. See [`error` event][].
1171+
11201172
#### NET
11211173

11221174
`net.client.socket`

‎lib/diagnostics_channel.js‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ function tracingChannelFrom(nameOrChannels, name) {
269269

270270
classTracingChannel{
271271
constructor(nameOrChannels){
272-
for(consteventNameoftraceEvents){
272+
for(leti=0;i<traceEvents.length;++i){
273+
consteventName=traceEvents[i];
273274
ObjectDefineProperty(this,eventName,{
274275
__proto__: null,
275276
value: tracingChannelFrom(nameOrChannels,eventName),
@@ -278,15 +279,16 @@ class TracingChannel {
278279
}
279280

280281
gethasSubscribers(){
281-
returnthis.start.hasSubscribers||
282-
this.end.hasSubscribers||
283-
this.asyncStart.hasSubscribers||
284-
this.asyncEnd.hasSubscribers||
285-
this.error.hasSubscribers;
282+
returnthis.start?.hasSubscribers||
283+
this.end?.hasSubscribers||
284+
this.asyncStart?.hasSubscribers||
285+
this.asyncEnd?.hasSubscribers||
286+
this.error?.hasSubscribers;
286287
}
287288

288289
subscribe(handlers){
289-
for(constnameoftraceEvents){
290+
for(leti=0;i<traceEvents.length;++i){
291+
constname=traceEvents[i];
290292
if(!handlers[name])continue;
291293

292294
this[name]?.subscribe(handlers[name]);
@@ -296,7 +298,8 @@ class TracingChannel {
296298
unsubscribe(handlers){
297299
letdone=true;
298300

299-
for(constnameoftraceEvents){
301+
for(leti=0;i<traceEvents.length;++i){
302+
constname=traceEvents[i];
300303
if(!handlers[name])continue;
301304

302305
if(!this[name]?.unsubscribe(handlers[name])){

‎lib/internal/modules/cjs/loader.js‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ let { startTimer, endTimer } = debugWithTimer('module_timer', (start, end) => {
189189
endTimer=end;
190190
});
191191

192+
const{ tracingChannel }=require('diagnostics_channel');
193+
constonRequire=getLazy(()=>tracingChannel('module.require'));
194+
192195
constisWindows=process.platform==='win32';
193196

194197
constrelativeResolveCache={__proto__: null};
@@ -209,7 +212,11 @@ function wrapModuleLoad(request, parent, isMain) {
209212
startTimer(logLabel,traceLabel);
210213

211214
try{
212-
returnModule._load(request,parent,isMain);
215+
returnonRequire().traceSync(Module._load,{
216+
__proto__: null,
217+
parentFilename: parent?.filename,
218+
id: request,
219+
},Module,request,parent,isMain);
213220
}finally{
214221
endTimer(logLabel,traceLabel);
215222
}

‎lib/internal/modules/esm/loader.js‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ const {
4242
}=require('internal/modules/helpers');
4343
letdefaultResolve,defaultLoad,defaultLoadSync,importMetaInitializer;
4444

45+
const{ tracingChannel }=require('diagnostics_channel');
46+
constonImport=tracingChannel('module.import');
47+
4548
/**
4649
* @typedef {import('url').URL} URL
4750
*/
@@ -210,10 +213,17 @@ class ModuleLoader {
210213
returncompileSourceTextModule(url,source,this);
211214
};
212215
const{ ModuleJob }=require('internal/modules/esm/module_job');
213-
constjob=newModuleJob(
214-
this,url,undefined,evalInstance,false,false);
215-
this.loadCache.set(url,undefined,job);
216-
const{ module }=awaitjob.run(isEntryPoint);
216+
constmodule=awaitonImport.tracePromise(async()=>{
217+
constjob=newModuleJob(
218+
this,url,undefined,evalInstance,false,false);
219+
this.loadCache.set(url,undefined,job);
220+
const{ module }=awaitjob.run(isEntryPoint);
221+
returnmodule;
222+
},{
223+
__proto__: null,
224+
parentURL: '<eval>',
225+
url,
226+
});
217227

218228
return{
219229
__proto__: null,
@@ -470,9 +480,15 @@ class ModuleLoader {
470480
* @returns {Promise<ModuleExports>}
471481
*/
472482
asyncimport(specifier,parentURL,importAttributes,isEntryPoint=false){
473-
constmoduleJob=awaitthis.getModuleJob(specifier,parentURL,importAttributes);
474-
const{ module }=awaitmoduleJob.run(isEntryPoint);
475-
returnmodule.getNamespace();
483+
returnonImport.tracePromise(async()=>{
484+
constmoduleJob=awaitthis.getModuleJob(specifier,parentURL,importAttributes);
485+
const{ module }=awaitmoduleJob.run(isEntryPoint);
486+
returnmodule.getNamespace();
487+
},{
488+
__proto__: null,
489+
parentURL,
490+
url: specifier,
491+
});
476492
}
477493

478494
/**

‎test/fixtures/console/console.snapshot‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ Trace: foo
77
at *
88
at *
99
at *
10+
at *

‎test/fixtures/errors/force_colors.snapshot‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ Error: Should include grayed stack trace
1111
 at *
1212
 at *
1313
 at *
14+
 at *
1415

1516
Node.js *

‎test/fixtures/errors/promise_unhandled_warn_with_error.snapshot‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
at *
88
at *
99
at *
10+
at *
1011
(Use `node --trace-warnings ...` to show where the warning was created)
1112
(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)

‎test/fixtures/errors/unhandled_promise_trace_warnings.snapshot‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
at *
1212
at *
1313
at *
14+
at *
1415
(node:*) Error: This was rejected
1516
at *
1617
at *
@@ -20,6 +21,7 @@
2021
at *
2122
at *
2223
at *
24+
at *
2325
(node:*) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
2426
at *
2527
at *

‎test/message/assert_throws_stack.out‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
1616
at *
1717
at *
1818
at *
19+
at *
1920
at * {
2021
generatedMessage: true,
2122
code: 'ERR_ASSERTION',

‎test/message/internal_assert.out‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Please open an issue with this stack trace at https://github.com/nodejs/node/iss
1313
at *
1414
at *
1515
at *
16+
at *
1617
at * {
1718
code: 'ERR_INTERNAL_ASSERTION'
1819
}

0 commit comments

Comments
 (0)