-
Notifications
You must be signed in to change notification settings - Fork 400
/
async_hooks.js
101 lines (85 loc) · 2.7 KB
/
async_hooks.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
'use strict'
var logger = require('../../logger').child({component: 'async_hooks'})
var promInit = require('../promise')
var psemver = require('../../util/process-version')
var setInternalProperty = require('../../util/internalProperty').setInternalProperty
module.exports = initialize
/**
* The spec for the native `Promise` class.
*/
var STATIC_PROMISE_METHODS = ['accept', 'all', 'defer', 'race', 'reject', 'resolve']
var NATIVE_PROMISE_SPEC = {
name: 'global',
constructor: 'Promise',
executor: true,
$proto: {
then: ['then', 'chain'],
catch: ['catch']
},
$static: {
$copy: STATIC_PROMISE_METHODS,
cast: STATIC_PROMISE_METHODS
}
}
function initialize(agent) {
var enableHooks = agent.config.checkAsyncHookStatus()
if (enableHooks && tryAsyncHooks(agent)) {
logger.debug('Using async_hooks.')
} else if (psemver.satisfies('>=0.12')) {
logger.debug('Using promise instrumentation.')
promInit(agent, global, NATIVE_PROMISE_SPEC)
}
}
function tryAsyncHooks(agent) {
var asyncHooks = null
try {
asyncHooks = require('async_hooks')
} catch (e) {
logger.info(e, 'Not using async_hooks module.')
return false
}
// this map is reused to track the segment that was active when
// the before callback is called to be replaced in the after callback
var segmentMap = new Map()
module.exports._segmentMap = segmentMap
var hook = asyncHooks.createHook({
init: function initHook(id, type, triggerId, promiseWrap) {
var transaction = agent.getTransaction()
if (!transaction || type !== 'PROMISE') {
return
}
var activeSegment = agent.tracer.getSegment()
if (promiseWrap && promiseWrap.promise) {
setInternalProperty(promiseWrap.promise, '__NR_segment', activeSegment)
}
segmentMap.set(id, activeSegment)
},
before: function beforeHook(id) {
var hookSegment = segmentMap.get(id)
if (!hookSegment) {
return
}
segmentMap.set(id, agent.tracer.getSegment())
agent.tracer.segment = hookSegment
},
after: function afterHook(id) {
var hookSegment = segmentMap.get(id)
// hookSegment is the segment that was active before the promise
// executed. If the promise is executing before a segment has been
// restored, hookSegment will be null and should be restored. Thus
// undefined is the only invalid value here.
if (hookSegment === undefined) {
return
}
segmentMap.set(id, agent.tracer.getSegment())
agent.tracer.segment = hookSegment
},
destroy: function destHook(id) {
segmentMap.delete(id)
}
}).enable()
agent.on('unload', function disableHook() {
hook.disable()
})
return true
}