Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7bfc339

Browse filesBrowse files
legendecastargos
authored andcommitted
cli: add --trace-exit cli option
It could be convenient to trace abnormal exit of the Node.js processes that printing stacktrace on each `process.exit` call with a cli option. This also takes effects on worker threads. PR-URL: #30516 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 732780f commit 7bfc339
Copy full SHA for 7bfc339

File tree

Expand file treeCollapse file tree

6 files changed

+92
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+92
-0
lines changed
Open diff view settings
Collapse file

‎doc/api/cli.md‎

Copy file name to clipboardExpand all lines: doc/api/cli.md
+9Lines changed: 9 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,14 @@ added: v7.7.0
786786

787787
Enables the collection of trace event tracing information.
788788

789+
### `--trace-exit`
790+
<!-- YAML
791+
added: REPLACEME
792+
-->
793+
794+
Prints a stack trace whenever an environment is exited proactively,
795+
i.e. invoking `process.exit()`.
796+
789797
### `--trace-sync-io`
790798
<!-- YAML
791799
added: v2.1.0
@@ -1128,6 +1136,7 @@ Node.js options that are allowed are:
11281136
* `--trace-event-categories`
11291137
* `--trace-event-file-pattern`
11301138
* `--trace-events-enabled`
1139+
* `--trace-exit`
11311140
* `--trace-sync-io`
11321141
* `--trace-tls`
11331142
* `--trace-uncaught`
Collapse file

‎doc/node.1‎

Copy file name to clipboardExpand all lines: doc/node.1
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ and
353353
.It Fl -trace-events-enabled
354354
Enable the collection of trace event tracing information.
355355
.
356+
.It Fl -trace-exit
357+
Prints a stack trace whenever an environment is exited proactively,
358+
i.e. invoking `process.exit()`.
359+
.
356360
.It Fl -trace-sync-io
357361
Print a stack trace whenever synchronous I/O is detected after the first turn of the event loop.
358362
.
Collapse file

‎src/env.cc‎

Copy file name to clipboardExpand all lines: src/env.cc
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,21 @@ void AsyncHooks::grow_async_ids_stack() {
931931
uv_key_t Environment::thread_local_env = {};
932932

933933
void Environment::Exit(int exit_code) {
934+
if (options()->trace_exit) {
935+
HandleScope handle_scope(isolate());
936+
937+
if (is_main_thread()) {
938+
fprintf(stderr, "(node:%d) ", uv_os_getpid());
939+
} else {
940+
fprintf(stderr, "(node:%d, thread:%llu) ", uv_os_getpid(), thread_id());
941+
}
942+
943+
fprintf(
944+
stderr, "WARNING: Exited the environment with code %d\n", exit_code);
945+
PrintStackTrace(
946+
isolate(),
947+
StackTrace::CurrentStackTrace(isolate(), 10, StackTrace::kDetailed));
948+
}
934949
if (is_main_thread()) {
935950
stop_sub_worker_contexts();
936951
DisposePlatform();
Collapse file

‎src/node_options.cc‎

Copy file name to clipboardExpand all lines: src/node_options.cc
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
511511
"show stack traces on deprecations",
512512
&EnvironmentOptions::trace_deprecation,
513513
kAllowedInEnvironment);
514+
AddOption("--trace-exit",
515+
"show stack trace when an environment exits",
516+
&EnvironmentOptions::trace_exit,
517+
kAllowedInEnvironment);
514518
AddOption("--trace-sync-io",
515519
"show stack trace when use of sync IO is detected after the "
516520
"first tick",
Collapse file

‎src/node_options.h‎

Copy file name to clipboardExpand all lines: src/node_options.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class EnvironmentOptions : public Options {
142142
bool test_udp_no_try_send = false;
143143
bool throw_deprecation = false;
144144
bool trace_deprecation = false;
145+
bool trace_exit = false;
145146
bool trace_sync_io = false;
146147
bool trace_tls = false;
147148
bool trace_uncaught = false;
Collapse file

‎test/parallel/test-trace-exit.js‎

Copy file name to clipboard
+59Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const { promisify } = require('util');
5+
const execFile = promisify(require('child_process').execFile);
6+
const { Worker, isMainThread, workerData } = require('worker_threads');
7+
8+
const variant = process.argv[process.argv.length - 1];
9+
switch (true) {
10+
case variant === 'main-thread': {
11+
return;
12+
}
13+
case variant === 'main-thread-exit': {
14+
return process.exit(0);
15+
}
16+
case variant.startsWith('worker-thread'): {
17+
const worker = new Worker(__filename, { workerData: variant });
18+
worker.on('error', common.mustNotCall());
19+
worker.on('exit', common.mustCall((code) => {
20+
assert.strictEqual(code, 0);
21+
}));
22+
return;
23+
}
24+
case !isMainThread: {
25+
if (workerData === 'worker-thread-exit') {
26+
process.exit(0);
27+
}
28+
return;
29+
}
30+
}
31+
32+
(async function() {
33+
for (const { execArgv, variant, warnings } of [
34+
{ execArgv: ['--trace-exit'], variant: 'main-thread-exit', warnings: 1 },
35+
{ execArgv: [], variant: 'main-thread-exit', warnings: 0 },
36+
{ execArgv: ['--trace-exit'], variant: 'main-thread', warnings: 0 },
37+
{ execArgv: [], variant: 'main-thread', warnings: 0 },
38+
{ execArgv: ['--trace-exit'], variant: 'worker-thread-exit', warnings: 1 },
39+
{ execArgv: [], variant: 'worker-thread-exit', warnings: 0 },
40+
{ execArgv: ['--trace-exit'], variant: 'worker-thread', warnings: 0 },
41+
{ execArgv: [], variant: 'worker-thread', warnings: 0 },
42+
]) {
43+
const { stdout, stderr } =
44+
await execFile(process.execPath, [...execArgv, __filename, variant]);
45+
assert.strictEqual(stdout, '');
46+
const actualWarnings =
47+
stderr.match(/WARNING: Exited the environment with code 0/g);
48+
if (warnings === 0) {
49+
assert.strictEqual(actualWarnings, null);
50+
return;
51+
}
52+
assert.strictEqual(actualWarnings.length, warnings);
53+
54+
if (variant.startsWith('worker')) {
55+
const workerIds = stderr.match(/\(node:\d+, thread:\d+)/g);
56+
assert.strictEqual(workerIds.length, warnings);
57+
}
58+
}
59+
})().then(common.mustCall());

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.