diff --git a/doc/api/cli.md b/doc/api/cli.md index b7ee385555d468..1ab7fbe739079f 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -1747,6 +1747,15 @@ Enables report to be generated when the process exits due to an uncaught exception. Useful when inspecting the JavaScript stack in conjunction with native stack and other runtime environment data. +### `--report-exclude-network` + + + +Exclude `header.networkInterfaces` from the diagnostic report. By default +this is not set and the network interfaces are included. + ### `-r`, `--require module` + + Delivers a JSON-formatted diagnostic summary, written to a file. The report is intended for development, test, and production use, to capture @@ -452,6 +459,10 @@ meaning of `SIGUSR2` for the said purposes. * `--report-signal` Sets or resets the signal for report generation (not supported on Windows). Default signal is `SIGUSR2`. +* `--report-exclude-network` Exclude `header.networkInterfaces` from the + diagnostic report. By default this is not set and the network interfaces + are included. + A report can also be triggered via an API call from a JavaScript application: ```js @@ -571,6 +582,8 @@ timestamp, PID, and sequence number. written. URLs are not supported. Defaults to the current working directory of the Node.js process. +`excludeNetwork` excludes `header.networkInterfaces` from the diagnostic report. + ```js // Trigger report only on uncaught exceptions. process.report.reportOnFatalError = false; @@ -587,6 +600,9 @@ process.report.reportOnFatalError = false; process.report.reportOnUncaughtException = false; process.report.reportOnSignal = true; process.report.signal = 'SIGQUIT'; + +// Disable network interfaces reporting +process.report.excludeNetwork = true; ``` Configuration on module initialization is also available via diff --git a/lib/internal/process/report.js b/lib/internal/process/report.js index 9889f913c3f81f..1639142dff0eb7 100644 --- a/lib/internal/process/report.js +++ b/lib/internal/process/report.js @@ -60,6 +60,13 @@ const report = { validateBoolean(b, 'compact'); nr.setCompact(b); }, + get excludeNetwork() { + return nr.getExcludeNetwork(); + }, + set excludeNetwork(b) { + validateBoolean(b, 'excludeNetwork'); + nr.setExcludeNetwork(b); + }, get signal() { return nr.getSignal(); }, diff --git a/src/node_options.cc b/src/node_options.cc index 7b5152172c5ce7..97ae9b41a2f3ef 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -785,6 +785,12 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "set default TLS maximum to TLSv1.3 (default: TLSv1.3)", &EnvironmentOptions::tls_max_v1_3, kAllowedInEnvvar); + + AddOption("--report-exclude-network", + "exclude network interface diagnostics." + " (default: false)", + &EnvironmentOptions::report_exclude_network, + kAllowedInEnvvar); } PerIsolateOptionsParser::PerIsolateOptionsParser( diff --git a/src/node_options.h b/src/node_options.h index a0b56ebacb436c..2f59f70f8ed60e 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -218,6 +218,8 @@ class EnvironmentOptions : public Options { std::vector user_argv; + bool report_exclude_network = false; + inline DebugOptions* get_debug_options() { return &debug_options_; } inline const DebugOptions& debug_options() const { return debug_options_; } diff --git a/src/node_report.cc b/src/node_report.cc index 54121cb6b48210..23bbdad186940d 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -61,8 +61,10 @@ static void WriteNodeReport(Isolate* isolate, const std::string& filename, std::ostream& out, Local error, - bool compact); -static void PrintVersionInformation(JSONWriter* writer); + bool compact, + bool exclude_network = false); +static void PrintVersionInformation(JSONWriter* writer, + bool exclude_network = false); static void PrintJavaScriptErrorStack(JSONWriter* writer, Isolate* isolate, Local error, @@ -93,7 +95,8 @@ static void WriteNodeReport(Isolate* isolate, const std::string& filename, std::ostream& out, Local error, - bool compact) { + bool compact, + bool exclude_network) { // Obtain the current time and the pid. TIME_TYPE tm_struct; DiagnosticFilename::LocalTime(&tm_struct); @@ -174,7 +177,7 @@ static void WriteNodeReport(Isolate* isolate, } // Report Node.js and OS version information - PrintVersionInformation(&writer); + PrintVersionInformation(&writer, exclude_network); writer.json_objectend(); if (isolate != nullptr) { @@ -256,7 +259,7 @@ static void WriteNodeReport(Isolate* isolate, } // Report Node.js version, OS version and machine information. -static void PrintVersionInformation(JSONWriter* writer) { +static void PrintVersionInformation(JSONWriter* writer, bool exclude_network) { std::ostringstream buf; // Report Node version buf << "v" << NODE_VERSION_STRING; @@ -300,7 +303,7 @@ static void PrintVersionInformation(JSONWriter* writer) { } PrintCpuInfo(writer); - PrintNetworkInterfaceInfo(writer); + if (!exclude_network) PrintNetworkInterfaceInfo(writer); char host[UV_MAXHOSTNAMESIZE]; size_t host_size = sizeof(host); @@ -917,8 +920,19 @@ std::string TriggerNodeReport(Isolate* isolate, compact = per_process::cli_options->report_compact; } - report::WriteNodeReport( - isolate, env, message, trigger, filename, *outstream, error, compact); + bool exclude_network = env != nullptr ? env->options()->report_exclude_network + : per_process::cli_options->per_isolate + ->per_env->report_exclude_network; + + report::WriteNodeReport(isolate, + env, + message, + trigger, + filename, + *outstream, + error, + compact, + exclude_network); // Do not close stdout/stderr, only close files we opened. if (outfile.is_open()) { @@ -969,8 +983,11 @@ void GetNodeReport(Isolate* isolate, if (isolate != nullptr) { env = Environment::GetCurrent(isolate); } + bool exclude_network = env != nullptr ? env->options()->report_exclude_network + : per_process::cli_options->per_isolate + ->per_env->report_exclude_network; report::WriteNodeReport( - isolate, env, message, trigger, "", out, error, false); + isolate, env, message, trigger, "", out, error, false, exclude_network); } // External function to trigger a report, writing to a supplied stream. @@ -983,8 +1000,11 @@ void GetNodeReport(Environment* env, if (env != nullptr) { isolate = env->isolate(); } + bool exclude_network = env != nullptr ? env->options()->report_exclude_network + : per_process::cli_options->per_isolate + ->per_env->report_exclude_network; report::WriteNodeReport( - isolate, env, message, trigger, "", out, error, false); + isolate, env, message, trigger, "", out, error, false, exclude_network); } } // namespace node diff --git a/src/node_report_module.cc b/src/node_report_module.cc index 58963fd5150b04..09ac89fc528d95 100644 --- a/src/node_report_module.cc +++ b/src/node_report_module.cc @@ -84,6 +84,17 @@ static void SetCompact(const FunctionCallbackInfo& info) { per_process::cli_options->report_compact = compact; } +static void GetExcludeNetwork(const FunctionCallbackInfo& info) { + Environment* env = Environment::GetCurrent(info); + info.GetReturnValue().Set(env->options()->report_exclude_network); +} + +static void SetExcludeNetwork(const FunctionCallbackInfo& info) { + Environment* env = Environment::GetCurrent(info); + CHECK(info[0]->IsBoolean()); + env->options()->report_exclude_network = info[0]->IsTrue(); +} + static void GetDirectory(const FunctionCallbackInfo& info) { Mutex::ScopedLock lock(per_process::cli_options_mutex); Environment* env = Environment::GetCurrent(info); @@ -174,6 +185,8 @@ static void Initialize(Local exports, SetMethod(context, exports, "getReport", GetReport); SetMethod(context, exports, "getCompact", GetCompact); SetMethod(context, exports, "setCompact", SetCompact); + SetMethod(context, exports, "getExcludeNetwork", GetExcludeNetwork); + SetMethod(context, exports, "setExcludeNetwork", SetExcludeNetwork); SetMethod(context, exports, "getDirectory", GetDirectory); SetMethod(context, exports, "setDirectory", SetDirectory); SetMethod(context, exports, "getFilename", GetFilename); @@ -200,6 +213,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(GetReport); registry->Register(GetCompact); registry->Register(SetCompact); + registry->Register(GetExcludeNetwork); + registry->Register(SetExcludeNetwork); registry->Register(GetDirectory); registry->Register(SetDirectory); registry->Register(GetFilename); diff --git a/test/report/test-report-config.js b/test/report/test-report-config.js index dce58c5bfcd954..55a4371fd32d79 100644 --- a/test/report/test-report-config.js +++ b/test/report/test-report-config.js @@ -66,6 +66,17 @@ assert.throws(() => { }, { code: 'ERR_INVALID_ARG_TYPE' }); assert.strictEqual(process.report.compact, true); +// Verify that process.report.excludeNetwork behaves properly. +assert.strictEqual(process.report.excludeNetwork, false); +process.report.excludeNetwork = true; +assert.strictEqual(process.report.excludeNetwork, true); +process.report.excludeNetwork = false; +assert.strictEqual(process.report.excludeNetwork, false); +assert.throws(() => { + process.report.excludeNetwork = {}; +}, { code: 'ERR_INVALID_ARG_TYPE' }); +assert.strictEqual(process.report.excludeNetwork, false); + if (!common.isWindows) { // Verify that process.report.signal behaves properly. assert.strictEqual(process.report.signal, 'SIGUSR2'); diff --git a/test/report/test-report-exclude-network.js b/test/report/test-report-exclude-network.js new file mode 100644 index 00000000000000..c5e50135482f1a --- /dev/null +++ b/test/report/test-report-exclude-network.js @@ -0,0 +1,41 @@ +'use strict'; +require('../common'); +const assert = require('node:assert'); +const { spawnSync } = require('node:child_process'); +const tmpdir = require('../common/tmpdir'); +const { describe, it, before } = require('node:test'); +const fs = require('node:fs'); +const helper = require('../common/report'); + +function validate(pid) { + const reports = helper.findReports(pid, tmpdir.path); + assert.strictEqual(reports.length, 1); + let report = fs.readFileSync(reports[0], { encoding: 'utf8' }); + report = JSON.parse(report); + assert.strictEqual(report.header.networkInterfaces, undefined); + fs.unlinkSync(reports[0]); +} + +describe('report exclude network option', () => { + before(() => { + tmpdir.refresh(); + process.report.directory = tmpdir.path; + }); + + it('should be configurable with --report-exclude-network', () => { + const args = ['--report-exclude-network', '-e', 'process.report.writeReport()']; + const child = spawnSync(process.execPath, args, { cwd: tmpdir.path }); + assert.strictEqual(child.status, 0); + assert.strictEqual(child.signal, null); + validate(child.pid); + }); + + it('should be configurable with report.excludeNetwork', () => { + process.report.excludeNetwork = true; + process.report.writeReport(); + validate(process.pid); + + const report = process.report.getReport(); + assert.strictEqual(report.header.networkInterfaces, undefined); + }); +});