$> node tree.js ./app.js | dot -Tsvg > events.svg && xdg-open events.svg
Last active
December 30, 2015 07:29
-
-
Save creationix/7796338 to your computer and use it in GitHub Desktop.
Generate a tree of events using process.addAsyncListener
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var http = require('http'); | |
var fs = require('fs'); | |
var server = http.createServer(function (req, res) { | |
var stream = fs.createReadStream(__filename); | |
stream.pipe(res); | |
res.setHeader("Content-Type", "application/javascript"); | |
stream.once('end', function () { | |
server.close(); | |
}); | |
}); | |
server.listen(8080, function () { | |
console.error("Server listening at http://localhost:8080/"); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// polyfill process.addAsyncListener for older nodes. | |
if (!process.addAsyncListener) require('async-listener'); | |
process.addAsyncListener(setup, { | |
before: onBefore, | |
after: onAfter, | |
error: onError | |
}); | |
var current = null; | |
var stack = []; | |
var leaves = []; | |
var nextId = 1; | |
function guessName() { | |
var stack = (new Error()).stack.split("\n"); | |
var seen = false; | |
var line; | |
for (var i = 1; i < stack.length; i++) { | |
line = stack[i]; | |
var isLib = /node_modules\/async-listener/.test(line); | |
if (!seen) { | |
if (isLib) seen = true; | |
continue; | |
} | |
if (isLib) continue; | |
break; | |
} | |
var match = line.match(/at ([^ ]*).*\(([^)]*)\)/); | |
return { | |
name: match && match[1], | |
file: match && match[2] | |
}; | |
} | |
function setup() { | |
var info = guessName(); | |
info.parent = current; | |
info.parentIndex = current ? current.children.length - 1 : 0; | |
info.setup = Date.now(); | |
info.id = nextId++; | |
info.children = []; | |
if (current) { | |
var index = leaves.indexOf(current); | |
if (index >= 0) leaves.splice(index, 1); | |
} | |
leaves.push(info); | |
return info; | |
} | |
function onBefore(context, storage) { | |
if (current) stack.push(current); | |
storage.children.push({ before: Date.now() }); | |
current = storage; | |
} | |
function onAfter(context, storage) { | |
storage.children[storage.children.length - 1].after = Date.now(); | |
current = stack.pop(); | |
} | |
function onError(storage, error) { | |
if (!storage) return false; | |
storage.error = error; | |
return true; | |
} | |
process.on('exit', function () { | |
var inspect = require('util').inspect; | |
var nodes = leaves; | |
leaves = []; | |
var seen = []; | |
console.error(inspect(nodes, {colors:true,depth:100})); | |
console.log('digraph events {'); | |
console.log('graph [rankdir = "LR"];'); | |
nodes.forEach(function (node) { | |
while (node) { | |
if (seen.indexOf(node) >= 0) return; | |
seen.push(node); | |
var ch = node.children.map(function (child, i) { | |
return '<c' + i + '>' + (child.before - node.setup) + 'ms - ' + (child.after - child.before) + 'ms'; | |
}).join("|"); | |
console.log('n' + node.id + ' [ shape=record label="<name>' + ("" + node.name).replace('<', "(").replace(">", ")") + '|' + node.file + '|' + ch + '" ];'); | |
var parent = node.parent; | |
if (parent) { | |
console.log('n' + parent.id + ':c' + node.parentIndex + ' -> n' + node.id + ':name'); | |
} | |
node = parent; | |
} | |
}); | |
console.log('}'); | |
}); | |
require(process.argv[2]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment