Skip to content

Commit 75a6d05

Browse files
committed
refactor(*): use async_hooks for Node.js 8.1.0 and above
Fixes #75
1 parent 692d651 commit 75a6d05

File tree

4 files changed

+100
-2
lines changed

4 files changed

+100
-2
lines changed

docs/compatibility.asciidoc

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ Previous versions of Node.js are not supported.
77
Some versions of Node.js contain bugs or issues that limit our ability to instrument them correctly.
88
The following versions of Node.js are known to not be fully instrumented:
99

10-
- v7.10.x - Recommended solution: Upgrade to v8.0.0 or higher to get full support
10+
- v7.10.x - Recommended solution: Upgrade to v8.1.0 or higher to get full support
11+
- v8.0.0 - Recommended solution: Upgrade to v8.1.0 or higher to get full support
1112

1213
[float]
1314
[[compatibility-frameworks]]

lib/instrumentation/async-hooks.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict'
2+
3+
const asyncHooks = require('async_hooks')
4+
5+
module.exports = function (ins) {
6+
const asyncHook = asyncHooks.createHook({init, before, after, destroy})
7+
const initState = new Map()
8+
const beforeState = new Map()
9+
10+
asyncHook.enable()
11+
12+
function init (asyncId, type, triggerAsyncId, resource) {
13+
// We don't care about the TIMERWRAP, as it will only init once for each
14+
// timer that shares the timeout value. Instead we rely on the Timeout
15+
// type, which will init for each scheduled timer.
16+
if (type === 'TIMERWRAP') return
17+
18+
initState.set(asyncId, ins.currentTransaction)
19+
}
20+
21+
function before (asyncId) {
22+
if (!initState.has(asyncId)) return // in case type === TIMERWRAP
23+
beforeState.set(asyncId, ins.currentTransaction)
24+
ins.currentTransaction = initState.get(asyncId)
25+
}
26+
27+
function after (asyncId) {
28+
if (!initState.has(asyncId)) return // in case type === TIMERWRAP
29+
ins.currentTransaction = beforeState.get(asyncId)
30+
}
31+
32+
function destroy (asyncId) {
33+
if (!initState.has(asyncId)) return // in case type === TIMERWRAP
34+
initState.delete(asyncId)
35+
beforeState.delete(asyncId)
36+
}
37+
}

lib/instrumentation/index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
var fs = require('fs')
44
var path = require('path')
5+
var semver = require('semver')
56
var hook = require('require-in-the-middle')
67
var Transaction = require('./transaction')
78
var Queue = require('./queue')
@@ -40,7 +41,11 @@ Instrumentation.prototype.start = function () {
4041
})
4142
})
4243

43-
require('./patch-async')(this)
44+
if (semver.gte(process.version, '8.1.0')) {
45+
require('./async-hooks')(this)
46+
} else {
47+
require('./patch-async')(this)
48+
}
4449

4550
debug('shimming Module._load function')
4651
hook(MODULES, function (exports, name, basedir) {

test/instrumentation/async-hooks.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use strict'
2+
3+
var agent = require('../..').start({
4+
appName: 'test',
5+
captureExceptions: false
6+
})
7+
var ins = agent._instrumentation
8+
9+
var test = require('tape')
10+
11+
test('setTimeout', function (t) {
12+
t.plan(2)
13+
twice(function () {
14+
var trans = agent.startTransaction()
15+
setTimeout(function () {
16+
t.equal(ins.currentTransaction, trans)
17+
}, 50)
18+
})
19+
})
20+
21+
test('setInterval', function (t) {
22+
t.plan(2)
23+
twice(function () {
24+
var trans = agent.startTransaction()
25+
var timer = setInterval(function () {
26+
clearInterval(timer)
27+
t.equal(ins.currentTransaction, trans)
28+
}, 50)
29+
})
30+
})
31+
32+
test('setImmediate', function (t) {
33+
t.plan(2)
34+
twice(function () {
35+
var trans = agent.startTransaction()
36+
setImmediate(function () {
37+
t.equal(ins.currentTransaction, trans)
38+
})
39+
})
40+
})
41+
42+
test('process.nextTick', function (t) {
43+
t.plan(2)
44+
twice(function () {
45+
var trans = agent.startTransaction()
46+
process.nextTick(function () {
47+
t.equal(ins.currentTransaction, trans)
48+
})
49+
})
50+
})
51+
52+
function twice (fn) {
53+
setImmediate(fn)
54+
setImmediate(fn)
55+
}

0 commit comments

Comments
 (0)