Skip to content

Commit a243225

Browse files
authored
src: add cli option to preserve env vars on dr
PR-URL: #55697 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Richard Lau <[email protected]>
1 parent 5d85b05 commit a243225

12 files changed

+199
-14
lines changed

doc/api/cli.md

+10
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,15 @@ Enables report to be generated upon receiving the specified (or predefined)
20562056
signal to the running Node.js process. The signal to trigger the report is
20572057
specified through `--report-signal`.
20582058

2059+
### `--report-exclude-env`
2060+
2061+
<!-- YAML
2062+
added: REPLACEME
2063+
-->
2064+
2065+
When `--report-exclude-env` is passed the diagnostic report generated will not
2066+
contain the `environmentVariables` data.
2067+
20592068
### `--report-signal=signal`
20602069

20612070
<!-- YAML
@@ -3115,6 +3124,7 @@ one is included in the list below.
31153124
* `--redirect-warnings`
31163125
* `--report-compact`
31173126
* `--report-dir`, `--report-directory`
3127+
* `--report-exclude-env`
31183128
* `--report-exclude-network`
31193129
* `--report-filename`
31203130
* `--report-on-fatalerror`

doc/api/process.md

+10
Original file line numberDiff line numberDiff line change
@@ -3494,6 +3494,16 @@ const { report } = require('node:process');
34943494
console.log(`Report on exception: ${report.reportOnUncaughtException}`);
34953495
```
34963496
3497+
### `process.report.excludeEnv`
3498+
3499+
<!-- YAML
3500+
added: REPLACEME
3501+
-->
3502+
3503+
* {boolean}
3504+
3505+
If `true`, a diagnostic report is generated without the environment variables.
3506+
34973507
### `process.report.signal`
34983508
34993509
<!-- YAML

doc/api/report.md

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
<!-- YAML
1212
changes:
13+
- version: REPLACEME
14+
pr-url: https://github.com/nodejs/node/pull/55697
15+
description: Added `--report-exclude-env` option for excluding environment variables from report generation.
1316
- version:
1417
- v22.0.0
1518
- v20.13.0
@@ -465,6 +468,10 @@ meaning of `SIGUSR2` for the said purposes.
465468
diagnostic report. By default this is not set and the network interfaces
466469
are included.
467470

471+
* `--report-exclude-env` Exclude `environmentVariables` from the
472+
diagnostic report. By default this is not set and the environment
473+
variables are included.
474+
468475
A report can also be triggered via an API call from a JavaScript application:
469476

470477
```js

lib/internal/process/report.js

+7
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ const report = {
105105

106106
nr.setReportOnUncaughtException(trigger);
107107
},
108+
get excludeEnv() {
109+
return nr.getExcludeEnv();
110+
},
111+
set excludeEnv(b) {
112+
validateBoolean(b, 'excludeEnv');
113+
nr.setExcludeEnv(b);
114+
},
108115
};
109116

