diff --git a/binding.gyp b/binding.gyp index 3d0be4e..c665e5b 100644 --- a/binding.gyp +++ b/binding.gyp @@ -14,6 +14,9 @@ "dll_files": [ "dbghelp.dll", "Netapi32.dll" ], }], ], + "defines": [ + 'NODEREPORT_VERSION=" exports) { node_isolate = isolate; SetLoadTime(); + SetVersionString(isolate); const char* verbose_switch = secure_getenv("NODEREPORT_VERBOSE"); if (verbose_switch != nullptr) { diff --git a/src/node_report.cc b/src/node_report.cc index a54d8ec..bb20b02 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -1,11 +1,9 @@ #include "node_report.h" -#include "node_version.h" #include "v8.h" #include "time.h" -#include "zlib.h" -#include "ares.h" #include +#include #include #include #include @@ -35,6 +33,14 @@ #include #endif +#if !defined(NODEREPORT_VERSION) +#define NODEREPORT_VERSION "dev" +#endif + +#if !defined(UNKNOWN_NODEVERSION_STRING) +#define UNKNOWN_NODEVERSION_STRING "Unable to determine Node.js version\n" +#endif + #ifndef _WIN32 extern char** environ; #endif @@ -52,7 +58,7 @@ using v8::String; using v8::V8; // Internal/static function declarations -static void PrintVersionInformation(FILE* fp); +static void PrintVersionInformation(FILE* fp, Isolate* isolate); static void PrintJavaScriptStack(FILE* fp, Isolate* isolate, DumpEvent event, const char* location); static void PrintStackFromStackTrace(FILE* fp, Isolate* isolate, DumpEvent event); static void PrintStackFrame(FILE* fp, Isolate* isolate, Local frame, int index, void* pc); @@ -70,6 +76,7 @@ const char* v8_states[] = {"JS", "GC", "COMPILER", "OTHER", "EXTERNAL", "IDLE"}; static bool report_active = false; // recursion protection static char report_filename[NR_MAXNAME + 1] = ""; static char report_directory[NR_MAXPATH + 1] = ""; // defaults to current working directory +static std::string version_string = UNKNOWN_NODEVERSION_STRING; #ifdef _WIN32 static SYSTEMTIME loadtime_tm_struct; // module load time #else // UNIX, OSX @@ -189,6 +196,97 @@ unsigned int ProcessNodeReportVerboseSwitch(const char* args) { return 0; // Default is verbose mode off } +void SetVersionString(Isolate* isolate) { + // Catch anything thrown and gracefully return + Nan::TryCatch trycatch; + version_string = UNKNOWN_NODEVERSION_STRING; + + // Retrieve the process object + v8::Local process_prop; + if (!Nan::New("process").ToLocal(&process_prop)) return; + v8::Local global_obj = isolate->GetCurrentContext()->Global(); + v8::Local process_value; + if (!Nan::Get(global_obj, process_prop).ToLocal(&process_value)) return; + if (!process_value->IsObject()) return; + v8::Local process_obj = process_value.As(); + + // Get process.version + v8::Local version_prop; + if (!Nan::New("version").ToLocal(&version_prop)) return; + v8::Local version; + if (!Nan::Get(process_obj, version_prop).ToLocal(&version)) return; + + // e.g. Node.js version: v6.9.1 + if (version->IsString()) { + Nan::Utf8String node_version(version); + version_string = "Node.js version: "; + version_string += *node_version; + version_string += "\n"; + } + + // Get process.versions + v8::Local versions_prop; + if (!Nan::New("versions").ToLocal(&versions_prop)) return; + v8::Local versions_value; + if (!Nan::Get(process_obj, versions_prop).ToLocal(&versions_value)) return; + if (!versions_value->IsObject()) return; + v8::Local versions_obj = versions_value.As(); + + // Get component names and versions from process.versions + v8::Local components; + if (!Nan::GetOwnPropertyNames(versions_obj).ToLocal(&components)) return; + v8::Local components_obj = components.As(); + std::map comp_versions; + uint32_t total_components = (*components)->Length(); + for (uint32_t i = 0; i < total_components; i++) { + v8::Local name_value; + if (!Nan::Get(components_obj, i).ToLocal(&name_value)) continue; + v8::Local version_value; + if (!Nan::Get(versions_obj, name_value).ToLocal(&version_value)) continue; + + Nan::Utf8String component_name(name_value); + Nan::Utf8String component_version(version_value); + if (*component_name == nullptr || *component_version == nullptr) continue; + + // Don't duplicate the Node.js version + if (!strcmp("node", *component_name)) { + if (version_string == UNKNOWN_NODEVERSION_STRING) { + version_string = "Node.js version: v"; + version_string += *component_version; + version_string += "\n"; + } + } else { + comp_versions[*component_name] = *component_version; + } + } + + // Format sorted component versions surrounded by (), wrapped + // e.g. + // (ares: 1.10.1-DEV, http_parser: 2.7.0, icu: 57.1, modules: 48, + // openssl: 1.0.2j, uv: 1.9.1, v8: 5.1.281.84, zlib: 1.2.8) + const size_t wrap = 80; + size_t line_length = 1; + version_string += "("; + for (auto it : comp_versions) { + std::string component_name = it.first; + std::string component_version = it.second; + size_t length = component_name.length() + component_version.length() + 2; + if (line_length + length + 1 >= wrap) { + version_string += "\n "; + line_length = 1; + } + version_string += component_name; + version_string += ": "; + version_string += component_version; + line_length += length; + if (it != *std::prev(comp_versions.end())) { + version_string += ", "; + line_length += 2; + } + } + version_string += ")\n"; +} + /******************************************************************************* * Function to save the nodereport module load time value *******************************************************************************/ @@ -317,7 +415,7 @@ void TriggerNodeReport(Isolate* isolate, DumpEvent event, const char* message, c fflush(fp); // Print Node.js and OS version information - PrintVersionInformation(fp); + PrintVersionInformation(fp, isolate); fflush(fp); // Print summary JavaScript stack backtrace @@ -369,12 +467,15 @@ void TriggerNodeReport(Isolate* isolate, DumpEvent event, const char* message, c * Function to print Node.js version, OS version and machine information * ******************************************************************************/ -static void PrintVersionInformation(FILE* fp) { +static void PrintVersionInformation(FILE* fp, Isolate* isolate) { // Print Node.js and deps component versions - fprintf(fp, "\nNode.js version: %s\n", NODE_VERSION); - fprintf(fp, "(v8: %s, libuv: %s, zlib: %s, ares: %s)\n", - V8::GetVersion(), uv_version_string(), ZLIB_VERSION, ARES_VERSION_STR); + fprintf(fp, "\n%s", version_string.c_str()); + + // Print NodeReport version + // e.g. NodeReport version: 1.0.6 (built against Node.js v6.9.1) + fprintf(fp, "\nNodeReport version: %s (built against Node.js v%s)\n", + NODEREPORT_VERSION, NODE_VERSION_STRING); // Print operating system and machine information (Windows) #ifdef _WIN32 diff --git a/src/node_report.h b/src/node_report.h index 624b2b1..210669e 100644 --- a/src/node_report.h +++ b/src/node_report.h @@ -43,6 +43,7 @@ void ProcessNodeReportDirectory(const char* args); unsigned int ProcessNodeReportVerboseSwitch(const char* args); void SetLoadTime(); +void SetVersionString(Isolate* isolate); // Local implementation of secure_getenv() inline const char* secure_getenv(const char* key) { diff --git a/test/common.js b/test/common.js index e50fd33..bab9cf8 100644 --- a/test/common.js +++ b/test/common.js @@ -9,6 +9,8 @@ const REPORT_SECTIONS = [ 'System Information' ]; +const reNewline = '(?:\\r*\\n)'; + exports.findReports = (pid) => { // Default filenames are of the form NodeReport..