Skip to content

Commit aee1485

Browse files
committed
src: add errorProperties on process.report
1 parent bc23d10 commit aee1485

File tree

7 files changed

+96
-31
lines changed

7 files changed

+96
-31
lines changed

lib/internal/process/execution.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ function createOnGlobalUncaughtException() {
157157
report.writeReport(er ? er.message : 'Exception',
158158
'Exception',
159159
null,
160-
er ? er.stack : undefined);
160+
er ? er : {});
161161
}
162162
} catch {} // Ignore the exception. Diagnostic reporting is unavailable.
163163
}

lib/internal/process/report.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ const report = {
2525
throw new ERR_INVALID_ARG_TYPE('err', 'Object', err);
2626
}
2727

28-
return nr.writeReport('JavaScript API', 'API', file, err.stack);
28+
return nr.writeReport('JavaScript API', 'API', file, err);
2929
},
3030
getReport(err) {
3131
if (err === undefined)
3232
err = new ERR_SYNTHETIC();
3333
else if (err === null || typeof err !== 'object')
3434
throw new ERR_INVALID_ARG_TYPE('err', 'Object', err);
3535

36-
return JSONParse(nr.getReport(err.stack));
36+
return JSONParse(nr.getReport(err));
3737
},
3838
get directory() {
3939
return nr.getDirectory();

src/node_errors.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ void OnFatalError(const char* location, const char* message) {
433433

434434
if (report_on_fatalerror) {
435435
report::TriggerNodeReport(
436-
isolate, env, message, "FatalError", "", Local<String>());
436+
isolate, env, message, "FatalError", "", Local<Object>());
437437
}
438438

439439
fflush(stderr);

src/node_report.cc

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,18 @@ using node::Mutex;
3737
using node::NativeSymbolDebuggingContext;
3838
using node::TIME_TYPE;
3939
using node::worker::Worker;
40+
using v8::Array;
41+
using v8::Context;
4042
using v8::HeapSpaceStatistics;
4143
using v8::HeapStatistics;
4244
using v8::Isolate;
4345
using v8::Local;
46+
using v8::Number;
47+
using v8::Object;
48+
using v8::StackTrace;
4449
using v8::String;
50+
using v8::TryCatch;
51+
using v8::Value;
4552
using v8::V8;
4653

4754
namespace per_process = node::per_process;
@@ -53,13 +60,16 @@ static void WriteNodeReport(Isolate* isolate,
5360
const char* trigger,
5461
const std::string& filename,
5562
std::ostream& out,
56-
Local<String> stackstr,
63+
Local<Object> error,
5764
bool compact);
5865
static void PrintVersionInformation(JSONWriter* writer);
59-
static void PrintJavaScriptStack(JSONWriter* writer,
60-
Isolate* isolate,
61-
Local<String> stackstr,
62-
const char* trigger);
66+
static void PrintJavaScriptErrorStack(JSONWriter* writer,
67+
Isolate* isolate,
68+
Local<Object> error,
69+
const char* trigger);
70+
static void PrintJavaScriptErrorProperties(JSONWriter* writer,
71+
Isolate* isolate,
72+
Local<Object> error);
6373
static void PrintNativeStack(JSONWriter* writer);
6474
static void PrintResourceUsage(JSONWriter* writer);
6575
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate);
@@ -76,7 +86,7 @@ std::string TriggerNodeReport(Isolate* isolate,
7686
const char* message,
7787
const char* trigger,
7888
const std::string& name,
79-
Local<String> stackstr) {
89+
Local<Object> error) {
8090
std::string filename;
8191

8292
// Determine the required report filename. In order of priority:
@@ -142,7 +152,7 @@ std::string TriggerNodeReport(Isolate* isolate,
142152
compact = per_process::cli_options->report_compact;
143153
}
144154
WriteNodeReport(isolate, env, message, trigger, filename, *outstream,
145-
stackstr, compact);
155+
error, compact);
146156

