Node.js Async Hooks
This allows you to directly track all async calls and where they are going. Unlike alot of other tactics, this does not require modifying the original code that needs to be tracked. Firstly, here is a simple HTTP server:
const http = require('http'); http.createServer((req, res) => { res.end('hello\n'); }).listen(5000); console.log('The HTTP server was started on port 5000'); // Result of: curl localhost:5000 // hello
If an async hook is created and enabled before the script, all the events can be tracked:
const async_hooks = require('async_hooks'); const fs = require('fs'); const asyncHook = async_hooks.createHook({ init: (asyncId, type, triggerAsyncId, resource) => { // Using console would trigger hooks which would trigger infinite recursion // console.info(asyncId, type, triggerAsyncId, resource); fs.writeSync(1, `${type} ${resource} \n`); } }); asyncHook.enable(); // When the server is started with the above first: // Event: TCPSERVERWRAP // Event: TickObject // The HTTP server was started on port 5000 // Event: TickObject
The TickObject represents each time the JavaScript even loop is incremented and new processing is done. That code can be put into a separate file. So to track parts of code a file can just be imported (asyncHook.disable can be used to stop tracking). For example, this is how to track when timeout callbacks are called and what those callbacks are:
const asyncHook = async_hooks.createHook({ init: (asyncId, type, triggerAsyncId, resource) => { if (type === 'Timeout') { const stack = new Error().stack; fs.writeSync(1, `Callback: ${type} ${resource._onTimeout.toString()} \n`); fs.writeSync(1, ` Location: ${stack} \n`); } } }); // asyncHook being defined in code snippet above asyncHook.enable(); http.createServer((req, res) => { setTimeout(() => { console.log('Running an async event'); }); res.end('hello\n'); }).listen(5000); // Run this in another CLI tab: // curl localhost:5000
There will be a few other timeout callbacks (called via libraries), but near this middle should be the one defined above and it will say exactly where it is called from.
Anyways, although this API is only for Node 8+ and is experimental, it is still useful for analyzing code performance and other characteristics. Especially when a lot of libraries and async calls are used.
Github Location: https://github.com/Jacob-Friesen/obscurejs/blob/master/2018/asyncHooks.js













