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

report: misc cleanup II #25610

Closed
wants to merge 6 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
265 changes: 132 additions & 133 deletions lib/internal/process/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,153 +11,152 @@ exports.setup = function() {
const REPORTFILENAME = 3;
const REPORTPATH = 4;
const REPORTVERBOSE = 5;
if (internalBinding('config').hasReport) {
// If report is enabled, extract the binding and
// wrap the APIs with thin layers, with some error checks.
// user options can come in from CLI / ENV / API.
// CLI and ENV is intercepted in C++ and the API call here (JS).
// So sync up with both sides as appropriate - initially from
// C++ to JS and from JS to C++ whenever the API is called.
// Some events are controlled purely from JS (signal | exception)
// and some from C++ (fatalerror) so this sync-up is essential for
// correct behavior and alignment with the supplied tunables.
const nr = internalBinding('report');

// Keep it un-exposed; lest programs play with it
// leaving us with a lot of unwanted sanity checks.
let config = {
events: [],
signal: 'SIGUSR2',
filename: '',
path: '',
verbose: false
};
const report = {
setDiagnosticReportOptions(options) {
emitExperimentalWarning('report');
// Reuse the null and undefined checks. Save
// space when dealing with large number of arguments.
const list = parseOptions(options);
// If report is enabled, extract the binding and
// wrap the APIs with thin layers, with some error checks.
// user options can come in from CLI / ENV / API.
// CLI and ENV is intercepted in C++ and the API call here (JS).
// So sync up with both sides as appropriate - initially from
// C++ to JS and from JS to C++ whenever the API is called.
// Some events are controlled purely from JS (signal | exception)
// and some from C++ (fatalerror) so this sync-up is essential for
// correct behavior and alignment with the supplied tunables.
const nr = internalBinding('report');

// Flush the stale entries from report, as
// we are refreshing it, items that the users did not
// touch may be hanging around stale otherwise.
config = {};
// Keep it un-exposed; lest programs play with it
// leaving us with a lot of unwanted sanity checks.
let config = {
events: [],
signal: 'SIGUSR2',
filename: '',
path: '',
verbose: false
};
const report = {
setDiagnosticReportOptions(options) {
emitExperimentalWarning('report');
// Reuse the null and undefined checks. Save
// space when dealing with large number of arguments.
const list = parseOptions(options);

// The parseOption method returns an array that include
// the indices at which valid params are present.
list.forEach((i) => {
switch (i) {
case REPORTEVENTS:
if (Array.isArray(options.events))
config.events = options.events;
else
throw new ERR_INVALID_ARG_TYPE('events',
'Array',
options.events);
break;
case REPORTSIGNAL:
if (typeof options.signal !== 'string') {
throw new ERR_INVALID_ARG_TYPE('signal',
'String',
options.signal);
}
process.removeListener(config.signal, handleSignal);
if (config.events.includes('signal'))
process.on(options.signal, handleSignal);
config.signal = options.signal;
break;
case REPORTFILENAME:
if (typeof options.filename !== 'string') {
throw new ERR_INVALID_ARG_TYPE('filename',
'String',
options.filename);
}
config.filename = options.filename;
break;
case REPORTPATH:
if (typeof options.path !== 'string')
throw new ERR_INVALID_ARG_TYPE('path', 'String', options.path);
config.path = options.path;
break;
case REPORTVERBOSE:
if (typeof options.verbose !== 'string' &&
typeof options.verbose !== 'boolean') {
throw new ERR_INVALID_ARG_TYPE('verbose',
'Booelan | String' +
' (true|false|yes|no)',
options.verbose);
}
config.verbose = options.verbose;
break;
}
});
// Upload this new config to C++ land
nr.syncConfig(config, true);
},
// Flush the stale entries from report, as
// we are refreshing it, items that the users did not
// touch may be hanging around stale otherwise.
config = {};

// The parseOption method returns an array that include
// the indices at which valid params are present.
list.forEach((i) => {
switch (i) {
case REPORTEVENTS:
if (Array.isArray(options.events))
config.events = options.events;
else
throw new ERR_INVALID_ARG_TYPE('events',
'Array',
options.events);
break;
case REPORTSIGNAL:
if (typeof options.signal !== 'string') {
throw new ERR_INVALID_ARG_TYPE('signal',
'String',
options.signal);
}
process.removeListener(config.signal, handleSignal);
if (config.events.includes('signal'))
process.on(options.signal, handleSignal);
config.signal = options.signal;
break;
case REPORTFILENAME:
if (typeof options.filename !== 'string') {
throw new ERR_INVALID_ARG_TYPE('filename',
'String',
options.filename);
}
config.filename = options.filename;
break;
case REPORTPATH:
if (typeof options.path !== 'string')
throw new ERR_INVALID_ARG_TYPE('path', 'String', options.path);
config.path = options.path;
break;
case REPORTVERBOSE:
if (typeof options.verbose !== 'string' &&
typeof options.verbose !== 'boolean') {
throw new ERR_INVALID_ARG_TYPE('verbose',
'Booelan | String' +
' (true|false|yes|no)',
options.verbose);
}
config.verbose = options.verbose;
break;
}
});
// Upload this new config to C++ land
nr.syncConfig(config, true);
},


triggerReport(file, err) {
emitExperimentalWarning('report');
if (err == null) {
if (file == null) {
return nr.triggerReport(new ERR_SYNTHETIC(
'JavaScript Callstack').stack);
}
if (typeof file !== 'string')
throw new ERR_INVALID_ARG_TYPE('file', 'String', file);
return nr.triggerReport(file, new ERR_SYNTHETIC(
triggerReport(file, err) {
emitExperimentalWarning('report');
if (err == null) {
if (file == null) {
return nr.triggerReport(new ERR_SYNTHETIC(
'JavaScript Callstack').stack);
}
if (typeof err !== 'object')
throw new ERR_INVALID_ARG_TYPE('err', 'Object', err);
if (file == null)
return nr.triggerReport(err.stack);
if (typeof file !== 'string')
throw new ERR_INVALID_ARG_TYPE('file', 'String', file);
return nr.triggerReport(file, err.stack);
},
getReport(err) {
emitExperimentalWarning('report');
if (err == null) {
return nr.getReport(new ERR_SYNTHETIC('JavaScript Callstack').stack);
} else if (typeof err !== 'object') {
throw new ERR_INVALID_ARG_TYPE('err', 'Objct', err);
} else {
return nr.getReport(err.stack);
}
return nr.triggerReport(file, new ERR_SYNTHETIC(
'JavaScript Callstack').stack);
}
};
if (typeof err !== 'object')
throw new ERR_INVALID_ARG_TYPE('err', 'Object', err);
if (file == null)
return nr.triggerReport(err.stack);
if (typeof file !== 'string')
throw new ERR_INVALID_ARG_TYPE('file', 'String', file);
return nr.triggerReport(file, err.stack);
},
getReport(err) {
emitExperimentalWarning('report');
if (err == null) {
return nr.getReport(new ERR_SYNTHETIC('JavaScript Callstack').stack);
} else if (typeof err !== 'object') {
throw new ERR_INVALID_ARG_TYPE('err', 'Objct', err);
} else {
return nr.getReport(err.stack);
}
}
};

// Download the CLI / ENV config into JS land.
nr.syncConfig(config, false);
// Download the CLI / ENV config into JS land.
nr.syncConfig(config, false);

function handleSignal(signo) {
if (typeof signo !== 'string')
signo = config.signal;
nr.onUserSignal(signo);
}
function handleSignal(signo) {
if (typeof signo !== 'string')
signo = config.signal;
nr.onUserSignal(signo);
}

if (config.events.includes('signal')) {
process.on(config.signal, handleSignal);
}
if (config.events.includes('signal')) {
process.on(config.signal, handleSignal);
}

function parseOptions(obj) {
const list = [];
if (obj == null)
return list;
if (obj.events != null)
list.push(REPORTEVENTS);
if (obj.signal != null)
list.push(REPORTSIGNAL);
if (obj.filename != null)
list.push(REPORTFILENAME);
if (obj.path != null)
list.push(REPORTPATH);
if (obj.verbose != null)
list.push(REPORTVERBOSE);
function parseOptions(obj) {
const list = [];
if (obj == null)
return list;
}
process.report = report;
if (obj.events != null)
list.push(REPORTEVENTS);
if (obj.signal != null)
list.push(REPORTSIGNAL);
if (obj.filename != null)
list.push(REPORTFILENAME);
if (obj.path != null)
list.push(REPORTPATH);
if (obj.verbose != null)
list.push(REPORTVERBOSE);
return list;
}
process.report = report;
};
4 changes: 0 additions & 4 deletions src/node_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ static void Initialize(Local<Object> target,

#endif // NODE_HAVE_I18N_SUPPORT

#if defined(NODE_REPORT)
READONLY_TRUE_PROPERTY(target, "hasReport");
#endif // NODE_REPORT

if (env->abort_on_uncaught_exception())
READONLY_TRUE_PROPERTY(target, "shouldAbortOnUncaughtException");

Expand Down
5 changes: 2 additions & 3 deletions src/node_errors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -319,17 +319,16 @@ void OnFatalError(const char* location, const char* message) {
}
#ifdef NODE_REPORT
Isolate* isolate = Isolate::GetCurrent();
std::string filename;
Environment* env = Environment::GetCurrent(isolate);
if (env != nullptr) {
std::shared_ptr<PerIsolateOptions> options = env->isolate_data()->options();
if (options->report_on_fatalerror) {
report::TriggerNodeReport(
isolate, env, message, __func__, filename, Local<String>());
isolate, env, message, __func__, "", Local<String>());
}
} else {
report::TriggerNodeReport(
isolate, nullptr, message, __func__, filename, Local<String>());
isolate, nullptr, message, __func__, "", Local<String>());
}
#endif // NODE_REPORT
fflush(stderr);
Expand Down
6 changes: 1 addition & 5 deletions src/node_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -501,17 +501,13 @@ static void PrintNativeStack(JSONWriter* writer) {
writer->json_arraystart("nativeStack");
int i;
std::ostringstream buf;
for (i = 1; i < size - 1; i += 1) {
for (i = 1; i < size; i++) {
void* frame = frames[i];
buf.str("");
buf << " [pc=" << frame << "] ";
buf << sym_ctx->LookupSymbol(frame).Display().c_str();
writer->json_element(buf.str());
}
buf.str("");
buf << " [pc=" << frames[i] << "] ";
buf << sym_ctx->LookupSymbol(frames[i]).Display().c_str();
writer->json_element(buf.str());
writer->json_arrayend();
}

Expand Down
Loading