110117
function addSignalHandler(sig) {

src/env-inl.h

+4
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,10 @@ inline bool Environment::is_in_heapsnapshot_heap_limit_callback() const {
890890
return is_in_heapsnapshot_heap_limit_callback_;
891891
}
892892

893+
inline bool Environment::report_exclude_env() const {
894+
return options_->report_exclude_env;
895+
}
896+
893897
inline void Environment::AddHeapSnapshotNearHeapLimitCallback() {
894898
DCHECK(!heapsnapshot_near_heap_limit_callback_added_);
895899
heapsnapshot_near_heap_limit_callback_added_ = true;

src/env.h

+2
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,8 @@ class Environment final : public MemoryRetainer {
10441044
inline void set_heap_snapshot_near_heap_limit(uint32_t limit);
10451045
inline bool is_in_heapsnapshot_heap_limit_callback() const;
10461046

1047+
inline bool report_exclude_env() const;
1048+
10471049
inline void AddHeapSnapshotNearHeapLimitCallback();
10481050

10491051
inline void RemoveHeapSnapshotNearHeapLimitCallback(size_t heap_limit);

src/node_options.cc

+5
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
878878
&EnvironmentOptions::tls_max_v1_3,
879879
kAllowedInEnvvar);
880880

881+
AddOption("--report-exclude-env",
882+
"Exclude environment variables when generating report"
883+
" (default: false)",
884+
&EnvironmentOptions::report_exclude_env,
885+
kAllowedInEnvvar);
881886
AddOption("--report-exclude-network",
882887
"exclude network interface diagnostics."
883888
" (default: false)",

src/node_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ class EnvironmentOptions : public Options {
249249

250250
std::vector<std::string> user_argv;
251251

252+
bool report_exclude_env = false;
252253
bool report_exclude_network = false;
253254

254255
inline DebugOptions* get_debug_options() { return &debug_options_; }

src/node_report.cc

+46-9
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ static void WriteNodeReport(Isolate* isolate,
6161
std::ostream& out,
6262
Local<Value> error,
6363
bool compact,
64-
bool exclude_network = false);
64+
bool exclude_network = false,
65+
bool exclude_env = false);
6566
static void PrintVersionInformation(JSONWriter* writer,
6667
bool exclude_network = false);
6768
static void PrintJavaScriptErrorStack(JSONWriter* writer,
@@ -78,6 +79,7 @@ static void PrintJavaScriptErrorProperties(JSONWriter* writer,
7879
static void PrintNativeStack(JSONWriter* writer);
7980
static void PrintResourceUsage(JSONWriter* writer);
8081
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate);
82+
static void PrintEnvironmentVariables(JSONWriter* writer);
8183
static void PrintSystemInformation(JSONWriter* writer);
8284
static void PrintLoadedLibraries(JSONWriter* writer);
8385
static void PrintComponentVersions(JSONWriter* writer);
@@ -95,7 +97,8 @@ static void WriteNodeReport(Isolate* isolate,
9597
std::ostream& out,
9698
Local<Value> error,
9799
bool compact,
98-
bool exclude_network) {
100+
bool exclude_network,
101+
bool exclude_env) {
99102
// Obtain the current time and the pid.
100103
TIME_TYPE tm_struct;
101104
DiagnosticFilename::LocalTime(&tm_struct);
@@ -249,6 +252,9 @@ static void WriteNodeReport(Isolate* isolate,
249252
writer.json_arrayend();
250253

251254
// Report operating system information
255+
if (exclude_env == false) {
256+
PrintEnvironmentVariables(&writer);
257+
}
252258
PrintSystemInformation(&writer);
253259

254260
writer.json_objectend();
@@ -694,8 +700,7 @@ static void PrintResourceUsage(JSONWriter* writer) {
694700
#endif // RUSAGE_THREAD
695701
}
696702

697-
// Report operating system information.
698-
static void PrintSystemInformation(JSONWriter* writer) {
703+
static void PrintEnvironmentVariables(JSONWriter* writer) {
699704
uv_env_item_t* envitems;
700705
int envcount;
701706
int r;
@@ -715,7 +720,10 @@ static void PrintSystemInformation(JSONWriter* writer) {
715720
}
716721

717722
writer->json_objectend();
723+
}
718724

725+
// Report operating system information.
726+
static void PrintSystemInformation(JSONWriter* writer) {
719727
#ifndef _WIN32
720728
static struct {
721729
const char* description;
@@ -915,6 +923,10 @@ std::string TriggerNodeReport(Isolate* isolate,
915923
bool exclude_network = env != nullptr ? env->options()->report_exclude_network
916924
: per_process::cli_options->per_isolate
917925
->per_env->report_exclude_network;
926+
bool exclude_env =
927+
env != nullptr
928+
? env->report_exclude_env()
929+
: per_process::cli_options->per_isolate->per_env->report_exclude_env;
918930

919931
report::WriteNodeReport(isolate,
920932
env,
@@ -924,7 +936,8 @@ std::string TriggerNodeReport(Isolate* isolate,
924936
*outstream,
925937
error,
926938
compact,
927-
exclude_network);
939+
exclude_network,
940+
exclude_env);
928941

929942
// Do not close stdout/stderr, only close files we opened.
930943
if (outfile.is_open()) {
@@ -978,8 +991,20 @@ void GetNodeReport(Isolate* isolate,
978991
bool exclude_network = env != nullptr ? env->options()->report_exclude_network
979992
: per_process::cli_options->per_isolate
980993
->per_env->report_exclude_network;
981-
report::WriteNodeReport(
982-
isolate, env, message, trigger, "", out, error, false, exclude_network);
994+
bool exclude_env =
995+
env != nullptr
996+
? env->report_exclude_env()
997+
: per_process::cli_options->per_isolate->per_env->report_exclude_env;
998+
report::WriteNodeReport(isolate,
999+
env,
1000+
message,
1001+
trigger,
1002+
"",
1003+
out,
1004+
error,
1005+
false,
1006+
exclude_network,
1007+
exclude_env);
9831008
}
9841009

9851010
// External function to trigger a report, writing to a supplied stream.
@@ -995,8 +1020,20 @@ void GetNodeReport(Environment* env,
9951020
bool exclude_network = env != nullptr ? env->options()->report_exclude_network
9961021
: per_process::cli_options->per_isolate
9971022
->per_env->report_exclude_network;
998-
report::WriteNodeReport(
999-
isolate, env, message, trigger, "", out, error, false, exclude_network);
1023+
bool exclude_env =
1024+
env != nullptr
1025+
? env->report_exclude_env()
1026+
: per_process::cli_options->per_isolate->per_env->report_exclude_env;
1027+
report::WriteNodeReport(isolate,
1028+
env,
1029+
message,
1030+
trigger,
1031+
"",
1032+
out,
1033+
error,
1034+
false,
1035+
exclude_network,
1036+
exclude_env);
10001037
}
10011038

10021039
} // namespace node

src/node_report_module.cc

+15
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ static void SetExcludeNetwork(const FunctionCallbackInfo<Value>& info) {
9595
env->options()->report_exclude_network = info[0]->IsTrue();
9696
}
9797

98+
static void GetExcludeEnv(const FunctionCallbackInfo<Value>& info) {
99+
Environment* env = Environment::GetCurrent(info);
100+
info.GetReturnValue().Set(env->report_exclude_env());
101+
}
102+
103+
static void SetExcludeEnv(const FunctionCallbackInfo<Value>& info) {
104+
Environment* env = Environment::GetCurrent(info);
105+
CHECK(info[0]->IsBoolean());
106+
env->options()->report_exclude_env = info[0]->IsTrue();
107+
}
108+
98109
static void GetDirectory(const FunctionCallbackInfo<Value>& info) {
99110
Mutex::ScopedLock lock(per_process::cli_options_mutex);
100111
Environment* env = Environment::GetCurrent(info);
@@ -187,6 +198,8 @@ static void Initialize(Local<Object> exports,
187198
SetMethod(context, exports, "setCompact", SetCompact);
188199
SetMethod(context, exports, "getExcludeNetwork", GetExcludeNetwork);
189200
SetMethod(context, exports, "setExcludeNetwork", SetExcludeNetwork);
201+
SetMethod(context, exports, "getExcludeEnv", GetExcludeEnv);
202+
SetMethod(context, exports, "setExcludeEnv", SetExcludeEnv);
190203
SetMethod(context, exports, "getDirectory", GetDirectory);
191204
SetMethod(context, exports, "setDirectory", SetDirectory);
192205
SetMethod(context, exports, "getFilename", GetFilename);
@@ -215,6 +228,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
215228
registry->Register(SetCompact);
216229
registry->Register(GetExcludeNetwork);
217230
registry->Register(SetExcludeNetwork);
231+
registry->Register(GetExcludeEnv);
232+
registry->Register(SetExcludeEnv);
218233
registry->Register(GetDirectory);
219234
registry->Register(SetDirectory);
220235
registry->Register(GetFilename);

test/common/report.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ function _validateContent(report, fields = []) {
5959

6060
// Verify that all sections are present as own properties of the report.
6161
const sections = ['header', 'nativeStack', 'javascriptStack', 'libuv',
62-
'environmentVariables', 'sharedObjects', 'resourceUsage', 'workers'];
62+
'sharedObjects', 'resourceUsage', 'workers'];
63+
64+
if (!process.report.excludeEnv) {
65+
sections.push('environmentVariables');
66+
}
67+
6368
if (!isWindows)
6469
sections.push('userLimits');
6570

@@ -294,10 +299,12 @@ function _validateContent(report, fields = []) {
294299
resource.type === 'loop' ? 'undefined' : 'boolean');
295300
});
296301

297-
// Verify the format of the environmentVariables section.
298-
for (const [key, value] of Object.entries(report.environmentVariables)) {
299-
assert.strictEqual(typeof key, 'string');
300-
assert.strictEqual(typeof value, 'string');
302+
if (!process.report.excludeEnv) {
303+
// Verify the format of the environmentVariables section.
304+
for (const [key, value] of Object.entries(report.environmentVariables)) {
305+
assert.strictEqual(typeof key, 'string');
306+
assert.strictEqual(typeof value, 'string');
307+
}
301308
}
302309

303310
// Verify the format of the userLimits section on non-Windows platforms.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Flags: --report-exclude-env
2+
'use strict';
3+
4+
// Test producing a report via API call, using the no-hooks/no-signal interface.
5+
require('../common');
6+
const assert = require('assert');
7+
const fs = require('fs');
8+
const path = require('path');
9+
const helper = require('../common/report');
10+
const tmpdir = require('../common/tmpdir');
11+
12+
tmpdir.refresh();
13+
process.report.directory = tmpdir.path;
14+
15+
function validate() {
16+
const reports = helper.findReports(process.pid, tmpdir.path);
17+
assert.strictEqual(reports.length, 1);
18+
helper.validate(reports[0], arguments[0]);
19+
fs.unlinkSync(reports[0]);
20+
return reports[0];
21+
}
22+
23+
{
24+
// Test with no arguments.
25+
process.report.writeReport();
26+
validate();
27+
}
28+
29+
{
30+
// Test with an error argument.
31+
process.report.writeReport(new Error('test error'));
32+
validate();
33+
}
34+
35+
{
36+
// Test with an error with one line stack
37+
const error = new Error();
38+
error.stack = 'only one line';
39+
process.report.writeReport(error);
40+
validate();
41+
}
42+
43+
{
44+
const error = new Error();
45+
error.foo = 'goo';
46+
process.report.writeReport(error);
47+
validate([['javascriptStack.errorProperties.foo', 'goo']]);
48+
}
49+
50+
{
51+
// Test with a file argument.
52+
const file = process.report.writeReport('custom-name-1.json');
53+
const absolutePath = tmpdir.resolve(file);
54+
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
55+
assert.strictEqual(file, 'custom-name-1.json');
56+
helper.validate(absolutePath);
57+
fs.unlinkSync(absolutePath);
58+
}
59+
60+
{
61+
// Test with file and error arguments.
62+
const file = process.report.writeReport('custom-name-2.json',
63+
new Error('test error'));
64+
const absolutePath = tmpdir.resolve(file);
65+
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
66+
assert.strictEqual(file, 'custom-name-2.json');
67+
helper.validate(absolutePath);
68+
fs.unlinkSync(absolutePath);
69+
}
70+
71+
{
72+
// Test with a filename option.
73+
process.report.filename = 'custom-name-3.json';
74+
const file = process.report.writeReport();
75+
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
76+
const filename = path.join(process.report.directory, 'custom-name-3.json');
77+
assert.strictEqual(file, process.report.filename);
78+
helper.validate(filename);
79+
fs.unlinkSync(filename);
80+
}

0 commit comments

Comments
 (0)