@senzops/apm-node 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/register.js +1 -1
- package/dist/register.js.map +1 -1
- package/dist/register.mjs +1 -1
- package/dist/register.mjs.map +1 -1
- package/package.json +1 -1
- package/src/instrumentation/express.ts +12 -2
- package/src/instrumentation/hook.ts +85 -216
package/package.json
CHANGED
|
@@ -273,6 +273,16 @@ const patchRouteMethodHandlers = (
|
|
|
273
273
|
}
|
|
274
274
|
};
|
|
275
275
|
|
|
276
|
+
const getSafeRouter = (app: any) => {
|
|
277
|
+
if (!app) return undefined;
|
|
278
|
+
if (app._router) return app._router;
|
|
279
|
+
try {
|
|
280
|
+
return app.router;
|
|
281
|
+
} catch {
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
276
286
|
const patchExpress = (
|
|
277
287
|
expressModule: any,
|
|
278
288
|
options?: SenzorOptions
|
|
@@ -320,9 +330,9 @@ const patchExpress = (
|
|
|
320
330
|
'senzor.express.application.use',
|
|
321
331
|
(original) =>
|
|
322
332
|
function patchedExpressApplicationUse(this: any, ...args: any[]) {
|
|
323
|
-
const router = this
|
|
333
|
+
const router = getSafeRouter(this);
|
|
324
334
|
const result = original.apply(this, args);
|
|
325
|
-
const activeRouter = this
|
|
335
|
+
const activeRouter = getSafeRouter(this) || router;
|
|
326
336
|
const layer = activeRouter?.stack?.[activeRouter.stack.length - 1];
|
|
327
337
|
patchLayer(layer, getLayerPath(args), options);
|
|
328
338
|
return result;
|
|
@@ -1,265 +1,134 @@
|
|
|
1
1
|
import Module from 'module';
|
|
2
2
|
|
|
3
|
-
const SENZOR_PATCHED =
|
|
4
|
-
|
|
3
|
+
const SENZOR_PATCHED = Symbol.for('senzor.require.patched');
|
|
4
|
+
const SENZOR_HOOKS = Symbol.for('senzor.require.hooks');
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
type HookFn = (exports: unknown) => unknown | void;
|
|
7
|
+
type HookMap = Map<string, HookFn[]>;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
// Module.createRequire works in both CJS and ESM contexts,
|
|
10
|
+
// unlike bare `require` which is unavailable in ESM builds.
|
|
11
|
+
const safeRequire: NodeRequire = Module.createRequire(
|
|
12
|
+
typeof __filename !== 'undefined'
|
|
13
|
+
? __filename
|
|
14
|
+
: process.cwd() + '/'
|
|
15
|
+
);
|
|
14
16
|
|
|
15
17
|
function getHookRegistry(): HookMap {
|
|
16
|
-
|
|
17
|
-
const mod =
|
|
18
|
-
Module as unknown as Record<
|
|
19
|
-
symbol,
|
|
20
|
-
HookMap
|
|
21
|
-
>;
|
|
18
|
+
const mod = Module as unknown as Record<symbol, HookMap>;
|
|
22
19
|
|
|
23
20
|
if (!mod[SENZOR_HOOKS]) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
value: new Map(),
|
|
30
|
-
enumerable: false
|
|
31
|
-
}
|
|
32
|
-
);
|
|
33
|
-
|
|
21
|
+
Object.defineProperty(mod, SENZOR_HOOKS, {
|
|
22
|
+
value: new Map(),
|
|
23
|
+
enumerable: false
|
|
24
|
+
});
|
|
34
25
|
}
|
|
35
26
|
|
|
36
27
|
return mod[SENZOR_HOOKS];
|
|
37
|
-
|
|
38
28
|
}
|
|
39
29
|
|
|
40
|
-
function runHooks(
|
|
41
|
-
|
|
42
|
-
exports
|
|
43
|
-
) {
|
|
44
|
-
|
|
45
|
-
const registry =
|
|
46
|
-
(Module as unknown as Record<
|
|
47
|
-
symbol,
|
|
48
|
-
HookMap
|
|
49
|
-
>)[SENZOR_HOOKS];
|
|
30
|
+
function runHooks(moduleName: string, exports: unknown) {
|
|
31
|
+
const registry = (Module as unknown as Record<symbol, HookMap>)[SENZOR_HOOKS];
|
|
32
|
+
if (!registry) return exports;
|
|
50
33
|
|
|
51
|
-
|
|
34
|
+
const hooks = registry.get(moduleName);
|
|
35
|
+
if (!hooks?.length) return exports;
|
|
52
36
|
|
|
53
|
-
|
|
54
|
-
registry.get(moduleName);
|
|
55
|
-
|
|
56
|
-
if (!hooks?.length) return exports;
|
|
57
|
-
|
|
58
|
-
let currentExports =
|
|
59
|
-
exports;
|
|
60
|
-
|
|
61
|
-
for (const hook of hooks) {
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
const nextExports =
|
|
65
|
-
hook(currentExports);
|
|
66
|
-
|
|
67
|
-
if (nextExports !== undefined) {
|
|
68
|
-
currentExports =
|
|
69
|
-
nextExports;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
|
|
74
|
-
console.error(
|
|
75
|
-
`[Senzor] instrumentation failed for ${moduleName}`,
|
|
76
|
-
err
|
|
77
|
-
);
|
|
37
|
+
let currentExports = exports;
|
|
78
38
|
|
|
39
|
+
for (const hook of hooks) {
|
|
40
|
+
try {
|
|
41
|
+
const nextExports = hook(currentExports);
|
|
42
|
+
if (nextExports !== undefined) {
|
|
43
|
+
currentExports = nextExports;
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error(`[Senzor] instrumentation failed for ${moduleName}`, err);
|
|
79
47
|
}
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return currentExports;
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function patchLoaderOnce() {
|
|
88
|
-
|
|
89
|
-
const mod =
|
|
90
|
-
Module as unknown as any;
|
|
91
|
-
|
|
92
|
-
if (mod[SENZOR_PATCHED]) {
|
|
93
|
-
return;
|
|
94
48
|
}
|
|
95
49
|
|
|
96
|
-
|
|
97
|
-
|
|
50
|
+
return currentExports;
|
|
51
|
+
}
|
|
98
52
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
request: string,
|
|
102
|
-
parent: unknown,
|
|
103
|
-
isMain: boolean
|
|
104
|
-
) {
|
|
53
|
+
function patchLoaderOnce() {
|
|
54
|
+
const mod = Module as unknown as any;
|
|
105
55
|
|
|
106
|
-
|
|
107
|
-
previousLoad.apply(
|
|
108
|
-
this,
|
|
109
|
-
arguments
|
|
110
|
-
);
|
|
56
|
+
if (mod[SENZOR_PATCHED]) return;
|
|
111
57
|
|
|
112
|
-
|
|
113
|
-
runHooks(
|
|
114
|
-
request,
|
|
115
|
-
exports
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
return patchedExports;
|
|
58
|
+
const previousLoad = mod._load;
|
|
119
59
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
);
|
|
60
|
+
mod._load = function patchedLoad(
|
|
61
|
+
request: string,
|
|
62
|
+
parent: unknown,
|
|
63
|
+
isMain: boolean
|
|
64
|
+
) {
|
|
65
|
+
const exports = previousLoad.apply(this, arguments);
|
|
66
|
+
return runHooks(request, exports);
|
|
67
|
+
};
|
|
130
68
|
|
|
69
|
+
Object.defineProperty(mod, SENZOR_PATCHED, {
|
|
70
|
+
value: true,
|
|
71
|
+
enumerable: false
|
|
72
|
+
});
|
|
131
73
|
}
|
|
132
74
|
|
|
133
|
-
function patchCached(
|
|
134
|
-
moduleName: string,
|
|
135
|
-
hook: HookFn
|
|
136
|
-
) {
|
|
137
|
-
|
|
75
|
+
function patchCached(moduleName: string, hook: HookFn) {
|
|
138
76
|
try {
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
require.resolve(
|
|
142
|
-
moduleName
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
const cached =
|
|
146
|
-
require.cache?.[
|
|
147
|
-
resolved
|
|
148
|
-
];
|
|
77
|
+
const resolved = safeRequire.resolve(moduleName);
|
|
78
|
+
const cached = safeRequire.cache?.[resolved];
|
|
149
79
|
|
|
150
80
|
if (cached?.exports) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (replacement !== undefined) {
|
|
158
|
-
cached.exports =
|
|
159
|
-
replacement;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
catch { }
|
|
166
|
-
|
|
81
|
+
const replacement = hook(cached.exports);
|
|
82
|
+
if (replacement !== undefined) {
|
|
83
|
+
cached.exports = replacement;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch { }
|
|
167
87
|
}
|
|
168
88
|
|
|
169
|
-
function tryRequire(
|
|
170
|
-
moduleName: string,
|
|
171
|
-
hook: HookFn
|
|
172
|
-
) {
|
|
173
|
-
|
|
89
|
+
function tryRequire(moduleName: string, hook: HookFn) {
|
|
174
90
|
try {
|
|
175
|
-
|
|
176
|
-
const mod =
|
|
177
|
-
require(moduleName);
|
|
178
|
-
|
|
91
|
+
const mod = safeRequire(moduleName);
|
|
179
92
|
if (mod) {
|
|
180
|
-
hook(mod);
|
|
93
|
+
hook(mod);
|
|
181
94
|
}
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
catch { }
|
|
185
|
-
|
|
95
|
+
} catch { }
|
|
186
96
|
}
|
|
187
97
|
|
|
188
|
-
function retryPatch(
|
|
189
|
-
moduleName: string,
|
|
190
|
-
hook: HookFn
|
|
191
|
-
) {
|
|
192
|
-
|
|
98
|
+
function retryPatch(moduleName: string, hook: HookFn) {
|
|
193
99
|
let attempts = 0;
|
|
194
|
-
|
|
195
100
|
const max = 5;
|
|
196
101
|
|
|
197
|
-
const timer =
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
attempts++;
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
|
|
204
|
-
const mod =
|
|
205
|
-
require(moduleName);
|
|
206
|
-
|
|
207
|
-
if (mod) {
|
|
208
|
-
|
|
209
|
-
hook(mod);
|
|
102
|
+
const timer = setInterval(() => {
|
|
103
|
+
attempts++;
|
|
210
104
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
catch { }
|
|
217
|
-
|
|
218
|
-
if (attempts >= max) {
|
|
105
|
+
try {
|
|
106
|
+
const mod = safeRequire(moduleName);
|
|
107
|
+
if (mod) {
|
|
108
|
+
hook(mod);
|
|
219
109
|
clearInterval(timer);
|
|
220
110
|
}
|
|
111
|
+
} catch { }
|
|
221
112
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export const hookRequire =
|
|
227
|
-
(
|
|
228
|
-
moduleName: string,
|
|
229
|
-
onRequire: HookFn
|
|
230
|
-
) => {
|
|
231
|
-
|
|
232
|
-
const registry =
|
|
233
|
-
getHookRegistry();
|
|
234
|
-
|
|
235
|
-
if (!registry.has(moduleName)) {
|
|
236
|
-
|
|
237
|
-
registry.set(
|
|
238
|
-
moduleName,
|
|
239
|
-
[]
|
|
240
|
-
);
|
|
241
|
-
|
|
113
|
+
if (attempts >= max) {
|
|
114
|
+
clearInterval(timer);
|
|
242
115
|
}
|
|
116
|
+
}, 200);
|
|
243
117
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
.push(onRequire);
|
|
247
|
-
|
|
248
|
-
patchLoaderOnce();
|
|
118
|
+
if (typeof timer.unref === 'function') timer.unref();
|
|
119
|
+
}
|
|
249
120
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
onRequire
|
|
253
|
-
);
|
|
121
|
+
export const hookRequire = (moduleName: string, onRequire: HookFn) => {
|
|
122
|
+
const registry = getHookRegistry();
|
|
254
123
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
);
|
|
124
|
+
if (!registry.has(moduleName)) {
|
|
125
|
+
registry.set(moduleName, []);
|
|
126
|
+
}
|
|
259
127
|
|
|
260
|
-
|
|
261
|
-
moduleName,
|
|
262
|
-
onRequire
|
|
263
|
-
);
|
|
128
|
+
registry.get(moduleName)!.push(onRequire);
|
|
264
129
|
|
|
265
|
-
|
|
130
|
+
patchLoaderOnce();
|
|
131
|
+
patchCached(moduleName, onRequire);
|
|
132
|
+
tryRequire(moduleName, onRequire);
|
|
133
|
+
retryPatch(moduleName, onRequire);
|
|
134
|
+
};
|