Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChengzhong Wu <chengzhong.wcz@alibaba-inc.com>2022-08-24 20:02:26 +0300
committerJuan José Arboleda <soyjuanarbol@gmail.com>2022-10-11 22:45:21 +0300
commit381e11e18e20e7d10ce29c019df28573cc4594fc (patch)
treeca1bc3e44edf979c234ab029e848734c3f054d75 /src
parentb53ea08d7b07a5b8a84d8e9da2d199dfa253a65b (diff)
report: expose report public native apis
Allows APM vendors to generate a diagnostic report without calling into JavaScript. Like, from their own message channels interrupting the isolate and generating a report on demand. PR-URL: https://github.com/nodejs/node/pull/44255 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/node.h30
-rw-r--r--src/node_errors.cc17
-rw-r--r--src/node_report.cc243
-rw-r--r--src/node_report.h16
-rw-r--r--src/node_report_module.cc6
5 files changed, 172 insertions, 140 deletions
diff --git a/src/node.h b/src/node.h
index 4be002ac18f..b787a474888 100644
--- a/src/node.h
+++ b/src/node.h
@@ -75,8 +75,9 @@
#include "v8-platform.h" // NOLINT(build/include_order)
#include "node_version.h" // NODE_MODULE_VERSION
-#include <memory>
#include <functional>
+#include <memory>
+#include <ostream>
// We cannot use __POSIX__ in this header because that's only defined when
// building Node.js.
@@ -528,6 +529,33 @@ NODE_EXTERN v8::MaybeLocal<v8::Value> PrepareStackTraceCallback(
v8::Local<v8::Value> exception,
v8::Local<v8::Array> trace);
+// Writes a diagnostic report to a file. If filename is not provided, the
+// default filename includes the date, time, PID, and a sequence number.
+// The report's JavaScript stack trace is taken from err, if present.
+// If isolate is nullptr, no information about the JavaScript environment
+// is included in the report.
+// Returns the filename of the written report.
+NODE_EXTERN std::string TriggerNodeReport(v8::Isolate* isolate,
+ const char* message,
+ const char* trigger,
+ const std::string& filename,
+ v8::Local<v8::Value> error);
+NODE_EXTERN std::string TriggerNodeReport(Environment* env,
+ const char* message,
+ const char* trigger,
+ const std::string& filename,
+ v8::Local<v8::Value> error);
+NODE_EXTERN void GetNodeReport(v8::Isolate* isolate,
+ const char* message,
+ const char* trigger,
+ v8::Local<v8::Value> error,
+ std::ostream& out);
+NODE_EXTERN void GetNodeReport(Environment* env,
+ const char* message,
+ const char* trigger,
+ v8::Local<v8::Value> error,
+ std::ostream& out);
+
// This returns the MultiIsolatePlatform used for an Environment or IsolateData
// instance, if one exists.
NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env);
diff --git a/src/node_errors.cc b/src/node_errors.cc
index b464a37e378..bfc93ec70d2 100644
--- a/src/node_errors.cc
+++ b/src/node_errors.cc
@@ -411,8 +411,7 @@ static void ReportFatalException(Environment* env,
}
if (env->isolate_data()->options()->report_uncaught_exception) {
- report::TriggerNodeReport(
- isolate, env, report_message.c_str(), "Exception", "", error);
+ TriggerNodeReport(env, report_message.c_str(), "Exception", "", error);
}
if (env->options()->trace_uncaught) {
@@ -440,10 +439,6 @@ void OnFatalError(const char* location, const char* message) {
}
Isolate* isolate = Isolate::TryGetCurrent();
- Environment* env = nullptr;
- if (isolate != nullptr) {
- env = Environment::GetCurrent(isolate);
- }
bool report_on_fatalerror;
{
Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
@@ -451,8 +446,7 @@ void OnFatalError(const char* location, const char* message) {
}
if (report_on_fatalerror) {
- report::TriggerNodeReport(
- isolate, env, message, "FatalError", "", Local<Object>());
+ TriggerNodeReport(isolate, message, "FatalError", "", Local<Object>());
}
fflush(stderr);
@@ -470,10 +464,6 @@ void OOMErrorHandler(const char* location, bool is_heap_oom) {
}
Isolate* isolate = Isolate::TryGetCurrent();
- Environment* env = nullptr;
- if (isolate != nullptr) {
- env = Environment::GetCurrent(isolate);
- }
bool report_on_fatalerror;
{
Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
@@ -481,8 +471,7 @@ void OOMErrorHandler(const char* location, bool is_heap_oom) {
}
if (report_on_fatalerror) {
- report::TriggerNodeReport(
- isolate, env, message, "OOMError", "", Local<Object>());
+ TriggerNodeReport(isolate, message, "OOMError", "", Local<Object>());
}
fflush(stderr);
diff --git a/src/node_report.cc b/src/node_report.cc
index 446b88303d8..3970f4ec531 100644
--- a/src/node_report.cc
+++ b/src/node_report.cc
@@ -1,8 +1,8 @@
-#include "env-inl.h"
-#include "json_utils.h"
#include "node_report.h"
#include "debug_utils-inl.h"
#include "diagnosticfilename-inl.h"
+#include "env-inl.h"
+#include "json_utils.h"
#include "node_internals.h"
#include "node_metadata.h"
#include "node_mutex.h"
@@ -29,8 +29,6 @@ constexpr double SEC_PER_MICROS = 1e-6;
constexpr int MAX_FRAME_COUNT = 10;
namespace node {
-namespace report {
-
using node::worker::Worker;
using v8::Array;
using v8::Context;
@@ -53,6 +51,7 @@ using v8::TryCatch;
using v8::V8;
using v8::Value;
+namespace report {
// Internal/static function declarations
static void WriteNodeReport(Isolate* isolate,
Environment* env,
@@ -83,102 +82,6 @@ static void PrintRelease(JSONWriter* writer);
static void PrintCpuInfo(JSONWriter* writer);
static void PrintNetworkInterfaceInfo(JSONWriter* writer);
-// External function to trigger a report, writing to file.
-std::string TriggerNodeReport(Isolate* isolate,
- Environment* env,
- const char* message,
- const char* trigger,
- const std::string& name,
- Local<Value> error) {
- std::string filename;
-
- // Determine the required report filename. In order of priority:
- // 1) supplied on API 2) configured on startup 3) default generated
- if (!name.empty()) {
- // Filename was specified as API parameter.
- filename = name;
- } else {
- std::string report_filename;
- {
- Mutex::ScopedLock lock(per_process::cli_options_mutex);
- report_filename = per_process::cli_options->report_filename;
- }
- if (report_filename.length() > 0) {
- // File name was supplied via start-up option.
- filename = report_filename;
- } else {
- filename = *DiagnosticFilename(env != nullptr ? env->thread_id() : 0,
- "report", "json");
- }
- }
-
- // Open the report file stream for writing. Supports stdout/err,
- // user-specified or (default) generated name
- std::ofstream outfile;
- std::ostream* outstream;
- if (filename == "stdout") {
- outstream = &std::cout;
- } else if (filename == "stderr") {
- outstream = &std::cerr;
- } else {
- std::string report_directory;
- {
- Mutex::ScopedLock lock(per_process::cli_options_mutex);
- report_directory = per_process::cli_options->report_directory;
- }
- // Regular file. Append filename to directory path if one was specified
- if (report_directory.length() > 0) {
- std::string pathname = report_directory;
- pathname += kPathSeparator;
- pathname += filename;
- outfile.open(pathname, std::ios::out | std::ios::binary);
- } else {
- outfile.open(filename, std::ios::out | std::ios::binary);
- }
- // Check for errors on the file open
- if (!outfile.is_open()) {
- std::cerr << "\nFailed to open Node.js report file: " << filename;
-
- if (report_directory.length() > 0)
- std::cerr << " directory: " << report_directory;
-
- std::cerr << " (errno: " << errno << ")" << std::endl;
- return "";
- }
- outstream = &outfile;
- std::cerr << "\nWriting Node.js report to file: " << filename;
- }
-
- bool compact;
- {
- Mutex::ScopedLock lock(per_process::cli_options_mutex);
- compact = per_process::cli_options->report_compact;
- }
- WriteNodeReport(isolate, env, message, trigger, filename, *outstream,
- error, compact);
-
- // Do not close stdout/stderr, only close files we opened.
- if (outfile.is_open()) {
- outfile.close();
- }
-
- // Do not mix JSON and free-form text on stderr.
- if (filename != "stderr") {
- std::cerr << "\nNode.js report completed" << std::endl;
- }
- return filename;
-}
-
-// External function to trigger a report, writing to a supplied stream.
-void GetNodeReport(Isolate* isolate,
- Environment* env,
- const char* message,
- const char* trigger,
- Local<Value> error,
- std::ostream& out) {
- WriteNodeReport(isolate, env, message, trigger, "", out, error, false);
-}
-
// Internal function to coordinate and write the various
// sections of the report to the supplied stream
static void WriteNodeReport(Isolate* isolate,
@@ -319,12 +222,8 @@ static void WriteNodeReport(Isolate* isolate,
expected_results += w->RequestInterrupt([&](Environment* env) {
std::ostringstream os;
- GetNodeReport(env->isolate(),
- env,
- "Worker thread subreport",
- trigger,
- Local<Value>(),
- os);
+ GetNodeReport(
+ env, "Worker thread subreport", trigger, Local<Value>(), os);
Mutex::ScopedLock lock(workers_mutex);
worker_infos.emplace_back(os.str());
@@ -884,4 +783,136 @@ static void PrintRelease(JSONWriter* writer) {
}
} // namespace report
+
+// External function to trigger a report, writing to file.
+std::string TriggerNodeReport(Isolate* isolate,
+ const char* message,
+ const char* trigger,
+ const std::string& name,
+ Local<Value> error) {
+ Environment* env = nullptr;
+ if (isolate != nullptr) {
+ env = Environment::GetCurrent(isolate);
+ }
+ return TriggerNodeReport(env, message, trigger, name, error);
+}
+
+// External function to trigger a report, writing to file.
+std::string TriggerNodeReport(Environment* env,
+ const char* message,
+ const char* trigger,
+ const std::string& name,
+ Local<Value> error) {
+ std::string filename;
+
+ // Determine the required report filename. In order of priority:
+ // 1) supplied on API 2) configured on startup 3) default generated
+ if (!name.empty()) {
+ // Filename was specified as API parameter.
+ filename = name;
+ } else {
+ std::string report_filename;
+ {
+ Mutex::ScopedLock lock(per_process::cli_options_mutex);
+ report_filename = per_process::cli_options->report_filename;
+ }
+ if (report_filename.length() > 0) {
+ // File name was supplied via start-up option.
+ filename = report_filename;
+ } else {
+ filename = *DiagnosticFilename(
+ env != nullptr ? env->thread_id() : 0, "report", "json");
+ }
+ }
+
+ // Open the report file stream for writing. Supports stdout/err,
+ // user-specified or (default) generated name
+ std::ofstream outfile;
+ std::ostream* outstream;
+ if (filename == "stdout") {
+ outstream = &std::cout;
+ } else if (filename == "stderr") {
+ outstream = &std::cerr;
+ } else {
+ std::string report_directory;
+ {
+ Mutex::ScopedLock lock(per_process::cli_options_mutex);
+ report_directory = per_process::cli_options->report_directory;
+ }
+ // Regular file. Append filename to directory path if one was specified
+ if (report_directory.length() > 0) {
+ std::string pathname = report_directory;
+ pathname += kPathSeparator;
+ pathname += filename;
+ outfile.open(pathname, std::ios::out | std::ios::binary);
+ } else {
+ outfile.open(filename, std::ios::out | std::ios::binary);
+ }
+ // Check for errors on the file open
+ if (!outfile.is_open()) {
+ std::cerr << "\nFailed to open Node.js report file: " << filename;
+
+ if (report_directory.length() > 0)
+ std::cerr << " directory: " << report_directory;
+
+ std::cerr << " (errno: " << errno << ")" << std::endl;
+ return "";
+ }
+ outstream = &outfile;
+ std::cerr << "\nWriting Node.js report to file: " << filename;
+ }
+
+ bool compact;
+ {
+ Mutex::ScopedLock lock(per_process::cli_options_mutex);
+ compact = per_process::cli_options->report_compact;
+ }
+
+ Isolate* isolate = nullptr;
+ if (env != nullptr) {
+ isolate = env->isolate();
+ }
+ report::WriteNodeReport(
+ isolate, env, message, trigger, filename, *outstream, error, compact);
+
+ // Do not close stdout/stderr, only close files we opened.
+ if (outfile.is_open()) {
+ outfile.close();
+ }
+
+ // Do not mix JSON and free-form text on stderr.
+ if (filename != "stderr") {
+ std::cerr << "\nNode.js report completed" << std::endl;
+ }
+ return filename;
+}
+
+// External function to trigger a report, writing to a supplied stream.
+void GetNodeReport(Isolate* isolate,
+ const char* message,
+ const char* trigger,
+ Local<Value> error,
+ std::ostream& out) {
+ Environment* env = nullptr;
+ if (isolate != nullptr) {
+ env = Environment::GetCurrent(isolate);
+ }
+ report::WriteNodeReport(
+ isolate, env, message, trigger, "", out, error, false);
+}
+
+// External function to trigger a report, writing to a supplied stream.
+void GetNodeReport(Environment* env,
+ const char* message,
+ const char* trigger,
+ Local<Value> error,
+ std::ostream& out) {
+ Isolate* isolate = nullptr;
+ if (env != nullptr) {
+ isolate = env->isolate();
+ }
+ report::WriteNodeReport(
+ isolate, env, message, trigger, "", out, error, false);
+}
+
} // namespace node
diff --git a/src/node_report.h b/src/node_report.h
index dde48f14ec0..7a2e817ac82 100644
--- a/src/node_report.h
+++ b/src/node_report.h
@@ -14,24 +14,10 @@
#endif
#include <iomanip>
+#include <sstream>
namespace node {
namespace report {
-
-// Function declarations - functions in src/node_report.cc
-std::string TriggerNodeReport(v8::Isolate* isolate,
- Environment* env,
- const char* message,
- const char* trigger,
- const std::string& name,
- v8::Local<v8::Value> error);
-void GetNodeReport(v8::Isolate* isolate,
- Environment* env,
- const char* message,
- const char* trigger,
- v8::Local<v8::Value> error,
- std::ostream& out);
-
// Function declarations - utility functions in src/node_report_utils.cc
void WalkHandle(uv_handle_t* h, void* arg);
diff --git a/src/node_report_module.cc b/src/node_report_module.cc
index b720ef33281..36db9add273 100644
--- a/src/node_report_module.cc
+++ b/src/node_report_module.cc
@@ -47,8 +47,7 @@ void WriteReport(const FunctionCallbackInfo<Value>& info) {
else
error = Local<Value>();
- filename = TriggerNodeReport(
- isolate, env, *message, *trigger, filename, error);
+ filename = TriggerNodeReport(env, *message, *trigger, filename, error);
// Return value is the report filename
info.GetReturnValue().Set(
String::NewFromUtf8(isolate, filename.c_str()).ToLocalChecked());
@@ -68,8 +67,7 @@ void GetReport(const FunctionCallbackInfo<Value>& info) {
else
error = Local<Object>();
- GetNodeReport(
- isolate, env, "JavaScript API", __func__, error, out);
+ GetNodeReport(env, "JavaScript API", __func__, error, out);
// Return value is the contents of a report as a string.
info.GetReturnValue().Set(