Comparing version 0.8.4 to 0.9.0
107
index.js
@@ -8,3 +8,2 @@ 'use strict'; | ||
HttpsServer, | ||
child_process, | ||
cluster, | ||
@@ -34,11 +33,2 @@ path, | ||
function setPrototypeOf(obj, proto) { | ||
if (Object.setPrototypeOf) { | ||
return Object.setPrototypeOf(obj, proto); | ||
} else { | ||
obj.__proto__ = proto; | ||
return obj; | ||
} | ||
} | ||
var log = (function () { | ||
@@ -84,3 +74,4 @@ var util; | ||
var hook = async_hooks.createHook({ | ||
init: _getRefSymbol | ||
init: _getRefSymbol, | ||
destroy: _noop // node 16.2.0+ crashes without this | ||
}); | ||
@@ -121,9 +112,56 @@ hook.enable(); | ||
(function () { | ||
var hooked = function (_, stack) { return stack; }; | ||
var getStackFrames = function (_, stack) { return stack; }; | ||
var getMappedStackFrames = function (_, stack) { | ||
// attempt to use source-map-support to process any source map info | ||
// This is copy-pasted from part of source-map-support's implementation | ||
// of prepareStackTrace. We're interested in the data, which we filter | ||
// for the first/likely relevant call site. We don't want to un-stringify | ||
// and parse the (string) return value of prepareStackTrace itself. | ||
var state = { nextPosition: null, curPosition: null }; | ||
for (var i = stack.length - 1; i >= 0; i--) { | ||
stack[i] = sms.wrapCallSite(stack[i], state); | ||
state.nextPosition = state.curPosition; | ||
} | ||
state.curPosition = state.nextPosition = null; | ||
return stack; | ||
} | ||
var sms = null; | ||
// we don't want to load any modules until we've hooked everything | ||
// this function defers loading `source-map-support`, and also tests | ||
// that it functions as expected. since we don't directly depend on | ||
// that module, it could have any version and the api could break in | ||
// the future. if that happens, we just behave as though it wasn't | ||
// present, and the user's code will continue to be mapped -- only | ||
// wtfnode source line attribution will not be. | ||
function loadSMS() { | ||
if (sms !== null) { return; } | ||
var _Error_prepareStackTrace = Error.prepareStackTrace; | ||
try { | ||
sms = require('source-map-support'); | ||
Error.prepareStackTrace = getMappedStackFrames; | ||
(new Error('synthetic')).stack; | ||
Error.prepareStackTrace = _Error_prepareStackTrace; | ||
getStackFrames = getMappedStackFrames; | ||
return; | ||
} catch (e) { | ||
Error.prepareStackTrace = _Error_prepareStackTrace; | ||
sms = false; | ||
log('warn', 'error getting source-mapped stack -- did the api change?'); | ||
} | ||
} | ||
function getStack() { | ||
loadSMS(); | ||
// capture whatever the current prepareStackTrace is when we call this function... | ||
var _Error_prepareStackTrace = Error.prepareStackTrace; | ||
Error.prepareStackTrace = hooked; | ||
var err = new Error(); | ||
var stack = err.stack.map(function (item) { | ||
Error.prepareStackTrace = getStackFrames; | ||
var unprocessedStack = (new Error('synthetic')).stack; | ||
// set it back ASAP so any failures are handled normally | ||
Error.prepareStackTrace = _Error_prepareStackTrace; | ||
return unprocessedStack.map(function (item) { | ||
if (item.isEval()) { | ||
@@ -143,4 +181,2 @@ var matched = item.getEvalOrigin().match(/\((.*):(\d*):(\d*)\)/) || {}; | ||
}); | ||
Error.prepareStackTrace = _Error_prepareStackTrace; | ||
return stack; | ||
} | ||
@@ -161,3 +197,3 @@ | ||
) { | ||
return stack[i]; | ||
return stack[i]; | ||
} | ||
@@ -374,22 +410,20 @@ } | ||
var worker = _cluster_fork.apply(this, arguments); | ||
// we get an open handle for a pipe, but no reference to the | ||
// worker itself, so we add one, as well as the call site info | ||
if (worker && worker.process) { | ||
var channel = worker.process.channel || worker.process._channel; | ||
if (!channel.hasOwnProperty('__callSite')) { | ||
Object.defineProperties(worker.process._channel, { | ||
__callSite: { | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
value: findCallsite(getStack()) | ||
}, | ||
__worker: { | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
value: worker | ||
} | ||
}); | ||
} | ||
if (worker && worker.process && worker.process._channel) { | ||
Object.defineProperties(worker.process._channel, { | ||
__callSite: { | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
value: findCallsite(getStack()) | ||
}, | ||
__worker: { | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
value: worker | ||
} | ||
}); | ||
} | ||
@@ -410,3 +444,2 @@ | ||
var count = 0; | ||
function getCallsite(thing) { | ||
@@ -413,0 +446,0 @@ if (!thing.__callSite) { |
{ | ||
"name": "wtfnode", | ||
"version": "0.8.4", | ||
"version": "0.9.0", | ||
"description": "Utility to help find out why Node isn't exiting", | ||
@@ -16,3 +16,3 @@ "repository": { | ||
"scripts": { | ||
"test": "(cd tests && node test && node test-eval && node test-promise && node test-promisify && node test-logging && node test-once-flowing && node test-issue-37.js)", | ||
"test": "(cd tests && node test && node test-eval && node test-promise && node test-promisify && node test-logging && node test-once-flowing && node test-issue-37.js && node test-no-source-map-support && node test-broken-source-map-support)", | ||
"test-sourcemaps": "(cd tests && coffee --map --compile test-sourcemaps.coffee && node test-sourcemaps.js || exit 0)", | ||
@@ -26,6 +26,6 @@ "kitchensink": "(cd tests && node kitchensink)" | ||
"license": "ISC", | ||
"devDependencies": { | ||
"coffee-script": "^1.12.7", | ||
"source-map-support": "^0.5.3" | ||
"dependencies": { | ||
"coffeescript": "^2.5.1", | ||
"source-map-support": "^0.5.19" | ||
} | ||
} |
# What? | ||
This package came out of frustration with trying to track down the cause of stalled node applications. Node exposes process._getActiveHandles(), which is kind of useful except it's hard to tell what is *actually* going on from just those results. This module breaks it down into something a little simpler, with useful information to help you track down what's really keeping your program open. | ||
This package came out of frustration with trying to track down the cause of stalled node applications. Node exposes process.\_getActiveHandles(), which is kind of useful except it's hard to tell what is _actually_ going on from just those results. This module breaks it down into something a little simpler, with useful information to help you track down what's really keeping your program open. | ||
# Sample output | ||
[i] app/24191 on devbox: Server listening on 0.0.0.0:9001 in development mode | ||
^C[WTF Node?] open handles: | ||
- Sockets: | ||
- 10.21.1.16:37696 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37697 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37698 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37699 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37700 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- Servers: | ||
- 0.0.0.0:9001 | ||
- Listeners: | ||
- connection: connectionListener @ /home/me/app/app-framework/lib/listener.js:13 | ||
- Timers: | ||
- (10000 ~ 10 s) wrapper @ /home/me/app/node_modules/knex/node_modules/pool2/lib/pool.js:80 | ||
- (300000 ~ 5 min) wrapper @ /home/me/app/services/foo.service.js:61 | ||
[i] app/24191 on devbox: Server listening on 0.0.0.0:9001 in development mode | ||
^C[WTF Node?] open handles: | ||
- Sockets: | ||
- 10.21.1.16:37696 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37697 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37698 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37699 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- 10.21.1.16:37700 -> 10.21.2.213:5432 | ||
- Listeners: | ||
- connect: anonymous @ /home/me/app/node_modules/pg/lib/connection.js:49 | ||
- Servers: | ||
- 0.0.0.0:9001 | ||
- Listeners: | ||
- connection: connectionListener @ /home/me/app/app-framework/lib/listener.js:13 | ||
- Timers: | ||
- (10000 ~ 10 s) wrapper @ /home/me/app/node_modules/knex/node_modules/pool2/lib/pool.js:80 | ||
- (300000 ~ 5 min) wrapper @ /home/me/app/services/foo.service.js:61 | ||
@@ -36,5 +36,7 @@ # Notes | ||
## Timers named "wrapper" | ||
You'll see that the function name listed under timers is `wrapper` -- this is the wrapper around interval timers as created by setInterval. I can still get a source line, but I can't get the original function name out, unfortunately. Caveats like this may exist in other places, too. | ||
## "IPC channel to parent" | ||
When using child_process.fork, or child_process.spawn with default stdio configuration (or possibly when your program is run by something else, such as PM2), an inter-process communication (IPC) channel is opened to send messages between the parent and child. Since this is not based on any code the current program has executed, I can't get much more information than that. It means that the parent end of the connection is still open, so you'll want to investigate whatever spawned the process you're seeing this from. | ||
@@ -63,2 +65,3 @@ | ||
## Configuring logging | ||
`wtfnode` uses three logging levels, which default to `console.log`, `console.warn`, and `console.error`. The output is sent to `console.log`; warnings about potential problems when calculating the output are sent to `console.warn`; `console.error` is currently only used to print CLI usage info. | ||
@@ -69,2 +72,3 @@ | ||
Usage: | ||
```js | ||
@@ -84,3 +88,3 @@ var wtf = require('wtfnode'); | ||
It currently does something useful under Node 0.10 through 8.6. If it stops doing something useful in the future, please post an issue, preferably with a reproducible test script and detailed version information, and I'll try and make it work properly again. | ||
It currently does something useful under Node 0.10 through 16.3.0. If it stops doing something useful in the future, please post an issue, preferably with a reproducible test script and detailed version information, and I'll try and make it work properly again. | ||
@@ -87,0 +91,0 @@ # Testing |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
34671
0
698
90
2
+ Addedcoffeescript@^2.5.1
+ Addedsource-map-support@^0.5.19
+ Addedbuffer-from@1.1.2(transitive)
+ Addedcoffeescript@2.7.0(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedsource-map-support@0.5.21(transitive)