@senzops/apm-node 1.2.2 → 1.2.4

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.
Files changed (57) hide show
  1. package/dist/index.global.js +1 -1
  2. package/dist/index.global.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +1 -1
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/register.js +1 -1
  8. package/dist/register.js.map +1 -1
  9. package/dist/register.mjs +1 -1
  10. package/dist/register.mjs.map +1 -1
  11. package/package.json +1 -1
  12. package/src/core/client.ts +172 -167
  13. package/src/core/context.ts +2 -2
  14. package/src/core/types.ts +48 -43
  15. package/src/instrumentation/express.ts +12 -2
  16. package/src/instrumentation/http.ts +1 -1
  17. package/.claude/worktrees/infallible-chatelet-f3fb36/.claude/settings.local.json +0 -9
  18. package/.claude/worktrees/infallible-chatelet-f3fb36/CHANGELOG.md +0 -49
  19. package/.claude/worktrees/infallible-chatelet-f3fb36/README.md +0 -398
  20. package/.claude/worktrees/infallible-chatelet-f3fb36/package-lock.json +0 -1494
  21. package/.claude/worktrees/infallible-chatelet-f3fb36/package.json +0 -42
  22. package/.claude/worktrees/infallible-chatelet-f3fb36/src/core/client.ts +0 -451
  23. package/.claude/worktrees/infallible-chatelet-f3fb36/src/core/context.ts +0 -48
  24. package/.claude/worktrees/infallible-chatelet-f3fb36/src/core/normalizer.ts +0 -44
  25. package/.claude/worktrees/infallible-chatelet-f3fb36/src/core/sanitizer.ts +0 -203
  26. package/.claude/worktrees/infallible-chatelet-f3fb36/src/core/transport.ts +0 -273
  27. package/.claude/worktrees/infallible-chatelet-f3fb36/src/core/types.ts +0 -106
  28. package/.claude/worktrees/infallible-chatelet-f3fb36/src/index.ts +0 -36
  29. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/bullmq.ts +0 -195
  30. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/cron.ts +0 -204
  31. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/express.ts +0 -338
  32. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/fastify.ts +0 -296
  33. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/framework.ts +0 -301
  34. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/hook.ts +0 -134
  35. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/http.ts +0 -530
  36. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/koa.ts +0 -173
  37. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/mongo.ts +0 -202
  38. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/mongoose.ts +0 -156
  39. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/mysql.ts +0 -169
  40. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/patch.ts +0 -56
  41. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/pg.ts +0 -131
  42. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/redis.ts +0 -109
  43. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/span.ts +0 -73
  44. package/.claude/worktrees/infallible-chatelet-f3fb36/src/instrumentation/undici.ts +0 -189
  45. package/.claude/worktrees/infallible-chatelet-f3fb36/src/middleware/express.ts +0 -48
  46. package/.claude/worktrees/infallible-chatelet-f3fb36/src/register.ts +0 -58
  47. package/.claude/worktrees/infallible-chatelet-f3fb36/src/utils/getClientIp.ts +0 -175
  48. package/.claude/worktrees/infallible-chatelet-f3fb36/src/utils/ids.ts +0 -7
  49. package/.claude/worktrees/infallible-chatelet-f3fb36/src/utils/internal.ts +0 -1
  50. package/.claude/worktrees/infallible-chatelet-f3fb36/src/utils/sdkMeta.ts +0 -6
  51. package/.claude/worktrees/infallible-chatelet-f3fb36/src/utils/traceContext.ts +0 -44
  52. package/.claude/worktrees/infallible-chatelet-f3fb36/src/wrappers/fastify.ts +0 -35
  53. package/.claude/worktrees/infallible-chatelet-f3fb36/src/wrappers/h3.ts +0 -59
  54. package/.claude/worktrees/infallible-chatelet-f3fb36/src/wrappers/next.ts +0 -131
  55. package/.claude/worktrees/infallible-chatelet-f3fb36/tsconfig.json +0 -15
  56. package/.claude/worktrees/infallible-chatelet-f3fb36/tsup.config.ts +0 -21
  57. package/.claude/worktrees/infallible-chatelet-f3fb36/wiki.md +0 -852
