Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use async_hooks #29

Merged
merged 2 commits into from Feb 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 17 additions & 14 deletions README.md
Expand Up @@ -26,26 +26,29 @@ setTimeout(function () {
}, 100)
```

Run the above script like this: `node --expose-internals example.js`. It will print the following:
Run the above script like this: `node example.js`. It will print the following:

```
There are 4 known handle(s) keeping the process running and 0 unknown
Known handles:
There are 5 handle(s) keeping the process running

# Timer
/Users/maf/dev/node_modules/why-is-node-running/example.js:6 - setInterval(function () {}, 1000)
/Users/maf/dev/node_modules/why-is-node-running/example.js:10 - createServer()
# Timeout
/home/maf/dev/node_modules/why-is-node-running/example.js:6 - setInterval(function () {}, 1000)
/home/maf/dev/node_modules/why-is-node-running/example.js:10 - createServer()

# TCP
/Users/maf/dev/node_modules/why-is-node-running/example.js:7 - server.listen(0)
/Users/maf/dev/node_modules/why-is-node-running/example.js:10 - createServer()
# TCPSERVERWRAP
/home/maf/dev/node_modules/why-is-node-running/example.js:7 - server.listen(0)
/home/maf/dev/node_modules/why-is-node-running/example.js:10 - createServer()

# TCP
/Users/maf/dev/node_modules/why-is-node-running/example.js:7 - server.listen(0)
/Users/maf/dev/node_modules/why-is-node-running/example.js:11 - createServer()
# Timeout
/home/maf/dev/node_modules/why-is-node-running/example.js:6 - setInterval(function () {}, 1000)
/home/maf/dev/node_modules/why-is-node-running/example.js:11 - createServer()

# Timer
/Users/maf/dev/node_modules/why-is-node-running/example.js:13 - setTimeout(function () {
# TCPSERVERWRAP
/home/maf/dev/node_modules/why-is-node-running/example.js:7 - server.listen(0)
/home/maf/dev/node_modules/why-is-node-running/example.js:11 - createServer()

# Timeout
/home/maf/dev/node_modules/why-is-node-running/example.js:13 - setTimeout(function () {
```

## CLI
Expand Down
1 change: 0 additions & 1 deletion cli.js
Expand Up @@ -9,7 +9,6 @@ console.log('probing program', prog)
console.log('kill -SIGUSR1', process.pid, 'for logging')

var nodeArgs = [
'--expose-internals',
'-r',
path.join(__dirname, 'include.js')
]
Expand Down
115 changes: 0 additions & 115 deletions core.js

This file was deleted.

2 changes: 1 addition & 1 deletion example.js
@@ -1,4 +1,4 @@
var log = require('why-is-node-running')
var log = require('./')
var net = require('net')

function createServer () {
Expand Down
123 changes: 32 additions & 91 deletions index.js
@@ -1,78 +1,40 @@
var core = require('./core')

var b = process.binding

process.binding = function (name) {
var loaded = b(name)
var cpy = {}

Object.keys(loaded).forEach(function (prop) {
if (typeof loaded[prop] === 'function' && loaded[prop].prototype) {
var wrap = function () {
var handle

if (arguments.length === 4) handle = new loaded[prop](arguments[0], arguments[1], arguments[2], arguments[3])
else if (arguments.length === 3) handle = new loaded[prop](arguments[0], arguments[1], arguments[2])
else if (arguments.length === 2) handle = new loaded[prop](arguments[0], arguments[1])
else if (arguments.length === 1) handle = new loaded[prop](arguments[0])
else handle = new loaded[prop]()

var e = new Error('whatevs')
var stacks = require('stackback')(e)

handle.__WHY_IS_NODE_RUNNING__ = {stacks: [], wrapped: loaded[prop]}

for (var i = 1; i < stacks.length; i++) {
handle.__WHY_IS_NODE_RUNNING__.stacks.push(stacks[i])
}

return handle
}

Object.keys(loaded[prop]).forEach(function (name) {
wrap[name] = loaded[prop][name]
})

if (/^[A-Z]/.test(prop)) {
cpy[prop] = wrap
} else {
cpy[prop] = loaded[prop]
}
} else {
cpy[prop] = loaded[prop]
}
})
var asyncHooks = require('async_hooks')
var stackback = require('stackback')
var path = require('path')
var fs = require('fs')
var sep = path.sep

var active = new Map()
var hook = asyncHooks.createHook({
init (asyncId, type) {
if (type === 'TIMERWRAP') return
var err = new Error('whatevs')
var stacks = stackback(err)
active.set(asyncId, {type, stacks})
},
destroy (asyncId) {
active.delete(asyncId)
}
})

return cpy
}
hook.enable()
module.exports = whyIsNodeRunning

core.globalTimeouts()
function whyIsNodeRunning (logger) {
if (!logger) logger = console

module.exports = function (logger) {
logger = logger || console
var handles = process._getActiveHandles()
var unknown = []
var known = []
hook.disable()
logger.error('There are %d handle(s) keeping the process running', active.size)
for (const o of active.values()) printStacks(o)

handles.forEach(function (handle) {
var stacks = findStacks(handle, 0)
if (stacks) {
known.push(stacks)
} else {
unknown.push(handle)
}
})

logger.error('There are %d known handle(s) keeping the process running and %d unknown', known.length, unknown.length)
logger.error('Known handles:\n')
known.forEach(function (obj, i) {
var stacks = obj.stacks

stacks = stacks.filter(function (s) {
return s.getFileName().indexOf(require('path').sep) > -1
function printStacks (o) {
var stacks = o.stacks.slice(1).filter(function (s) {
var filename = s.getFileName()
return filename.indexOf(sep) > -1 && filename.indexOf('internal' + sep) !== 0
})

logger.error('# %s', obj.wrapped.name)
logger.error('')
logger.error('# %s', o.type)

if (!stacks[0]) {
logger.error('(unknown stack trace)')
Expand All @@ -85,33 +47,12 @@ module.exports = function (logger) {
stacks.forEach(function (s) {
var prefix = s.getFileName() + ':' + s.getLineNumber()
try {
var src = require('fs').readFileSync(s.getFileName(), 'utf-8').split(/\n|\r\n/)
var src = fs.readFileSync(s.getFileName(), 'utf-8').split(/\n|\r\n/)
logger.error(prefix + padding.slice(prefix.length) + ' - ' + src[s.getLineNumber() - 1].trim())
} catch (e) {
logger.error(prefix + padding.slice(prefix.length))
}
})
}

logger.error('\nUnknown handles:\n')

unknown.forEach(function (stack) {
logger.error(stack)
logger.error()
})
})
}

function findStacks (obj, depth) {
if (depth === 10) return null

var keys = Object.keys(obj)
for (var i = 0; i < keys.length; i++) {
var val = obj[keys[i]]
if (keys[i] === '__WHY_IS_NODE_RUNNING__') return val
if (typeof val === 'object' && val) {
val = findStacks(val, depth + 1)
if (val) return val
}
}
}