Comparing version 0.9.4 to 0.10.0
152
index.js
@@ -26,2 +26,4 @@ 'use strict'; | ||
var dumpOptions = {}; | ||
function timerCallback(thing) { | ||
@@ -179,3 +181,4 @@ if (typeof thing._repeat === 'function') { return '_repeat'; } | ||
file: item.getFileName(), | ||
line: item.getLineNumber() | ||
line: item.getLineNumber(), | ||
column: item.getColumnNumber() | ||
}; | ||
@@ -312,3 +315,10 @@ }); | ||
if (callSite && !this.hasOwnProperty('__callSite')) { | ||
var stack = getStack(); | ||
Object.defineProperties(this, { | ||
__fullStack: { | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
value: stack | ||
}, | ||
__callSite: { | ||
@@ -318,3 +328,3 @@ enumerable: false, | ||
writable: false, | ||
value: findCallsite(getStack()) | ||
value: findCallsite(stack) | ||
} | ||
@@ -350,3 +360,5 @@ }); | ||
var callSite = wrapFn(args[1], args[1].name, null).__callSite; | ||
var wrapped = wrapFn(args[1], args[1].name, null); | ||
var fullStack = wrapped.__fullStack; | ||
var callSite = wrapped.__callSite; | ||
@@ -365,2 +377,10 @@ var res = addListener(this, origMethod, type, fn); | ||
Object.defineProperties(listener, { | ||
__fullStack: { | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
value: fullStack | ||
} | ||
}); | ||
Object.defineProperties(listener, { | ||
__callSite: { | ||
@@ -418,3 +438,10 @@ enumerable: false, | ||
if (worker && worker.process && worker.process._channel) { | ||
var fullStack = getStack(); | ||
Object.defineProperties(worker.process._channel, { | ||
__fullStack: { | ||
enumerable: false, | ||
configurable: false, | ||
writable: false, | ||
value: fullStack | ||
}, | ||
__callSite: { | ||
@@ -424,3 +451,3 @@ enumerable: false, | ||
writable: false, | ||
value: findCallsite(getStack()) | ||
value: findCallsite(fullStack) | ||
}, | ||
@@ -445,5 +472,5 @@ __worker: { | ||
while (i < units.length && t / units[i] > 1) { t /= units[i++]; } | ||
return Math.floor(t) + ' ' + labels[i-1]; | ||
}; | ||
while (i < units.length && t / units[i] >= 1) { t /= units[i++]; } | ||
return (Math.round(t*10)/10) + ' ' + labels[i-1]; | ||
} | ||
@@ -459,4 +486,23 @@ function getCallsite(thing) { | ||
return thing.__callSite; | ||
}; | ||
} | ||
function getRenderedStack(thing, level) { | ||
if (!thing.__fullStack) { | ||
return ''; | ||
} | ||
var head = '\n'; | ||
while (level--) { | ||
head += ' '; | ||
} | ||
var stack = ''; | ||
for (var i = 0; i < thing.__fullStack.length; ++i) { | ||
var frame = thing.__fullStack[i]; | ||
if (frame.file === __filename) { | ||
continue; | ||
} | ||
stack += head + 'at ' + (frame.name || '(anonymous)') + ' (' + (frame.file || 'internal') + (frame.line != null ? ':' + frame.line + (frame.column != null ? ':' + frame.column : '') : '') + ')'; | ||
} | ||
return stack; | ||
} | ||
function getProtocol(req, socket) { | ||
@@ -499,3 +545,4 @@ if (typeof req.protocol === 'string') return req.protocol; | ||
function dump() { | ||
function dump(options) { | ||
options = options || {nopts: true}; | ||
log('info', '[WTF Node?] open handles:'); | ||
@@ -550,3 +597,9 @@ | ||
var callSite = getCallsite(fn); | ||
log('info', ' - %s: %s @ %s:%d', 'keypress', fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
var stack; | ||
if (options.fullStacks && (stack = getRenderedStack(fn, 4))) { | ||
log('info', ' - %s: %s%s', 'keypress', fn.name || fn.__name || callSite.name || '(anonymous)', stack); | ||
} else { | ||
log('info', ' - %s: %s @ %s:%d', 'keypress', fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
} | ||
}); | ||
@@ -573,3 +626,8 @@ } | ||
var callSite = getCallsite(cp); | ||
log('info', ' - Entry point: %s:%d', callSite.file, callSite.line); | ||
var stack; | ||
if (options.fullStacks && (stack = getRenderedStack(cp, 3))) { | ||
log('info', ' - Entry point: %s', stack); | ||
} else { | ||
log('info', ' - Entry point: %s:%d', callSite.file, callSite.line); | ||
} | ||
} | ||
@@ -597,3 +655,8 @@ if (cp.stdio && cp.stdio.length) { | ||
var callSite = getCallsite(cw); | ||
log('info', ' - Entry point: %s:%d', callSite.file, callSite.line); | ||
var stack; | ||
if (options.fullStacks && (stack = getRenderedStack(cw, 3))) { | ||
log('info', ' - Entry point: %s', stack); | ||
} else { | ||
log('info', ' - Entry point: %s:%d', callSite.file, callSite.line); | ||
} | ||
}); | ||
@@ -623,3 +686,8 @@ } | ||
var callSite = getCallsite(fn); | ||
log('info', ' - %s: %s @ %s:%d', 'connect', fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
var stack; | ||
if (options.fullStacks && (stack = getRenderedStack(fn, 4))) { | ||
log('info', ' - %s: %s%s', 'connect', fn.name || fn.__name || callSite.name || '(anonymous)', stack); | ||
} else { | ||
log('info', ' - %s: %s @ %s:%d', 'connect', fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
} | ||
}); | ||
@@ -674,3 +742,8 @@ } | ||
var callSite = getCallsite(fn); | ||
log('info', ' - %s: %s @ %s:%d', eventType, fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
var stack; | ||
if (options.fullStacks && (stack = getRenderedStack(fn, 4))) { | ||
log('info', ' - %s: %s%s', eventType, fn.name || fn.__name || callSite.name || '(anonymous)', stack); | ||
} else { | ||
log('info', ' - %s: %s @ %s:%d', eventType, fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
} | ||
}); | ||
@@ -735,6 +808,10 @@ } | ||
timers.forEach(function (t) { | ||
var fn = t[timerCallback(t)], | ||
callSite = getCallsite(fn); | ||
log('info', ' - (%d ~ %s) %s @ %s:%d', t._idleTimeout, formatTime(t._idleTimeout), fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
var fn = t[timerCallback(t)]; | ||
var callSite = getCallsite(fn); | ||
var stack; | ||
if (options.fullStacks && (stack = getRenderedStack(fn, 2))) { | ||
log('info', ' - (%d ~ %s) %s%s', t._idleTimeout, formatTime(t._idleTimeout), fn.name || fn.__name || callSite.name || '(anonymous)', stack); | ||
} else { | ||
log('info', ' - (%d ~ %s) %s @ %s:%d', t._idleTimeout, formatTime(t._idleTimeout), fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
} | ||
}); | ||
@@ -747,6 +824,10 @@ } | ||
intervals.forEach(function (t) { | ||
var fn = t[timerCallback(t)], | ||
callSite = getCallsite(fn); | ||
log('info', ' - (%d ~ %s) %s @ %s:%d', t._idleTimeout, formatTime(t._idleTimeout), fn.name || fn.__name || callSite.name, callSite.file, callSite.line); | ||
var fn = t[timerCallback(t)]; | ||
var callSite = getCallsite(fn); | ||
var stack; | ||
if (options.fullStacks && (stack = getRenderedStack(fn, 2))) { | ||
log('info', ' - (%d ~ %s) %s%s', t._idleTimeout, formatTime(t._idleTimeout), fn.name || fn.__name || callSite.name || '(anonymous)', stack); | ||
} else { | ||
log('info', ' - (%d ~ %s) %s @ %s:%d', t._idleTimeout, formatTime(t._idleTimeout), fn.name || fn.__name || callSite.name || '(anonymous)', callSite.file, callSite.line); | ||
} | ||
}); | ||
@@ -777,3 +858,3 @@ } | ||
process.nextTick(function () { | ||
try { dump(); } | ||
try { dump(dumpOptions); } | ||
catch (e) { log('error', e); } | ||
@@ -797,8 +878,21 @@ process.exit(); | ||
if (process.argv.length < 3) { | ||
log('error', 'Usage: wtfnode <yourscript> <yourargs> ...'); | ||
log('error', 'Usage: wtfnode [--fullstacks] <yourscript> <yourargs> ...'); | ||
process.exit(1); | ||
} | ||
var moduleParams = process.argv.slice(3); | ||
var modulePath = path.resolve(process.cwd(), process.argv[2]); | ||
return [].concat(process.argv[0], modulePath, moduleParams); | ||
var offset = 0; | ||
// Very poor-man's argument parsing. | ||
// Could be extended to more options using something like process.argv.indexOf(), | ||
// but care should be taken that we're not mistaking arguments meant for the child module as arguments meant for wtfnode. | ||
var fullStacks = process.argv[2] === '--fullstacks'; | ||
if (fullStacks) { | ||
++offset; | ||
} | ||
var moduleParams = process.argv.slice(3 + offset); | ||
var modulePath = path.resolve(process.cwd(), process.argv[2 + offset]); | ||
return { | ||
newArgV: [].concat(process.argv[0], modulePath, moduleParams), | ||
options: { | ||
fullStacks: fullStacks, | ||
} | ||
}; | ||
} | ||
@@ -812,3 +906,5 @@ | ||
// the module that it is the 'main' module. | ||
var newArgv = parseArgs(process.argv); | ||
var parsedArgs = parseArgs(process.argv); | ||
var newArgv = parsedArgs.newArgV; | ||
dumpOptions = parsedArgs.options; | ||
var Module = require('module'); | ||
@@ -815,0 +911,0 @@ process.argv = newArgv; |
{ | ||
"name": "wtfnode", | ||
"version": "0.9.4", | ||
"version": "0.10.0", | ||
"description": "Utility to help find out why Node isn't exiting", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -47,3 +47,3 @@ # What? | ||
You can install as a global module (`npm install -g wtfnode`) and call a node script manually: `wtfnode <yourscript> <yourargs> ...` | ||
You can install as a global module (`npm install -g wtfnode`) and call a node script manually: `wtfnode [OPTION...] <yourscript> <yourargs> ...` | ||
@@ -54,2 +54,5 @@ If you do this, `wtfnode` will load itself, then forward control to the script you specified as if you had run `node <yourscript> ...`. When you are ready, send SIGINT (Ctrl+C). The process will exit, and the active handles at the time of exit will be printed out. | ||
## Options | ||
- `--fullstacks` Include full stack traces in output | ||
# Module usage | ||
@@ -63,2 +66,10 @@ | ||
If you wish you can customize the output from `wtf.dump()` like so: | ||
```javascript | ||
wtf.dump({ | ||
fullStacks: true, // Include full stack traces in output, default is false | ||
}); | ||
``` | ||
**Important**: Require at the entry point of your application. You must do this before loading / referencing even native node modules, or certain hooks may not be effective. | ||
@@ -65,0 +76,0 @@ |
41631
837
101