summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-02-10 00:06:03 +0100
committerAnna Henningsen <anna@addaleax.net>2019-02-12 00:55:46 +0100
commit2c84f6e75cc513fe6e958f0489d104ee883db232 (patch)
treea7e70744a9d17cec3433cdd040366d26e0575bbc
parent6edf88284b2ef522d2f073e66fa32e9cbe6fafd2 (diff)
downloadandroid-node-v8-2c84f6e75cc513fe6e958f0489d104ee883db232.tar.gz
android-node-v8-2c84f6e75cc513fe6e958f0489d104ee883db232.tar.bz2
android-node-v8-2c84f6e75cc513fe6e958f0489d104ee883db232.zip
report: make more items programmatically accessible
Prefer structured output over stringified information for libuv handles and the native stack trace. PR-URL: https://github.com/nodejs/node/pull/26019 Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: James M Snell <jasnell@gmail.com>
-rw-r--r--doc/api/report.md79
-rw-r--r--src/node_report.cc15
-rw-r--r--src/node_report.h4
-rw-r--r--src/node_report_utils.cc109
4 files changed, 132 insertions, 75 deletions
diff --git a/doc/api/report.md b/doc/api/report.md
index 89bb203691..8d6d054c0a 100644
--- a/doc/api/report.md
+++ b/doc/api/report.md
@@ -78,12 +78,26 @@ is provided below for reference.
]
},
"nativeStack": [
- " [pc=0xa7ef87] [/home/nodeuser/project/node/out/Release/node]",
- " [pc=0xa81adb] report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::string, v8::Local<v8::String>) [/home/nodeuser/project/node/out/Release/node]",
- " [pc=0xa834f2] report::OnUncaughtException(v8::FunctionCallbackInfo<v8::Value> const&) [/home/nodeuser/project/node/out/Release/node]",
- " [pc=0xbe6b78] [/home/nodeuser/project/node/out/Release/node]",
- " [pc=0xbe7596] v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [/home/nodeuser/project/node/out/Release/node]",
- " [pc=0x1930cae] [/home/nodeuser/project/node/out/Release/node]"
+ {
+ "pc": "0x000055b57f07a9ef",
+ "symbol": "report::GetNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, v8::Local<v8::String>, std::ostream&) [./node]"
+ },
+ {
+ "pc": "0x000055b57f07cf03",
+ "symbol": "report::GetReport(v8::FunctionCallbackInfo<v8::Value> const&) [./node]"
+ },
+ {
+ "pc": "0x000055b57f1bccfd",
+ "symbol": " [./node]"
+ },
+ {
+ "pc": "0x000055b57f1be048",
+ "symbol": "v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [./node]"
+ },
+ {
+ "pc": "0x000055b57feeda0e",
+ "symbol": " [./node]"
+ }
],
"javascriptHeap": {
"totalMemory": 6127616,
@@ -175,46 +189,75 @@ is provided below for reference.
"details": ""
},
{
+ "repeat": 0,
+ "firesInMsFromNow": 94403548320796,
+ "expired": true,
"type": "timer",
"is_active": false,
"is_referenced": false,
- "address": "0x00007fff5fbfeab0",
- "details": "repeat: 0, timeout expired: 18075165916 ms ago"
+ "address": "0x00007fff5fbfeab0"
},
{
"type": "check",
"is_active": true,
"is_referenced": false,
- "address": "0x00007fff5fbfeb48",
- "details": ""
+ "address": "0x00007fff5fbfeb48"
},
{
"type": "idle",
"is_active": false,
"is_referenced": true,
- "address": "0x00007fff5fbfebc0",
- "details": ""
+ "address": "0x00007fff5fbfebc0"
},
{
"type": "prepare",
"is_active": false,
"is_referenced": false,
- "address": "0x00007fff5fbfec38",
- "details": ""
+ "address": "0x00007fff5fbfec38"
},
{
"type": "check",
"is_active": false,
"is_referenced": false,
- "address": "0x00007fff5fbfecb0",
- "details": ""
+ "address": "0x00007fff5fbfecb0"
},
{
"type": "async",
"is_active": true,
"is_referenced": false,
- "address": "0x000000010188f2e0",
- "details": ""
+ "address": "0x000000010188f2e0"
+ },
+ {
+ "width": 204,
+ "height": 55,
+ "fd": 17,
+ "writeQueueSize": 0,
+ "readable": true,
+ "writable": true,
+ "type": "tty",
+ "is_active": false,
+ "is_referenced": true,
+ "address": "0x000055b581db0e18"
+ },
+ {
+ "signum": 28,
+ "signal": "SIGWINCH",
+ "type": "signal",
+ "is_active": true,
+ "is_referenced": false,
+ "address": "0x000055b581d80010"
+ },
+ {
+ "width": 204,
+ "height": 55,
+ "fd": 19,
+ "writeQueueSize": 0,
+ "readable": true,
+ "writable": true,
+ "type": "tty",
+ "is_active": true,
+ "is_referenced": true,
+ "address": "0x000055b581df59f8"
},
{
"type": "loop",
diff --git a/src/node_report.cc b/src/node_report.cc
index 7477a2fd24..1a459a2d1c 100644
--- a/src/node_report.cc
+++ b/src/node_report.cc
@@ -216,9 +216,8 @@ void GetNodeReport(Isolate* isolate,
// Obtain the current time and the pid (platform dependent)
TIME_TYPE tm_struct;
LocalTime(&tm_struct);
- std::string str = "NA";
WriteNodeReport(
- isolate, env, message, location, str, out, stackstr, &tm_struct);
+ isolate, env, message, location, "", out, stackstr, &tm_struct);
}
// Internal function to coordinate and write the various
@@ -249,7 +248,7 @@ static void WriteNodeReport(Isolate* isolate,
if (!filename.empty())
writer.json_keyvalue("filename", filename);
else
- writer.json_keyvalue("filename", "''");
+ writer.json_keyvalue("filename", JSONWriter::Null{});
// Report dump event and module load date/time stamps
char timebuf[64];
@@ -431,13 +430,13 @@ static void PrintNativeStack(JSONWriter* writer) {
const int size = sym_ctx->GetStackTrace(frames, arraysize(frames));
writer->json_arraystart("nativeStack");
int i;
- std::ostringstream buf;
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());
+ writer->json_start();
+ writer->json_keyvalue("pc",
+ ValueToHexString(reinterpret_cast<uintptr_t>(frame)));
+ writer->json_keyvalue("symbol", sym_ctx->LookupSymbol(frame).Display());
+ writer->json_end();
}
writer->json_arrayend();
}
diff --git a/src/node_report.h b/src/node_report.h
index eb38bee8c6..c83c52eb39 100644
--- a/src/node_report.h
+++ b/src/node_report.h
@@ -54,7 +54,6 @@ void GetNodeReport(v8::Isolate* isolate,
std::ostream& out);
// Function declarations - utility functions in src/node_report_utils.cc
-void ReportEndpoints(uv_handle_t* h, std::ostringstream& out);
void WalkHandle(uv_handle_t* h, void* arg);
std::string EscapeJsonChars(const std::string& str);
@@ -157,6 +156,8 @@ class JSONWriter {
state_ = kAfterValue;
}
+ struct Null {}; // Usable as a JSON value.
+
private:
template <typename T,
typename test_for_number = typename std::
@@ -168,6 +169,7 @@ class JSONWriter {
out_ << number;
}
+ inline void write_value(Null null) { out_ << "null"; }
inline void write_value(const char* str) { write_string(str); }
inline void write_value(const std::string& str) { write_string(str); }
diff --git a/src/node_report_utils.cc b/src/node_report_utils.cc
index 34fa1b7405..db72901187 100644
--- a/src/node_report_utils.cc
+++ b/src/node_report_utils.cc
@@ -5,20 +5,24 @@ namespace report {
using node::MallocedBuffer;
+static constexpr auto null = JSONWriter::Null{};
+
// Utility function to format libuv socket information.
-void ReportEndpoints(uv_handle_t* h, std::ostringstream& out) {
+static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
struct sockaddr_storage addr_storage;
struct sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
int addr_size = sizeof(addr_storage);
int rc = -1;
+ bool wrote_local_endpoint = false;
+ bool wrote_remote_endpoint = false;
switch (h->type) {
case UV_UDP:
- rc = uv_udp_getsockname(&(handle->udp), addr, &addr_size);
+ rc = uv_udp_getsockname(&handle->udp, addr, &addr_size);
break;
case UV_TCP:
- rc = uv_tcp_getsockname(&(handle->tcp), addr, &addr_size);
+ rc = uv_tcp_getsockname(&handle->tcp, addr, &addr_size);
break;
default:
break;
@@ -28,31 +32,42 @@ void ReportEndpoints(uv_handle_t* h, std::ostringstream& out) {
uv_getnameinfo_t local;
rc = uv_getnameinfo(h->loop, &local, nullptr, addr, NI_NUMERICSERV);
- if (rc == 0)
- out << local.host << ":" << local.service;
+ if (rc == 0) {
+ writer->json_objectstart("localEndpoint");
+ writer->json_keyvalue("host", local.host);
+ writer->json_keyvalue("port", local.service);
+ writer->json_objectend();
+ wrote_local_endpoint = true;
+ }
+ }
+ if (!wrote_local_endpoint) writer->json_keyvalue("localEndpoint", null);
- if (h->type == UV_TCP) {
- // Get the remote end of the connection.
- rc = uv_tcp_getpeername(&(handle->tcp), addr, &addr_size);
- if (rc == 0) {
- uv_getnameinfo_t remote;
- rc = uv_getnameinfo(h->loop, &remote, nullptr, addr, NI_NUMERICSERV);
+ if (h->type == UV_TCP) {
+ // Get the remote end of the connection.
+ rc = uv_tcp_getpeername(&handle->tcp, addr, &addr_size);
+ if (rc == 0) {
+ uv_getnameinfo_t remote;
+ rc = uv_getnameinfo(h->loop, &remote, nullptr, addr, NI_NUMERICSERV);
- if (rc == 0)
- out << " connected to " << remote.host << ":" << remote.service;
- } else if (rc == UV_ENOTCONN) {
- out << " (not connected)";
+ if (rc == 0) {
+ writer->json_objectstart("remoteEndpoint");
+ writer->json_keyvalue("host", remote.host);
+ writer->json_keyvalue("port", remote.service);
+ writer->json_objectend();
+ wrote_local_endpoint = true;
}
}
}
+ if (!wrote_remote_endpoint) writer->json_keyvalue("remoteEndpoint", null);
}
// Utility function to format libuv path information.
-void ReportPath(uv_handle_t* h, std::ostringstream& out) {
+static void ReportPath(uv_handle_t* h, JSONWriter* writer) {
MallocedBuffer<char> buffer(0);
int rc = -1;
size_t size = 0;
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
+ bool wrote_filename = false;
// First call to get required buffer size.
switch (h->type) {
case UV_FS_EVENT:
@@ -65,7 +80,7 @@ void ReportPath(uv_handle_t* h, std::ostringstream& out) {
break;
}
if (rc == UV_ENOBUFS) {
- buffer = MallocedBuffer<char>(size);
+ buffer = MallocedBuffer<char>(size + 1);
switch (h->type) {
case UV_FS_EVENT:
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size);
@@ -78,55 +93,58 @@ void ReportPath(uv_handle_t* h, std::ostringstream& out) {
}
if (rc == 0) {
// buffer is not null terminated.
- std::string name(buffer.data, size);
- out << "filename: " << name;
+ buffer.data[size] = '\0';
+ writer->json_keyvalue("filename", buffer.data);
+ wrote_filename = true;
}
}
+ if (!wrote_filename) writer->json_keyvalue("filename", null);
}
// Utility function to walk libuv handles.
void WalkHandle(uv_handle_t* h, void* arg) {
const char* type = uv_handle_type_name(h->type);
- std::ostringstream data;
JSONWriter* writer = static_cast<JSONWriter*>(arg);
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
+ writer->json_start();
+
switch (h->type) {
case UV_FS_EVENT:
case UV_FS_POLL:
- ReportPath(h, data);
+ ReportPath(h, writer);
break;
case UV_PROCESS:
- data << "pid: " << handle->process.pid;
+ writer->json_keyvalue("pid", handle->process.pid);
break;
case UV_TCP:
case UV_UDP:
- ReportEndpoints(h, data);
+ ReportEndpoints(h, writer);
break;
case UV_TIMER: {
uint64_t due = handle->timer.timeout;
uint64_t now = uv_now(handle->timer.loop);
- data << "repeat: " << uv_timer_get_repeat(&(handle->timer));
- if (due > now) {
- data << ", timeout in: " << (due - now) << " ms";
- } else {
- data << ", timeout expired: " << (now - due) << " ms ago";
- }
+ writer->json_keyvalue("repeat", uv_timer_get_repeat(&handle->timer));
+ writer->json_keyvalue("firesInMsFromNow",
+ static_cast<int64_t>(due - now));
+ writer->json_keyvalue("expired", now >= due);
break;
}
case UV_TTY: {
int height, width, rc;
rc = uv_tty_get_winsize(&(handle->tty), &width, &height);
if (rc == 0) {
- data << "width: " << width << ", height: " << height;
+ writer->json_keyvalue("width", width);
+ writer->json_keyvalue("height", height);
}
break;
}
case UV_SIGNAL:
// SIGWINCH is used by libuv so always appears.
// See http://docs.libuv.org/en/v1.x/signal.html
- data << "signum: " << handle->signal.signum << " (" <<
- node::signo_string(handle->signal.signum) << ")";
+ writer->json_keyvalue("signum", handle->signal.signum);
+ writer->json_keyvalue("signal",
+ node::signo_string(handle->signal.signum));
break;
default:
break;
@@ -141,13 +159,10 @@ void WalkHandle(uv_handle_t* h, void* arg) {
// values they contain.
int send_size = 0;
int recv_size = 0;
- if (h->type == UV_TCP || h->type == UV_UDP) {
- data << ", ";
- }
uv_send_buffer_size(h, &send_size);
uv_recv_buffer_size(h, &recv_size);
- data << "send buffer size: " << send_size
- << ", recv buffer size: " << recv_size;
+ writer->json_keyvalue("sendBufferSize", send_size);
+ writer->json_keyvalue("recvBufferSize", recv_size);
}
#ifndef _WIN32
@@ -157,18 +172,16 @@ void WalkHandle(uv_handle_t* h, void* arg) {
int rc = uv_fileno(h, &fd_v);
if (rc == 0) {
+ writer->json_keyvalue("fd", static_cast<int>(fd_v));
switch (fd_v) {
case 0:
- data << ", stdin";
+ writer->json_keyvalue("stdio", "stdin");
break;
case 1:
- data << ", stdout";
+ writer->json_keyvalue("stdio", "stdout");
break;
case 2:
- data << ", stderr";
- break;
- default:
- data << ", file descriptor: " << static_cast<int>(fd_v);
+ writer->json_keyvalue("stdio", "stderr");
break;
}
}
@@ -176,18 +189,18 @@ void WalkHandle(uv_handle_t* h, void* arg) {
#endif
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY) {
- data << ", write queue size: " << handle->stream.write_queue_size;
- data << (uv_is_readable(&handle->stream) ? ", readable" : "")
- << (uv_is_writable(&handle->stream) ? ", writable" : "");
+ writer->json_keyvalue("writeQueueSize", handle->stream.write_queue_size);
+ writer->json_keyvalue("readable",
+ static_cast<bool>(uv_is_readable(&handle->stream)));
+ writer->json_keyvalue("writable",
+ static_cast<bool>(uv_is_writable(&handle->stream)));
}
- writer->json_start();
writer->json_keyvalue("type", type);
writer->json_keyvalue("is_active", static_cast<bool>(uv_is_active(h)));
writer->json_keyvalue("is_referenced", static_cast<bool>(uv_has_ref(h)));
writer->json_keyvalue("address",
ValueToHexString(reinterpret_cast<uint64_t>(h)));
- writer->json_keyvalue("details", data.str());
writer->json_end();
}