@@ -1,195 +0,0 @@
1
- import type { SenzorClient } from '../core/client';
2
- import { hookRequire } from './hook';
3
- import { Context } from '../core/context';
4
-
5
- const PATCHED =
6
- Symbol.for(
7
- 'senzor.bullmq.patched'
8
- );
9
-
10
- function patchWorker(
11
- target: any,
12
- client: SenzorClient,
13
- debug: boolean
14
- ) {
15
-
16
- if (
17
- !target?.Worker?.prototype
18
- ) {
19
- return;
20
- }
21
-
22
- const proto =
23
- target.Worker.prototype;
24
-
25
- const original =
26
- proto.processJob;
27
-
28
- if (
29
- typeof original !==
30
- 'function' ||
31
- original[PATCHED]
32
- ) {
33
- return;
34
- }
35
-
36
- proto.processJob =
37
- async function (
38
- job: any
39
- ) {
40
-
41
- const queueDelay =
42
- job.timestamp
43
- ? Date.now() -
44
- job.timestamp
45
- : 0;
46
-
47
- const currentAttempt =
48
- (job.attemptsMade || 0)
49
- + 1;
50
-
51
- const maxAttempts =
52
- job.opts?.attempts
53
- ?? 1;
54
-
55
- const isFinal =
56
- currentAttempt >=
57
- maxAttempts;
58
-
59
- const taskName =
60
- job.name ===
61
- '__default__'
62
- ? job.queueName
63
- : `${job.queueName}:${job.name}`;
64
-
65
- return client.startTask(
66
-
67
- taskName,
68
-
69
- 'queue',
70
-
71
- {
72
- queueDelay,
73
- attempts:
74
- currentAttempt,
75
- isDeadLetter: false,
76
- metadata: {
77
- jobId: job.id,
78
- queueName:
79
- job.queueName,
80
- maxAttempts
81
- }
82
- },
83
-
84
- async () => {
85
-
86
- try {
87
-
88
- const result =
89
- await original.call(
90
- this,
91
- job
92
- );
93
-
94
- client.endTask(
95
- 'success'
96
- );
97
-
98
- return result;
99
-
100
- }
101
- catch (error) {
102
-
103
- try {
104
-
105
- const ctx =
106
- Context.current();
107
-
108
- if (
109
- ctx &&
110
- ctx.contextType === 'task' &&
111
- isFinal
112
- ) {
113
-
114
- ctx.data
115
- .isDeadLetter =
116
- true;
117
-
118
- }
119
-
120
- }
121
- catch { }
122
-
123
- client.captureError(
124
- error,
125
- {
126
- queueName:
127
- job.queueName,
128
- jobId: job.id,
129
- isDeadLetter:
130
- isFinal
131
- }
132
- );
133
-
134
- client.endTask(
135
- 'failed'
136
- );
137
-
138
- throw error;
139
-
140
- }
141
-
142
- }
143
-
144
- );
145
-
146
- };
147
-
148
- Object.defineProperty(
149
- proto.processJob,
150
- PATCHED,
151
- {
152
- value: true
153
- }
154
- );
155
-
156
- if (debug) {
157
-
158
- console.log(
159
- '[Senzor] BullMQ instrumented'
160
- );
161
-
162
- }
163
-
164
- }
165
-
166
- export const instrumentBullMQ =
167
- (
168
- client: SenzorClient,
169
- debug: boolean
170
- ) => {
171
-
172
- hookRequire(
173
- 'bullmq',
174
- (exports: any) => {
175
-
176
- patchWorker(
177
- exports,
178
- client,
179
- debug
180
- );
181
-
182
- if (exports?.default) {
183
-
184
- patchWorker(
185
- exports.default,
186
- client,
187
- debug
188
- );
189
-
190
- }
191
-
192
- }
193
- );
194
-
195
- };
@@ -1,204 +0,0 @@
1
- import type { SenzorClient } from '../core/client';
2
- import { hookRequire } from './hook';
3
-
4
- const PATCHED =
5
- Symbol.for('senzor.cron.patched');
6
-
7
- type CronHandler =
8
- (...args: unknown[]) => unknown;
9
-
10
- type CronSchedule =
11
- (
12
- expression: string,
13
- handler: CronHandler,
14
- options?: unknown
15
- ) => unknown;
16
-
17
- function normalizeOptions(
18
- options: unknown
19
- ): Record<string, unknown> {
20
-
21
- if (
22
- typeof options === 'object' &&
23
- options !== null
24
- ) {
25
- return options as Record<
26
- string,
27
- unknown
28
- >;
29
- }
30
-
31
- // backward compatibility with:
32
- // cron.schedule(expr, fn, "UTC")
33
- if (options) {
34
- return { timezone: options };
35
- }
36
-
37
- return {};
38
-
39
- }
40
-
41
- function patchTarget(
42
- target: Record<string, unknown>,
43
- client: SenzorClient,
44
- debug: boolean
45
- ): void {
46
-
47
- const schedule =
48
- target.schedule as
49
- CronSchedule | undefined;
50
-
51
- if (
52
- typeof schedule !== 'function' ||
53
- (schedule as any)[PATCHED]
54
- ) {
55
- return;
56
- }
57
-
58
- const original =
59
- schedule;
60
-
61
- const wrapped: CronSchedule =
62
- function (
63
- this: unknown,
64
- expression,
65
- handler,
66
- options
67
- ) {
68
-
69
- if (
70
- typeof handler !==
71
- 'function'
72
- ) {
73
-
74
- return original.call(
75
- this,
76
- expression,
77
- handler,
78
- options
79
- );
80
-
81
- }
82
-
83
- try {
84
-
85
- const opts =
86
- normalizeOptions(
87
- options
88
- );
89
-
90
- const taskName =
91
- (opts as any)?.name ??
92
- `cron: ${expression}`;
93
-
94
- const wrappedHandler =
95
- client.wrapTask(
96
- taskName,
97
- 'cron',
98
- {
99
- expression,
100
- metadata: opts
101
- },
102
- handler
103
- );
104
-
105
- return original.call(
106
- this,
107
- expression,
108
- wrappedHandler,
109
- options
110
- );
111
-
112
- }
113
- catch (err) {
114
-
115
- if (debug) {
116
-
117
- console.error(
118
- '[Senzor] cron wrap failed',
119
- err
120
- );
121
-
122
- }
123
-
124
- return original.call(
125
- this,
126
- expression,
127
- handler,
128
- options
129
- );
130
-
131
- }
132
-
133
- };
134
-
135
- Object.defineProperty(
136
- wrapped,
137
- PATCHED,
138
- {
139
- value: true,
140
- enumerable: false
141
- }
142
- );
143
-
144
- // Some ESM namespace exports are frozen
145
- try {
146
-
147
- target.schedule =
148
- wrapped;
149
-
150
- }
151
- catch {
152
-
153
- if (debug) {
154
-
155
- console.warn(
156
- '[Senzor] unable to patch cron schedule (readonly export)'
157
- );
158
-
159
- }
160
-
161
- }
162
-
163
- if (debug) {
164
-
165
- console.log(
166
- '[Senzor] node-cron instrumented'
167
- );
168
-
169
- }
170
-
171
- }
172
-
173
- export const instrumentNodeCron =
174
- (
175
- client: SenzorClient,
176
- debug: boolean
177
- ): void => {
178
-
179
- hookRequire(
180
- 'node-cron',
181
- (exports: any) => {
182
-
183
- if (!exports) return;
184
-
185
- patchTarget(
186
- exports,
187
- client,
188
- debug
189
- );
190
-
191
- if (exports.default) {
192
-
193
- patchTarget(
194
- exports.default,
195
- client,
196
- debug
197
- );
198
-
199
- }
200
-
201
- }
202
- );
203
-
204
- };
@@ -1,338 +0,0 @@
1
- import { normalizePath } from '../core/normalizer';
2
- import { SenzorOptions } from '../core/types';
3
- import { hookRequire } from './hook';
4
- import { patchMethod } from './patch';
5
- import { invokeWithFrameworkSpan } from './framework';
6
-
7
- const LAYER_PATCHED = Symbol.for('senzor.express.layer.patched');
8
-
9
- const routeMethods = new Set([
10
- 'checkout',
11
- 'copy',
12
- 'delete',
13
- 'get',
14
- 'head',
15
- 'lock',
16
- 'merge',
17
- 'mkactivity',
18
- 'mkcol',
19
- 'move',
20
- 'm-search',
21
- 'notify',
22
- 'options',
23
- 'patch',
24
- 'post',
25
- 'purge',
26
- 'put',
27
- 'report',
28
- 'search',
29
- 'subscribe',
30
- 'trace',
31
- 'unlock',
32
- 'unsubscribe'
33
- ]);
34
-
35
- const stringifyPath = (value: unknown): string | undefined => {
36
- if (typeof value === 'string') return value;
37
- if (value instanceof RegExp) return value.toString();
38
- if (Array.isArray(value)) {
39
- return value.map(stringifyPath).filter(Boolean).join(',');
40
- }
41
- if (typeof value === 'number') return String(value);
42
- return undefined;
43
- };
44
-
45
- const getLayerPath = (args: any[]): string | undefined => {
46
- for (const arg of args) {
47
- if (typeof arg === 'function') return undefined;
48
- const path = stringifyPath(arg);
49
- if (path) return path;
50
- }
51
-
52
- return undefined;
53
- };
54
-
55
- const getRequestRoute = (
56
- req: any,
57
- layer: any,
58
- layerPath?: string
59
- ): string | undefined => {
60
- const routePath = stringifyPath(layer?.route?.path);
61
- if (routePath) {
62
- const baseUrl = req?.baseUrl || '';
63
- return `${baseUrl}${routePath}` || routePath;
64
- }
65
-
66
- if (req?.route?.path) {
67
- return `${req.baseUrl || ''}${req.route.path}`;
68
- }
69
-
70
- if (layerPath) {
71
- const baseUrl = req?.baseUrl || '';
72
- return `${baseUrl}${layerPath}` || layerPath;
73
- }
74
-
75
- const path = req?.originalUrl || req?.url || req?.path;
76
- return path ? normalizePath(String(path).split('?')[0]) : undefined;
77
- };
78
-
79
- const getLayerType = (
80
- layer: any,
81
- original: Function,
82
- forcedType?: 'middleware' | 'router' | 'request_handler' | 'error_handler'
83
- ) => {
84
- if (forcedType) return forcedType;
85
- if (original.length === 4) return 'error_handler' as const;
86
- if (layer?.route) return 'request_handler' as const;
87
- if (layer?.name === 'router' || layer?.handle?.stack || layer?.handle?.name === 'router') {
88
- return 'router' as const;
89
- }
90
- return 'middleware' as const;
91
- };
92
-
93
- const getRouteMethod = (layer: any, req: any): string | undefined => {
94
- if (layer?.route?.methods) {
95
- const method = Object.keys(layer.route.methods).find(
96
- (candidate) => layer.route.methods[candidate]
97
- );
98
- if (method) return method.toUpperCase();
99
- }
100
-
101
- return req?.method;
102
- };
103
-
104
- const copyEnumerableProperties = (
105
- source: Function,
106
- target: Function
107
- ) => {
108
- for (const key in source as any) {
109
- try {
110
- Object.defineProperty(target, key, {
111
- configurable: true,
112
- enumerable: true,
113
- get() {
114
- return (source as any)[key];
115
- },
116
- set(value) {
117
- (source as any)[key] = value;
118
- }
119
- });
120
- } catch { }
121
- }
122
- };
123
-
124
- const patchLayer = (
125
- layer: any,
126
- layerPath: string | undefined,
127
- options?: SenzorOptions,
128
- forcedType?: 'middleware' | 'router' | 'request_handler' | 'error_handler'
129
- ) => {
130
- if (!layer || layer[LAYER_PATCHED] || typeof layer.handle !== 'function') {
131
- return;
132
- }
133
-
134
- Object.defineProperty(layer, LAYER_PATCHED, {
135
- value: true,
136
- enumerable: false
137
- });
138
-
139
- patchMethod(
140
- layer,
141
- 'handle',
142
- 'senzor.express.layer.handle',
143
- (original) => {
144
- const layerType = getLayerType(layer, original, forcedType);
145
- const handlerName =
146
- original.name ||
147
- layer.name ||
148
- layerType;
149
-
150
- if (original.length === 4) {
151
- const wrapped = function senzorExpressErrorHandler(
152
- this: unknown,
153
- err: any,
154
- req: any,
155
- res: any,
156
- next: Function
157
- ) {
158
- const route = getRequestRoute(req, layer, layerPath);
159
- return invokeWithFrameworkSpan(
160
- original,
161
- this,
162
- [err, req, res, next],
163
- {
164
- framework: 'express',
165
- type: 'error_handler',
166
- name: `express.error_handler ${route || handlerName}`,
167
- route,
168
- method: getRouteMethod(layer, req),
169
- layerPath,
170
- handlerName,
171
- request: req,
172
- response: res,
173
- attributes: {
174
- 'express.type': 'error_handler',
175
- 'express.layer.name': layer.name,
176
- error: err?.message,
177
- 'error.type': err?.name || typeof err
178
- }
179
- },
180
- options,
181
- {
182
- callbackIndex: 3,
183
- callbackCompletesSpan: true,
184
- responseEndsSpan: true
185
- }
186
- );
187
- };
188
-
189
- copyEnumerableProperties(original, wrapped);
190
- return wrapped;
191
- }
192
-
193
- const wrapped = function senzorExpressLayer(
194
- this: unknown,
195
- req: any,
196
- res: any,
197
- next: Function
198
- ) {
199
- const route = getRequestRoute(req, layer, layerPath);
200
- const method = getRouteMethod(layer, req);
201
- const displayRoute = route || layerPath || handlerName;
202
- const name =
203
- layerType === 'request_handler'
204
- ? `express.request_handler ${method || ''} ${displayRoute}`.trim()
205
- : `express.${layerType} ${displayRoute}`;
206
-
207
- return invokeWithFrameworkSpan(
208
- original,
209
- this,
210
- [req, res, next],
211
- {
212
- framework: 'express',
213
- type: layerType,
214
- name,
215
- route,
216
- method,
217
- layerPath,
218
- handlerName,
219
- request: req,
220
- response: res,
221
- attributes: {
222
- 'express.type': layerType,
223
- 'express.layer.name': layer.name,
224
- 'http.route': route
225
- }
226
- },
227
- options,
228
- {
229
- callbackIndex: 2,
230
- callbackCompletesSpan: true,
231
- responseEndsSpan: true
232
- }
233
- );
234
- };
235
-
236
- copyEnumerableProperties(original, wrapped);
237
- return wrapped;
238
- }
239
- );
240
- };
241
-
242
- const patchRouteMethodHandlers = (
243
- route: any,
244
- routePath: string | undefined,
245
- options?: SenzorOptions
246
- ) => {
247
- if (!route || route.__senzorRouteMethodsPatched) return;
248
-
249
- Object.defineProperty(route, '__senzorRouteMethodsPatched', {
250
- value: true,
251
- enumerable: false
252
- });
253
-
254
- for (const method of routeMethods) {
255
- if (typeof route[method] !== 'function') continue;
256
-
257
- patchMethod(
258
- route,
259
- method,
260
- `senzor.express.route.${method}`,
261
- (original) =>
262
- function patchedExpressRouteMethod(this: any, ...args: any[]) {
263
- const result = original.apply(this, args);
264
- const stack = this?.stack || [];
265
-
266
- for (const layer of stack) {
267
- patchLayer(layer, routePath, options, 'request_handler');
268
- }
269
-
270
- return result;
271
- }
272
- );
273
- }
274
- };
275
-
276
- const patchExpress = (
277
- expressModule: any,
278
- options?: SenzorOptions
279
- ) => {
280
- if (!expressModule) return;
281
-
282
- const routerProto =
283
- typeof expressModule?.Router?.prototype?.route === 'function'
284
- ? expressModule.Router.prototype
285
- : expressModule.Router;
286
-
287
- patchMethod(
288
- routerProto,
289
- 'route',
290
- 'senzor.express.router.route',
291
- (original) =>
292
- function patchedExpressRoute(this: any, ...args: any[]) {
293
- const route = original.apply(this, args);
294
- const routePath = getLayerPath(args);
295
- const layer = this?.stack?.[this.stack.length - 1];
296
-
297
- patchLayer(layer, routePath, options, 'router');
298
- patchRouteMethodHandlers(route, routePath, options);
299
-
300
- return route;
301
- }
302
- );
303
-
304
- patchMethod(
305
- routerProto,
306
- 'use',
307
- 'senzor.express.router.use',
308
- (original) =>
309
- function patchedExpressRouterUse(this: any, ...args: any[]) {
310
- const result = original.apply(this, args);
311
- const layer = this?.stack?.[this.stack.length - 1];
312
- patchLayer(layer, getLayerPath(args), options);
313
- return result;
314
- }
315
- );
316
-
317
- patchMethod(
318
- expressModule.application,
319
- 'use',
320
- 'senzor.express.application.use',
321
- (original) =>
322
- function patchedExpressApplicationUse(this: any, ...args: any[]) {
323
- const router = this?.router || this?._router;
324
- const result = original.apply(this, args);
325
- const activeRouter = this?.router || this?._router || router;
326
- const layer = activeRouter?.stack?.[activeRouter.stack.length - 1];
327
- patchLayer(layer, getLayerPath(args), options);
328
- return result;
329
- }
330
- );
331
- };
332
-
333
- export const instrumentExpress = (options?: SenzorOptions) => {
334
- hookRequire('express', (exports: any) => {
335
- patchExpress(exports, options);
336
- if (exports?.default) patchExpress(exports.default, options);
337
- });
338
- };