Repository navigation
Initial drop of nodereport project for nodejs repo - #2
Conversation
|
I'm getting this on OS X 10.10.5 and Node.js v4/v6: Also when applying this patch: |
|
As an FYI Richard is on holiday this week , so response will be delayed. |
|
@bnoordhuis, believe you looked at PR to core, so you make be able to review this as the key issues will be the same, just as an npm versus part of core. |
| "conditions": [ | ||
| ["OS=='linux'", { | ||
| "defines": [ "_GNU_SOURCE" ], | ||
| "cflags": [ "-g -O2 -std=c++11", ], |
There was a problem hiding this comment.
These should be split, not as a single string.
|
LGTM with a few nits. |
|
@mhdawson thanks for the review, I have moved the blocks of code that print version information and stack traces in node_report.cc into separate functions, and fixed the minor nits. Also added the scripts entry into package.json so uses can run "npm test", and fixed some CRLF line endings in the test code. I had not considered line-mode options (options are currently supported via env vars and/or JS API calls). A typical node command line is: We could allow nodereport options to be mixed in with either the node/v8 or the application options. Suitable unique naming would be need, e.g something like "nodereport_events=exception+signal". Application options are available via process.argv, though I am not sure how to access that from C++, otherwise I should be able to get the command line from the OS . Anyway, something for a future enhancement. |
|
Got it to build on OS X, is |
|
Should this be merged so that it can be worked on more collaboratively? |
|
@Fishrock123 yes absolutely, the report is intended to be read manually, using any text editor/notepad/email etc, and should be readily understandable to node developers, admins, testers etc Yes this is ready to go and for others to contribute. @mhdawson - not sure how this repo is set up, who has powers to merge this? thanks |
|
I think we should probably just give you perms to merge it. cc/ @nodejs/post-mortem |
|
This repo has @mhdawson and the @nodejs/post-mortem team as collaborators. @rnchamberlain isn't (to my surprise) a member of the @nodejs/post-mortem team, even though he's clearly active in that space, so I added him to that team. Once @rnchamberlain accepts the invite, he'll have the credentials to push commits to this repo. |
|
|
||
| var nodereport = require('nodereport'); | ||
|
|
||
| By default, this will trigger a NodeReport to be written to the current |
There was a problem hiding this comment.
I don't think this is a good idea. It means that there is no way to opt-out of auto-handling of unhandledException, which would be useful for someone who wanted to only use the manual .triggerReport(). I think it would make more sense for a require of nodereport to make no changes to global process state until it was attached. Syntax could be require('nodereport')(), or require('nodereport').attach(), or any other variant.
There was a problem hiding this comment.
also, I would want to control independently whether nodereport attached to SIGUSR2, or even configure the signal.
There was a problem hiding this comment.
Hi @sam-github, you can override the defaults and configure which events you want via the API, so
require("nodereport").setEvents("fatalerror+signal");
will switch off the exception handler, likewise
require("nodereport").setEvents("exception+fatalerror");
will switch off the signal handler.
require("nodereport").setSignal("SIGQUIT");
will configure SIGQUIT for the trigger signal instead of SIGUSR2, and we could add more choices for that (though I just found a bug in that code, fix on it's way).
There was a problem hiding this comment.
Perhaps an optional options arg with key events as an array of potential triggers and key sigusr2 as a boolean to enable/disable the signal would be a nice approach.
Such an arg would be reasonably extensible for other triggers too.
Also allows for clear defaults to be set early in code.
There was a problem hiding this comment.
Yes, I think that's the way to go, extra parameter(s) on the module Initialize(). There is a limitation here in the v8 APIs, in that isolate->SetFatalErrorHandler(), isolate->SetCaptureStackTraceForUncaughtExceptions() and isolate->SetAbortOnUncaughtExceptionCallback() do not have 'unset' counterparts, and they don't support chaining of the callbacks. So if the nodereport module sets those at startup, a subsequent setEvents() call to the module can only switch off what we do in our callback, the underlying change to v8/node behaviour remains in place. Using env vars gets around that in the current implementation, as they are available at module init, but they are a bit nasty. So Sam's require('nodereport')(...), suggestion, with 'at start-up' equivalents of the setEvents(), setSignal(), setDirectory etc APIs would be a better solution.
| Configuration is available via these environment variables and/or Javascript | ||
| API calls: | ||
|
|
||
| export NODEREPORT_EVENTS=exception+fatalerror+signal |
There was a problem hiding this comment.
that its possible to configure nodereport via env vars is great, that its necessary to do so is I think too much focus on policy instead of mechanism
There was a problem hiding this comment.
I'd expect the .setEvents() API to be the usual way to configure it, with the env vars as an alternative maybe for admins when changing the code is not convenient. I'll update the readme to reflect that.
Re the defaults, the design was for all the events to work 'out of the box' i.e. with just require("nodereport"). We could take a more cautious approach as you suggest, and just have
.triggerReport() available until .setEvents(list of selected events) is called.
|
I don't think we should pull from core eslint (it's a legacy mess). Just use |
|
I believe I have given everybody in the post-mortem team write access to this repo. Was just waiting for 1 more L.G.T.M from one of the other reviewers before landing. |
| } | ||
| NAN_METHOD(SetCoreDump) { | ||
| Nan::Utf8String parameter(info[0]); | ||
| nodereport_events = ProcessNodeReportCoreSwitch(*parameter); |
There was a problem hiding this comment.
I believe this is intended: s/nodereport_events/nodereport_core/
There was a problem hiding this comment.
@joshgav good spot, and same error in SetSignal method below, fix in progress
|
Status? I think I'd actually like to start using this. |
|
Fixed as discussed with @sam-github and @joshgav. So Status: as per @mhdawson above, just another LGTM then we land. Meantime available to try out now with |
|
@bnoordhuis LGTY? @rnchamberlain API LGTM. If you want to make it easy to enable all capabilities, you could implement a usage like: So a side-effectless require is possible, but all side-effects can be opted in easily, and the "module call" above would check for env vars You could also extend above with an options object rather than method calls for configuration: EDIT: just suggestions, which can be taken up in a subsequent PR if you are interested, they don't have to happen now. |
|
@sam-github I had a look at both of your suggested syntax options, but couldn't immediately work out how to code them on the C++ side! There is a mention of a two-argument form of the Init() function here: https://nodejs.org/api/addons.html, which has a module object passed in as well as the exports object? Anyway yes, potential future enhancement - thanks. |
|
|
||
| # Build directories | ||
| /build/ | ||
| /node_modules/ |
There was a problem hiding this comment.
This file uses Windows line endings for some reason.
| api.js - NodeReport triggered by Javascript API call | ||
| exception.js - NodeReport triggered by unhandled exception | ||
| fatalerror.js - NodeReport triggered by fatal error on Javascript heap out of memory | ||
| loop.js - looping application, NodeReport triggered using kill -USR2 <pid> |
There was a problem hiding this comment.
There is some trailing whitespace in this file.
| setTimeout(function() { | ||
| console.log('loop.js: timeout expired, exiting.'); | ||
| process.exit(0); | ||
| }, 60000); |
|
|
||
| if (info[0]->IsString()) { | ||
| // Filename parameter supplied | ||
| Nan::Utf8String filename_parameter(info[0]->ToString()); |
There was a problem hiding this comment.
You don't have to ToString() the argument to Nan::Utf8String.
| if (filename_parameter.length() < NR_MAXNAME) { | ||
| snprintf(filename, sizeof(filename), "%s", *filename_parameter); | ||
| } else { | ||
| Nan::ThrowSyntaxError("nodereport: filename parameter is too long"); |
There was a problem hiding this comment.
SyntaxError is kind of weird to throw for a bad argument.
| break; | ||
| case kFatalError: | ||
| #if NODE_VERSION_AT_LEAST(6, 0, 0) | ||
| if (!strncmp(location,"MarkCompactCollector", sizeof("MarkCompactCollector") - 1)) { |
| // Walk the frames printing symbolic information if available | ||
| for (int i = 0; i < numberOfFrames; i++) { | ||
| DWORD64 dwOffset64 = 0; | ||
| DWORD64 dwAddress = (DWORD64)(frames[i]); |
| if (SymFromAddr(hProcess, dwAddress, &dwOffset64, pSymbol)) { | ||
| DWORD dwOffset = 0; | ||
| IMAGEHLP_LINE64 line; | ||
| line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); |
There was a problem hiding this comment.
There was a problem hiding this comment.
Right, but that doesn't preclude sizeof(line), does it?
There was a problem hiding this comment.
Either sizeof(type name) or sizeof(variable name) work OK I believe, the MSDN examples uses sizeof(type name). Is sizeof(variable name) preferred?
There was a problem hiding this comment.
It is in the node core code base so you may want to follow that here. The reasoning is that sizeof(var) won't break when the type of var changes.
| lpvEnv = GetEnvironmentStrings(); | ||
| if (lpvEnv != NULL) { | ||
| // Variable strings are separated by NULL byte, and the block is terminated by a NULL byte. | ||
| lpszVariable = (LPTSTR) lpvEnv; |
| #endif // !__GLIBC_PREREQ(2, 17) | ||
| #else | ||
| #define secure_getenv getenv | ||
| #endif // defined(__GLIBC__) |
There was a problem hiding this comment.
Potential downside is that a .node compiled against glibc 2.17 won't work with e.g. glibc 2.15. That is, you won't be able to simply copy the shared object around.
There was a problem hiding this comment.
I wonder if that's a common thing to do, copy binaries around from an npm install. Someone is bound to do it I suppose, and they will get an unresolved symbol at load time. Under consideration!
I think I have fixed everything else, see commits below, and thanks for the review.
There was a problem hiding this comment.
Its a nice to have to be able to build on one system, and run on another slightly different one. It fails often enough that its usually necessary to build on a system of identical os/etc level and architecture as the deployment/production system.
There was a problem hiding this comment.
OK, glibc 2.17 is fairly recent: https://sourceware.org/glibc/wiki/Glibc%20Timeline. I'll do it the node.cc way and have a local implementation of secure_getenv().
|
Looking back we have an LGTM and an API LGTM on this, I'll merge shortly unless anyone objects. Thanks. |
Implementation of native NPM module for diagnostic report triggered on exception and fatal error events, signals and JavaScript API. Supports Node v4 and v6, Linux, Mac and Windows. Includes testcases and demo samples.