From 1f1267280950fd30a9e4a3403797dc50b423f11b Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Thu, 1 Feb 2024 20:20:29 -0700 Subject: [PATCH] report: add `--report-disable-network` option New option `--report-disable-network`, also available as `report.disableNetwork`, enables the user to disable networking interfaces in their diagnostic report. On some systems, this can cause the report to take minutes to generate so this option can be used to optimize that. fixes: https://github.com/nodejs/node/issues/46060 --- doc/api/report.md | 8 ++++ lib/internal/process/report.js | 7 ++++ src/node_options.cc | 5 +++ src/node_options.h | 1 + src/node_report.cc | 45 +++++++++++++++++----- src/node_report_module.cc | 17 ++++++++ test/report/test-report-config.js | 11 ++++++ test/report/test-report-disable-network.js | 38 ++++++++++++++++++ 8 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 test/report/test-report-disable-network.js diff --git a/doc/api/report.md b/doc/api/report.md index 213f7126960027..3daf389a039227 100644 --- a/doc/api/report.md +++ b/doc/api/report.md @@ -452,6 +452,9 @@ 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-disable-network` Disable the `header.networkInterfaces` reporting. + Default is `false`. + A report can also be triggered via an API call from a JavaScript application: ```js @@ -571,6 +574,8 @@ timestamp, PID, and sequence number. written. URLs are not supported. Defaults to the current working directory of the Node.js process. +`disableNetwork` disables the `header.networkInterfaces` reporting. + ```js // Trigger report only on uncaught exceptions. process.report.reportOnFatalError = false; @@ -587,6 +592,9 @@ process.report.reportOnFatalError = false; process.report.reportOnUncaughtException = false; process.report.reportOnSignal = true; process.report.signal = 'SIGQUIT'; + +// Disable network interfaces reporting +process.report.disableNetwork = 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..2ca7557620c0b2 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 disableNetwork() { + return nr.getDisableNetwork(); + }, + set disableNetwork(b) { + validateBoolean(b, 'disableNetwork'); + nr.setDisableNetwork(b); + }, get signal() { return nr.getSignal(); }, diff --git a/src/node_options.cc b/src/node_options.cc index 7b5152172c5ce7..c807cc9bd6d90f 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -950,6 +950,11 @@ PerProcessOptionsParser::PerProcessOptionsParser( "generate diagnostic report on fatal (internal) errors", &PerProcessOptions::report_on_fatalerror, kAllowedInEnvvar); + AddOption("--report-disable-network", + "disable network interface diagnostics." + " (default: false)", + &PerProcessOptions::report_disable_network, + kAllowedInEnvvar); #ifdef NODE_HAVE_I18N_SUPPORT AddOption("--icu-data-dir", diff --git a/src/node_options.h b/src/node_options.h index 915151b7dc2904..374b27769b4ca9 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -306,6 +306,7 @@ class PerProcessOptions : public Options { bool report_compact = false; std::string report_directory; std::string report_filename; + bool report_disable_network = false; // TODO(addaleax): Some of these could probably be per-Environment. std::string use_largepages = "off"; diff --git a/src/node_report.cc b/src/node_report.cc index 54121cb6b48210..10d5ecfafd7b53 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -61,8 +61,9 @@ static void WriteNodeReport(Isolate* isolate, const std::string& filename, std::ostream& out, Local error, - bool compact); -static void PrintVersionInformation(JSONWriter* writer); + bool compact, + bool disable_network); +static void PrintVersionInformation(JSONWriter* writer, bool disable_network); static void PrintJavaScriptErrorStack(JSONWriter* writer, Isolate* isolate, Local error, @@ -93,7 +94,8 @@ static void WriteNodeReport(Isolate* isolate, const std::string& filename, std::ostream& out, Local error, - bool compact) { + bool compact, + bool disable_network) { // Obtain the current time and the pid. TIME_TYPE tm_struct; DiagnosticFilename::LocalTime(&tm_struct); @@ -174,7 +176,7 @@ static void WriteNodeReport(Isolate* isolate, } // Report Node.js and OS version information - PrintVersionInformation(&writer); + PrintVersionInformation(&writer, disable_network); writer.json_objectend(); if (isolate != nullptr) { @@ -256,7 +258,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 disable_network) { std::ostringstream buf; // Report Node version buf << "v" << NODE_VERSION_STRING; @@ -300,7 +302,8 @@ static void PrintVersionInformation(JSONWriter* writer) { } PrintCpuInfo(writer); - PrintNetworkInterfaceInfo(writer); + if (!disable_network) + PrintNetworkInterfaceInfo(writer); char host[UV_MAXHOSTNAMESIZE]; size_t host_size = sizeof(host); @@ -917,8 +920,22 @@ std::string TriggerNodeReport(Isolate* isolate, compact = per_process::cli_options->report_compact; } + bool disable_network; + { + Mutex::ScopedLock lock(per_process::cli_options_mutex); + disable_network = per_process::cli_options->report_disable_network; + } + report::WriteNodeReport( - isolate, env, message, trigger, filename, *outstream, error, compact); + isolate, + env, + message, + trigger, + filename, + *outstream, + error, + compact, + disable_network); // Do not close stdout/stderr, only close files we opened. if (outfile.is_open()) { @@ -969,8 +986,13 @@ void GetNodeReport(Isolate* isolate, if (isolate != nullptr) { env = Environment::GetCurrent(isolate); } + bool disable_network; + { + Mutex::ScopedLock lock(per_process::cli_options_mutex); + disable_network = per_process::cli_options->report_disable_network; + } report::WriteNodeReport( - isolate, env, message, trigger, "", out, error, false); + isolate, env, message, trigger, "", out, error, false, disable_network); } // External function to trigger a report, writing to a supplied stream. @@ -983,8 +1005,13 @@ void GetNodeReport(Environment* env, if (env != nullptr) { isolate = env->isolate(); } + bool disable_network; + { + Mutex::ScopedLock lock(per_process::cli_options_mutex); + disable_network = per_process::cli_options->report_disable_network; + } report::WriteNodeReport( - isolate, env, message, trigger, "", out, error, false); + isolate, env, message, trigger, "", out, error, false, disable_network); } } // namespace node diff --git a/src/node_report_module.cc b/src/node_report_module.cc index 58963fd5150b04..4cb654581eb65e 100644 --- a/src/node_report_module.cc +++ b/src/node_report_module.cc @@ -84,6 +84,19 @@ static void SetCompact(const FunctionCallbackInfo& info) { per_process::cli_options->report_compact = compact; } +static void GetDisableNetwork(const FunctionCallbackInfo& info) { + Mutex::ScopedLock lock(per_process::cli_options_mutex); + info.GetReturnValue().Set(per_process::cli_options->report_disable_network); +} + +static void SetDisableNetwork(const FunctionCallbackInfo& info) { + Mutex::ScopedLock lock(per_process::cli_options_mutex); + Environment* env = Environment::GetCurrent(info); + Isolate* isolate = env->isolate(); + bool disable_network = info[0]->ToBoolean(isolate)->Value(); + per_process::cli_options->report_disable_network = disable_network; +} + static void GetDirectory(const FunctionCallbackInfo& info) { Mutex::ScopedLock lock(per_process::cli_options_mutex); Environment* env = Environment::GetCurrent(info); @@ -174,6 +187,8 @@ static void Initialize(Local exports, SetMethod(context, exports, "getReport", GetReport); SetMethod(context, exports, "getCompact", GetCompact); SetMethod(context, exports, "setCompact", SetCompact); + SetMethod(context, exports, "getDisableNetwork", GetDisableNetwork); + SetMethod(context, exports, "setDisableNetwork", SetDisableNetwork); SetMethod(context, exports, "getDirectory", GetDirectory); SetMethod(context, exports, "setDirectory", SetDirectory); SetMethod(context, exports, "getFilename", GetFilename); @@ -200,6 +215,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(GetReport); registry->Register(GetCompact); registry->Register(SetCompact); + registry->Register(GetDisableNetwork); + registry->Register(SetDisableNetwork); 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..103ad23c4638c9 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.reportDisableNetwork behaves properly. +assert.strictEqual(process.report.disableNetwork, true); +process.report.disableNetwork = false; +assert.strictEqual(process.report.disableNetwork, false); +process.report.disableNetwork = true; +assert.strictEqual(process.report.disableNetwork, true); +assert.throws(() => { + process.report.disableNetwork = {}; +}, { code: 'ERR_INVALID_ARG_TYPE' }); +assert.strictEqual(process.report.disableNetwork, true); + if (!common.isWindows) { // Verify that process.report.signal behaves properly. assert.strictEqual(process.report.signal, 'SIGUSR2'); diff --git a/test/report/test-report-disable-network.js b/test/report/test-report-disable-network.js new file mode 100644 index 00000000000000..519f9b9f8e79f4 --- /dev/null +++ b/test/report/test-report-disable-network.js @@ -0,0 +1,38 @@ +'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 disable network option', () => { + before(() => { + tmpdir.refresh(); + process.report.directory = tmpdir.path; + }); + + it('should be configurable with --report-disable-network', () => { + const args = ['--report-disable-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.disableNetwork', () => { + process.report.disableNetwork = true; + process.report.writeReport(); + validate(process.pid); + }); +});