-
Notifications
You must be signed in to change notification settings - Fork 3
/
hooks.js
82 lines (74 loc) · 2.33 KB
/
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
'use strict'
const asyncHooks = require('async_hooks')
const { performance } = require('perf_hooks')
const { cleanHooksStackMeta } = require('./lib/cleanStack')
const { printMessage } = require('./lib/print')
const filePath = process.env.AID_HOOK_SCOPE
const data = new Map()
const depthCache = {}
function getDepthFor (asyncId, triggerAsyncId) {
const value = (depthCache[triggerAsyncId] || 0) + 1
depthCache[asyncId] = value
return value
}
function getFunctionId (stack, asyncId) {
// debugLog(cleanHooksStack(stack))
const meta = cleanHooksStackMeta(stack)
if (meta.untraceable) {
return null
}
let clean = meta.frames[0]
if (clean.split('(')[1][0] !== '/') {
printMessage(`COULD NOT PROCESS STACKTRACE ${asyncId} ${stack.split('\n').slice(2).join('\n')}`)
}
if (meta.wasAnon) {
clean = meta.wasAnon + clean
}
if (meta.wasConsole) {
clean = ' at console called' + clean
}
return clean.replace(' at ', '')
}
Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 20)
const asyncHook = asyncHooks.createHook({
init (asyncId, type, triggerAsyncId) {
const e = {}
Error.captureStackTrace(e)
if (data.has(triggerAsyncId) || e.stack.includes(filePath)) {
const funcId = getFunctionId(e.stack, asyncId)
if (funcId) {
data.set(asyncId, { funcId, triggerAsyncId, depth: getDepthFor(asyncId, triggerAsyncId) })
}
}
},
before (asyncId) {
const info = data.get(asyncId)
if (!info) return
performance.mark('b' + asyncId)
},
after (asyncId) {
const info = data.get(asyncId)
if (!info) return
performance.mark('a' + asyncId)
const prefix = ' '.repeat(info.depth - 1) + '└'
printMessage(`${prefix}[${denominate(info.triggerAsyncId)}->${denominate(asyncId)}] ${info.funcId}`)
performance.measure(`[${denominate(asyncId)} from ${denominate(info.triggerAsyncId)}] ${info.funcId}`, 'b' + asyncId, 'a' + asyncId)
}
// TODO add destroy to clean up data in case node reuses sayncIds
})
let first = 0
function denominate (num) {
if (!first) {
first = parseInt(num, 10) - 1
}
return pad(num - first)
}
function pad (num) {
if (num < 10) return '00000' + num
if (num < 100) return '0000' + num
if (num < 1000) return '000' + num
if (num < 10000) return '00' + num
if (num < 100000) return '0' + num
return num
}
asyncHook.enable()