├── .gitignore ├── .travis.yml ├── example.js ├── package.json ├── LICENSE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - 4 5 | - 6 6 | - 7 7 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var onAsyncHooks = require('./') 2 | var http = require('http') 3 | 4 | onAsyncHooks(function (data) { 5 | console.log(data) 6 | }) 7 | 8 | http.createServer(function (req, res) { 9 | res.end('Hello qts') 10 | }).listen(8080) 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "on-async-hook", 3 | "version": "1.0.1", 4 | "description": "async_hook trace emitter", 5 | "main": "index.js", 6 | "repository": "lrlna/on-async-hook", 7 | "scripts": { 8 | "test": "standard", 9 | "start": "node example" 10 | }, 11 | "keywords": [ 12 | "async_hook", 13 | "tracing", 14 | "logging" 15 | ], 16 | "author": "Irina Shestak ", 17 | "license": "MIT", 18 | "devDependencies": { 19 | "standard": "^10.0.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [Irina Shestak] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # on-async-hook 🔍 2 | [![npm version][1]][2] [![build status][3]][4] 3 | [![downloads][5]][6] [![js-standard-style][7]][8] 4 | 5 | [async_hook](https://nodejs.org/api/async_hooks.html) trace emitter to help you with your tracing needs. Fair warning, async_hook api is only available in node 8, and is an under an experimental flag. 6 | 7 | ## Usage 8 | 9 | ```js 10 | var onAsyncHook = require('on-async-hook') 11 | 12 | onAsyncHook(function (data) { 13 | console.log(data) 14 | }) 15 | ``` 16 | 17 | ## API 18 | ### `stop = onAsyncHook([opts], cb(data))` 19 | Create an instance of `onAsyncHook`. Calls a callback with data you can add to your logger. 20 | 21 | ### `stop()` 22 | Disable `onAsyncHook` instance. 23 | 24 | # Install 25 | ```bash 26 | npm install on-async-hook 27 | ``` 28 | [MIT](https://tldrlegal.com/license/mit-license) 29 | 30 | [1]: https://img.shields.io/npm/v/on-async-hook.svg?style=flat-square 31 | [2]: https://npmjs.org/package/on-async-hook 32 | [3]: https://img.shields.io/travis/lrlna/on-async-hook/master.svg?style=flat-square 33 | [4]: https://travis-ci.org/lrlna/on-async-hook 34 | [5]: http://img.shields.io/npm/dm/on-async-hook.svg?style=flat-square 35 | [6]: https://npmjs.org/package/on-async-hook 36 | [7]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 37 | [8]: https://github.com/feross/standard 38 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var NS_PER_SEC = 1e9 3 | 4 | module.exports = onAsyncHook 5 | 6 | function onAsyncHook (opts, cb) { 7 | if (!cb) { 8 | cb = opts 9 | opts = {} 10 | } 11 | 12 | assert.equal(typeof opts, 'object', 'on-async-hook: opts should be type object') 13 | assert.equal(typeof cb, 'function', 'on-async-hook: cb should be type function') 14 | 15 | // catch this if we are not in node 8 16 | try { 17 | var asyncHooks = require('async_hooks') 18 | } catch (e) { 19 | return function () {} 20 | } 21 | 22 | var links = {} 23 | var traces = {} 24 | var spans = {} 25 | 26 | var hooks = { 27 | init: init, 28 | destroy: destroy 29 | } 30 | 31 | var asyncHook = asyncHooks.createHook(hooks) 32 | asyncHook.enable() 33 | 34 | return function () { 35 | asyncHook.disable() 36 | } 37 | 38 | function init (asyncId, type, triggerId) { 39 | var currentId = asyncHooks.executionAsyncId() 40 | // don't want the initial start TCPWRAP 41 | if (currentId === 1 && type === 'TCPWRAP') return 42 | if (triggerId === 0) return 43 | 44 | var time = process.hrtime() 45 | var span = createSpan(asyncId, type, triggerId, time) 46 | var traceId = links[triggerId] 47 | var trace = null 48 | 49 | if (!traceId) { 50 | traceId = asyncId 51 | trace = createTrace(time, traceId) 52 | } else { 53 | trace = traces[traceId] 54 | } 55 | traces[asyncId] = trace 56 | links[asyncId] = traceId 57 | spans[asyncId] = span 58 | trace.spans.push(span) 59 | } 60 | 61 | function destroy (asyncId) { 62 | var time = process.hrtime() 63 | var span = spans[asyncId] 64 | if (!span) return 65 | span.endTime = time[0] * NS_PER_SEC + time[1] 66 | span.duration = span.endTime - span.startTime 67 | var trace = traces[asyncId] 68 | if (!trace) return 69 | trace.endTime = time[0] * NS_PER_SEC + time[1] 70 | trace.duration = trace.endTime - trace.startTime 71 | links[asyncId] = null 72 | traces[asyncId] = null 73 | trace.spans.forEach(function (span) { 74 | var id = span.id 75 | links[id] = null 76 | spans[id] = null 77 | }) 78 | cb(trace) 79 | } 80 | 81 | function createSpan (id, type, parent, time) { 82 | return { 83 | id: id, 84 | type: type, 85 | parent: parent, 86 | startTime: time[0] * NS_PER_SEC + time[1] 87 | } 88 | } 89 | 90 | function createTrace (time, id) { 91 | return { 92 | startTime: time[0] * NS_PER_SEC + time[1], 93 | id: id, 94 | spans: [] 95 | } 96 | } 97 | } 98 | --------------------------------------------------------------------------------