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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions doc/api/cli.md
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
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
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
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
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
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
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
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
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
@@ -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
@@ -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
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
@@ -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
@@ -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
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
@@ -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
@@ -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:*:*)