147157
// Do not close stdout/stderr, only close files we opened.
148158
if (outfile.is_open()) {
@@ -161,9 +171,9 @@ void GetNodeReport(Isolate* isolate,
161171
Environment* env,
162172
const char* message,
163173
const char* trigger,
164-
Local<String> stackstr,
174+
Local<Object> error,
165175
std::ostream& out) {
166-
WriteNodeReport(isolate, env, message, trigger, "", out, stackstr, false);
176+
WriteNodeReport(isolate, env, message, trigger, "", out, error, false);
167177
}
168178

169179
// Internal function to coordinate and write the various
@@ -174,7 +184,7 @@ static void WriteNodeReport(Isolate* isolate,
174184
const char* trigger,
175185
const std::string& filename,
176186
std::ostream& out,
177-
Local<String> stackstr,
187+
Local<Object> error,
178188
bool compact) {
179189
// Obtain the current time and the pid.
180190
TIME_TYPE tm_struct;
@@ -259,8 +269,13 @@ static void WriteNodeReport(Isolate* isolate,
259269
PrintVersionInformation(&writer);
260270
writer.json_objectend();
261271

262-
// Report summary JavaScript stack backtrace
263-
PrintJavaScriptStack(&writer, isolate, stackstr, trigger);
272+
writer.json_objectstart("javascriptStack");
273+
// Report summary JavaScript error stack backtrace
274+
PrintJavaScriptErrorStack(&writer, isolate, error, trigger);
275+
276+
// Report summary JavaScript error properties backtrace
277+
PrintJavaScriptErrorProperties(&writer, isolate, error);
278+
writer.json_objectend(); // the end of 'javascriptStack'
264279

265280
// Report native stack backtrace
266281
PrintNativeStack(&writer);
@@ -301,7 +316,7 @@ static void WriteNodeReport(Isolate* isolate,
301316
env,
302317
"Worker thread subreport",
303318
trigger,
304-
Local<String>(),
319+
Local<Object>(),
305320
os);
306321

307322
Mutex::ScopedLock lock(workers_mutex);
@@ -455,18 +470,56 @@ static void PrintNetworkInterfaceInfo(JSONWriter* writer) {
455470
}
456471
}
457472

473+
static void PrintJavaScriptErrorProperties(JSONWriter* writer,
474+
Isolate* isolate,
475+
Local<Object> error) {
476+
writer->json_objectstart("errorProperties");
477+
if (!error.IsEmpty()) {
478+
TryCatch try_catch(isolate);
479+
Local<Context> context = error->GetIsolate()->GetCurrentContext();
480+
Local<Array> keys;
481+
if (!error->GetOwnPropertyNames(context).ToLocal(&keys)) {
482+
return writer->json_objectend(); // the end of 'errorProperties'
483+
}
484+
uint32_t keys_length = keys->Length();
485+
for (uint32_t i = 0; i < keys_length; i++) {
486+
Local<Value> key;
487+
if (!keys->Get(context, i).ToLocal(&key) || !key->IsString()) {
488+
continue;
489+
}
490+
Local<Value> value;
491+
Local<String> value_string;
492+
if (!error->Get(context, key).ToLocal(&value) ||
493+
!value->ToString(context).ToLocal(&value_string)) {
494+
continue;
495+
}
496+
String::Utf8Value k(isolate, key);
497+
if (!strcmp(*k, "stack") || !strcmp(*k, "message")) continue;
498+
String::Utf8Value v(isolate, value_string);
499+
writer->json_keyvalue(std::string(*k, k.length()),
500+
std::string(*v, v.length()));
501+
}
502+
}
503+
writer->json_objectend(); // the end of 'errorProperties'
504+
}
505+
458506
// Report the JavaScript stack.
459-
static void PrintJavaScriptStack(JSONWriter* writer,
507+
static void PrintJavaScriptErrorStack(JSONWriter* writer,
460508
Isolate* isolate,
461-
Local<String> stackstr,
509+
Local<Object> error,
462510
const char* trigger) {
463-
writer->json_objectstart("javascriptStack");
464-
465-
std::string ss;
511+
Local<Value> stackstr;
512+
std::string ss = "";
513+
TryCatch try_catch(isolate);
466514
if ((!strcmp(trigger, "FatalError")) ||
467515
(!strcmp(trigger, "Signal"))) {
468516
ss = "No stack.\nUnavailable.\n";
469-
} else {
517+
} else if (!error.IsEmpty() &&
518+
error
519+
->Get(isolate->GetCurrentContext(),
520+
node::FIXED_ONE_BYTE_STRING(isolate,
521+
"stack"))
522+
.ToLocal(&stackstr)) {
470523
String::Utf8Value sv(isolate, stackstr);
471524
ss = std::string(*sv, sv.length());
472525
}
@@ -490,7 +543,6 @@ static void PrintJavaScriptStack(JSONWriter* writer,
490543
}
491544
writer->json_arrayend();
492545
}
493-
writer->json_objectend();
494546
}
495547

496548
// Report a native stack backtrace

src/node_report.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ std::string TriggerNodeReport(v8::Isolate* isolate,
2020
const char* message,
2121
const char* trigger,
2222
const std::string& name,
23-
v8::Local<v8::String> stackstr);
23+
v8::Local<v8::Object> error);
2424
void GetNodeReport(v8::Isolate* isolate,
2525
node::Environment* env,
2626
const char* message,
2727
const char* trigger,
28-
v8::Local<v8::String> stackstr,
28+
v8::Local<v8::Object> error,
2929
std::ostream& out);
3030

3131
// Function declarations - utility functions in src/node_report_utils.cc

src/node_report_module.cc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,21 @@ void WriteReport(const FunctionCallbackInfo<Value>& info) {
3232
Isolate* isolate = env->isolate();
3333
HandleScope scope(isolate);
3434
std::string filename;
35-
Local<String> stackstr;
35+
Local<Object> error;
3636

3737
CHECK_EQ(info.Length(), 4);
3838
String::Utf8Value message(isolate, info[0].As<String>());
3939
String::Utf8Value trigger(isolate, info[1].As<String>());
40-
stackstr = info[3].As<String>();
4140

4241
if (info[2]->IsString())
4342
filename = *String::Utf8Value(isolate, info[2]);
43+
if (!info[3].IsEmpty() && info[3]->IsObject())
44+
error = info[3].As<Object>();
45+
else
46+
error = Local<Object>();
4447

4548
filename = TriggerNodeReport(
46-
isolate, env, *message, *trigger, filename, stackstr);
49+
isolate, env, *message, *trigger, filename, error);
4750
// Return value is the report filename
4851
info.GetReturnValue().Set(
4952
String::NewFromUtf8(isolate, filename.c_str(), v8::NewStringType::kNormal)
@@ -55,10 +58,17 @@ void GetReport(const FunctionCallbackInfo<Value>& info) {
5558
Environment* env = Environment::GetCurrent(info);
5659
Isolate* isolate = env->isolate();
5760
HandleScope scope(isolate);
61+
Local<Object> error;
5862
std::ostringstream out;
5963

64+
CHECK_EQ(info.Length(), 1);
65+
if (!info[0].IsEmpty() && info[0]->IsObject())
66+
error = info[0].As<Object>();
67+
else
68+
error = Local<Object>();
69+
6070
GetNodeReport(
61-
isolate, env, "JavaScript API", __func__, info[0].As<String>(), out);
71+
isolate, env, "JavaScript API", __func__, error, out);
6272

6373
// Return value is the contents of a report as a string.
6474
info.GetReturnValue().Set(String::NewFromUtf8(isolate,

test/common/report.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,10 @@ function _validateContent(report) {
144144
assert.strictEqual(header.host, os.hostname());
145145

146146
// Verify the format of the javascriptStack section.
147-
checkForUnknownFields(report.javascriptStack, ['message', 'stack']);
147+
checkForUnknownFields(report.javascriptStack,
148+
['message', 'stack', 'errorProperties']);
149+
assert.strictEqual(typeof report.javascriptStack.errorProperties,
150+
'object');
148151
assert.strictEqual(typeof report.javascriptStack.message, 'string');
149152
if (report.javascriptStack.stack !== undefined) {
150153
assert(Array.isArray(report.javascriptStack.stack));

0 commit comments

Comments
 (0)