Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli: add --trace-uncaught flag #30025

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,18 @@ added: v12.2.0
Prints TLS packet trace information to `stderr`. This can be used to debug TLS
connection problems.

### `--trace-uncaught`
<!-- YAML
added: REPLACEME
-->

Print stack traces for uncaught exceptions; usually, the stack trace associated
with the creation of an `Error` is printed, whereas this makes Node.js also
print the stack trace associated with throwing the value (which does not need
to be an `Error` instance).

Enabling this option may affect garbage collection behavior negatively.

### `--trace-warnings`
<!-- YAML
added: v6.0.0
Expand Down Expand Up @@ -1044,6 +1056,7 @@ Node.js options that are allowed are:
* `--trace-events-enabled`
* `--trace-sync-io`
* `--trace-tls`
* `--trace-uncaught`
* `--trace-warnings`
* `--track-heap-objects`
* `--unhandled-rejections`
Expand Down
12 changes: 12 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,18 @@ Print a stack trace whenever synchronous I/O is detected after the first turn of
.It Fl -trace-tls
Prints TLS packet trace information to stderr.
.
.It Fl -trace-uncaught
Print stack traces for uncaught exceptions; usually, the stack trace associated
with the creation of an
.Sy Error
is printed, whereas this makes Node.js also
print the stack trace associated with throwing the value (which does not need
to be an
.Sy Error
instance).
.Pp
Enabling this option may affect garbage collection behavior negatively.
.
.It Fl -trace-warnings
Print stack traces for process warnings (including deprecations).
.
Expand Down
2 changes: 2 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ int Environment::InitializeInspector(
void Environment::InitializeDiagnostics() {
isolate_->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
Environment::BuildEmbedderGraph, this);
if (options_->trace_uncaught)
isolate_->SetCaptureStackTraceForUncaughtExceptions(true);

#if defined HAVE_DTRACE || defined HAVE_ETW
InitDTrace(this);
Expand Down
13 changes: 13 additions & 0 deletions src/node_errors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,19 @@ static void ReportFatalException(Environment* env,
"%s\n%s: %s\n", *arrow_string, *name_string, *message_string);
}
}

if (!env->options()->trace_uncaught) {
PrintErrorString("(Use `node --trace-uncaught ...` to show "
"where the exception was thrown)\n");
}
}

if (env->options()->trace_uncaught) {
Local<StackTrace> trace = message->GetStackTrace();
if (!trace.IsEmpty()) {
PrintErrorString("Thrown at:\n");
PrintStackTrace(env->isolate(), trace);
}
}

fflush(stderr);
Expand Down
4 changes: 4 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
"prints TLS packet trace information to stderr",
&EnvironmentOptions::trace_tls,
kAllowedInEnvironment);
AddOption("--trace-uncaught",
"show stack traces for the `throw` behind uncaught exceptions",
&EnvironmentOptions::trace_uncaught,
kAllowedInEnvironment);
AddOption("--trace-warnings",
"show stack traces on process warnings",
&EnvironmentOptions::trace_warnings,
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class EnvironmentOptions : public Options {
bool trace_deprecation = false;
bool trace_sync_io = false;
bool trace_tls = false;
bool trace_uncaught = false;
bool trace_warnings = false;
std::string unhandled_rejections;
std::string userland_loader;
Expand Down
2 changes: 2 additions & 0 deletions test/message/eval_messages.out
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ ReferenceError: y is not defined
var ______________________________________________; throw 10
^
10
(Use `node --trace-uncaught ...` to show where the exception was thrown)

[eval]:1
var ______________________________________________; throw 10
^
10
(Use `node --trace-uncaught ...` to show where the exception was thrown)
done
2 changes: 2 additions & 0 deletions test/message/stdin_messages.out
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ ReferenceError: y is not defined
var ______________________________________________; throw 10
^
10
(Use `node --trace-uncaught ...` to show where the exception was thrown)

[stdin]:1
var ______________________________________________; throw 10
^
10
(Use `node --trace-uncaught ...` to show where the exception was thrown)
done
1 change: 1 addition & 0 deletions test/message/throw_error_with_getter_throw.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
throw { // eslint-disable-line no-throw-literal
^
[object Object]
(Use `node --trace-uncaught ...` to show where the exception was thrown)
11 changes: 11 additions & 0 deletions test/message/throw_error_with_getter_throw_traced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Flags: --trace-uncaught
'use strict';
require('../common');
throw { // eslint-disable-line no-throw-literal
get stack() {
throw new Error('weird throw but ok');
},
get name() {
throw new Error('weird throw but ok');
},
};
12 changes: 12 additions & 0 deletions test/message/throw_error_with_getter_throw_traced.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

*:4
throw { // eslint-disable-line no-throw-literal
^
[object Object]
Thrown at:
at *throw_error_with_getter_throw_traced.js:*:*
at Module._compile (internal/modules/cjs/loader.js:*:*)
at Module._extensions..js (internal/modules/cjs/loader.js:*:*)
at Module.load (internal/modules/cjs/loader.js:*:*)
at Module._load (internal/modules/cjs/loader.js:*:*)
at Module.runMain (internal/modules/cjs/loader.js:*:*)
1 change: 1 addition & 0 deletions test/message/throw_null.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
throw null;
^
null
(Use `node --trace-uncaught ...` to show where the exception was thrown)
6 changes: 6 additions & 0 deletions test/message/throw_null_traced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Flags: --trace-uncaught
'use strict';
require('../common');

// eslint-disable-next-line no-throw-literal
throw null;
12 changes: 12 additions & 0 deletions test/message/throw_null_traced.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

*test*message*throw_null_traced.js:*
throw null;
^
null
Thrown at:
at *throw_null_traced.js:*:*
at Module._compile (internal/modules/cjs/loader.js:*:*)
at Module._extensions..js (internal/modules/cjs/loader.js:*:*)
at Module.load (internal/modules/cjs/loader.js:*:*)
at Module._load (internal/modules/cjs/loader.js:*:*)
at Module.runMain (internal/modules/cjs/loader.js:*:*)
1 change: 1 addition & 0 deletions test/message/throw_undefined.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
throw undefined;
^
undefined
(Use `node --trace-uncaught ...` to show where the exception was thrown)
6 changes: 6 additions & 0 deletions test/message/throw_undefined_traced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Flags: --trace-uncaught
'use strict';
require('../common');

// eslint-disable-next-line no-throw-literal
throw undefined;
12 changes: 12 additions & 0 deletions test/message/throw_undefined_traced.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

*test*message*throw_undefined_traced.js:*
throw undefined;
^
undefined
Thrown at:
at *throw_undefined_traced.js:*:*
at Module._compile (internal/modules/cjs/loader.js:*:*)
at Module._extensions..js (internal/modules/cjs/loader.js:*:*)
at Module.load (internal/modules/cjs/loader.js:*:*)
at Module._load (internal/modules/cjs/loader.js:*:*)
at Module.runMain (internal/modules/cjs/loader.js:*:*)