@senzops/apm-node 1.2.7 → 1.3.0
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 +9 -0
- package/README.md +479 -398
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -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/core/client.ts +57 -0
- package/src/core/context.ts +71 -9
- package/src/core/transport.ts +20 -3
- package/src/core/types.ts +5 -1
- package/src/index.ts +4 -0
- package/src/instrumentation/amqplib.ts +371 -0
- package/src/instrumentation/anthropic.ts +245 -0
- package/src/instrumentation/aws-sdk.ts +403 -0
- package/src/instrumentation/azure-openai.ts +177 -0
- package/src/instrumentation/bunyan.ts +93 -0
- package/src/instrumentation/cassandra.ts +367 -0
- package/src/instrumentation/cohere.ts +227 -0
- package/src/instrumentation/connect.ts +200 -0
- package/src/instrumentation/dataloader.ts +291 -0
- package/src/instrumentation/dns.ts +220 -0
- package/src/instrumentation/firebase.ts +445 -0
- package/src/instrumentation/fs.ts +260 -0
- package/src/instrumentation/generic-pool.ts +317 -0
- package/src/instrumentation/google-genai.ts +426 -0
- package/src/instrumentation/graphql.ts +434 -0
- package/src/instrumentation/grpc.ts +666 -0
- package/src/instrumentation/hapi.ts +257 -0
- package/src/instrumentation/kafka.ts +360 -0
- package/src/instrumentation/knex.ts +249 -0
- package/src/instrumentation/lru-memoizer.ts +175 -0
- package/src/instrumentation/memcached.ts +190 -0
- package/src/instrumentation/mistral.ts +254 -0
- package/src/instrumentation/nestjs.ts +243 -0
- package/src/instrumentation/net.ts +171 -0
- package/src/instrumentation/openai.ts +281 -0
- package/src/instrumentation/pino.ts +170 -0
- package/src/instrumentation/restify.ts +213 -0
- package/src/instrumentation/runtime.ts +352 -0
- package/src/instrumentation/socketio.ts +272 -0
- package/src/instrumentation/tedious.ts +509 -0
- package/src/instrumentation/winston.ts +149 -0
- package/src/register.ts +22 -3
- package/src/wrappers/lambda.ts +417 -0
- package/tsup.config.ts +3 -3
- package/wiki.md +1547 -852
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { SenzorOptions } from '../core/types';
|
|
2
|
+
import { hookRequire } from './hook';
|
|
3
|
+
import { patchMethod } from './patch';
|
|
4
|
+
import { runWithCapturedSpan, startCapturedSpan } from './span';
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// generic-pool Instrumentation
|
|
8
|
+
//
|
|
9
|
+
// Instruments the `generic-pool` package — the de-facto connection/resource
|
|
10
|
+
// pooling library used by many database drivers (pg, mysql2, tedious),
|
|
11
|
+
// cache clients, and custom resource managers in Node.js.
|
|
12
|
+
//
|
|
13
|
+
// Patches Pool.prototype methods:
|
|
14
|
+
// - acquire() — resource acquisition from the pool
|
|
15
|
+
// - release() — resource return to the pool
|
|
16
|
+
// - destroy() — resource destruction
|
|
17
|
+
// - drain() — pool draining (graceful shutdown)
|
|
18
|
+
//
|
|
19
|
+
// These spans measure pool health and contention:
|
|
20
|
+
// - How long acquire() takes reveals pool exhaustion
|
|
21
|
+
// - Release/destroy patterns show resource lifecycle
|
|
22
|
+
//
|
|
23
|
+
// Captured attributes:
|
|
24
|
+
// - pool.type: 'generic-pool'
|
|
25
|
+
// - pool.operation: acquire, release, destroy, drain
|
|
26
|
+
// - pool.size: current pool size
|
|
27
|
+
// - pool.available: available resources
|
|
28
|
+
// - pool.pending: pending acquisition requests
|
|
29
|
+
// - pool.max: maximum pool size
|
|
30
|
+
// - pool.min: minimum pool size
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/** Extract pool stats from a generic-pool Pool instance. */
|
|
34
|
+
const getPoolStats = (pool: any): Record<string, any> => {
|
|
35
|
+
const stats: Record<string, any> = {
|
|
36
|
+
'pool.type': 'generic-pool',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
if (typeof pool.size !== 'undefined') stats['pool.size'] = pool.size;
|
|
41
|
+
if (typeof pool.available !== 'undefined') stats['pool.available'] = pool.available;
|
|
42
|
+
if (typeof pool.pending !== 'undefined') stats['pool.pending'] = pool.pending;
|
|
43
|
+
if (typeof pool.borrowed !== 'undefined') stats['pool.borrowed'] = pool.borrowed;
|
|
44
|
+
if (pool.max !== undefined) stats['pool.max'] = pool.max;
|
|
45
|
+
if (pool.min !== undefined) stats['pool.min'] = pool.min;
|
|
46
|
+
|
|
47
|
+
// Try _config for older versions
|
|
48
|
+
if (pool._config) {
|
|
49
|
+
if (stats['pool.max'] === undefined && pool._config.max) stats['pool.max'] = pool._config.max;
|
|
50
|
+
if (stats['pool.min'] === undefined && pool._config.min) stats['pool.min'] = pool._config.min;
|
|
51
|
+
}
|
|
52
|
+
} catch { }
|
|
53
|
+
|
|
54
|
+
return stats;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Pool method patching
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
const patchPool = (poolProto: any, options?: SenzorOptions) => {
|
|
62
|
+
if (!poolProto) return;
|
|
63
|
+
|
|
64
|
+
// --- acquire(priority?) → Promise<resource> ---
|
|
65
|
+
patchMethod(
|
|
66
|
+
poolProto,
|
|
67
|
+
'acquire',
|
|
68
|
+
'senzor.generic-pool.pool.acquire',
|
|
69
|
+
(original) =>
|
|
70
|
+
function patchedAcquire(this: any, ...args: any[]) {
|
|
71
|
+
const poolStats = getPoolStats(this);
|
|
72
|
+
|
|
73
|
+
const span = startCapturedSpan(
|
|
74
|
+
'Pool acquire',
|
|
75
|
+
'custom',
|
|
76
|
+
{
|
|
77
|
+
...poolStats,
|
|
78
|
+
'pool.operation': 'acquire',
|
|
79
|
+
library: 'generic-pool',
|
|
80
|
+
},
|
|
81
|
+
options
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (!span) return original.apply(this, args);
|
|
85
|
+
|
|
86
|
+
return runWithCapturedSpan(span, () => {
|
|
87
|
+
try {
|
|
88
|
+
const result = original.apply(this, args);
|
|
89
|
+
|
|
90
|
+
if (result && typeof result.then === 'function') {
|
|
91
|
+
return result.then(
|
|
92
|
+
(resource: any) => {
|
|
93
|
+
// Capture pool state after acquisition
|
|
94
|
+
const postStats = getPoolStats(this);
|
|
95
|
+
span.end(0, {
|
|
96
|
+
'pool.size_after': postStats['pool.size'],
|
|
97
|
+
'pool.available_after': postStats['pool.available'],
|
|
98
|
+
'pool.pending_after': postStats['pool.pending'],
|
|
99
|
+
});
|
|
100
|
+
return resource;
|
|
101
|
+
},
|
|
102
|
+
(error: any) => {
|
|
103
|
+
span.end(500, {
|
|
104
|
+
'error.message': error?.message,
|
|
105
|
+
'error.type': error?.name || 'PoolError',
|
|
106
|
+
});
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
span.end(0);
|
|
113
|
+
return result;
|
|
114
|
+
} catch (error: any) {
|
|
115
|
+
span.end(500, {
|
|
116
|
+
'error.message': error?.message,
|
|
117
|
+
'error.type': error?.name || 'Error',
|
|
118
|
+
});
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// --- release(resource) → Promise<void> ---
|
|
126
|
+
patchMethod(
|
|
127
|
+
poolProto,
|
|
128
|
+
'release',
|
|
129
|
+
'senzor.generic-pool.pool.release',
|
|
130
|
+
(original) =>
|
|
131
|
+
function patchedRelease(this: any, resource: any) {
|
|
132
|
+
const poolStats = getPoolStats(this);
|
|
133
|
+
|
|
134
|
+
const span = startCapturedSpan(
|
|
135
|
+
'Pool release',
|
|
136
|
+
'custom',
|
|
137
|
+
{
|
|
138
|
+
...poolStats,
|
|
139
|
+
'pool.operation': 'release',
|
|
140
|
+
library: 'generic-pool',
|
|
141
|
+
},
|
|
142
|
+
options
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (!span) return original.call(this, resource);
|
|
146
|
+
|
|
147
|
+
return runWithCapturedSpan(span, () => {
|
|
148
|
+
try {
|
|
149
|
+
const result = original.call(this, resource);
|
|
150
|
+
|
|
151
|
+
if (result && typeof result.then === 'function') {
|
|
152
|
+
return result.then(
|
|
153
|
+
(value: any) => { span.end(0); return value; },
|
|
154
|
+
(error: any) => {
|
|
155
|
+
span.end(500, { 'error.message': error?.message });
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
span.end(0);
|
|
162
|
+
return result;
|
|
163
|
+
} catch (error: any) {
|
|
164
|
+
span.end(500, { 'error.message': error?.message });
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// --- destroy(resource) → Promise<void> ---
|
|
172
|
+
patchMethod(
|
|
173
|
+
poolProto,
|
|
174
|
+
'destroy',
|
|
175
|
+
'senzor.generic-pool.pool.destroy',
|
|
176
|
+
(original) =>
|
|
177
|
+
function patchedDestroy(this: any, resource: any) {
|
|
178
|
+
const poolStats = getPoolStats(this);
|
|
179
|
+
|
|
180
|
+
const span = startCapturedSpan(
|
|
181
|
+
'Pool destroy',
|
|
182
|
+
'custom',
|
|
183
|
+
{
|
|
184
|
+
...poolStats,
|
|
185
|
+
'pool.operation': 'destroy',
|
|
186
|
+
library: 'generic-pool',
|
|
187
|
+
},
|
|
188
|
+
options
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
if (!span) return original.call(this, resource);
|
|
192
|
+
|
|
193
|
+
return runWithCapturedSpan(span, () => {
|
|
194
|
+
try {
|
|
195
|
+
const result = original.call(this, resource);
|
|
196
|
+
|
|
197
|
+
if (result && typeof result.then === 'function') {
|
|
198
|
+
return result.then(
|
|
199
|
+
(value: any) => { span.end(0); return value; },
|
|
200
|
+
(error: any) => {
|
|
201
|
+
span.end(500, { 'error.message': error?.message });
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
span.end(0);
|
|
208
|
+
return result;
|
|
209
|
+
} catch (error: any) {
|
|
210
|
+
span.end(500, { 'error.message': error?.message });
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// --- drain() → Promise<void> ---
|
|
218
|
+
if (typeof poolProto.drain === 'function') {
|
|
219
|
+
patchMethod(
|
|
220
|
+
poolProto,
|
|
221
|
+
'drain',
|
|
222
|
+
'senzor.generic-pool.pool.drain',
|
|
223
|
+
(original) =>
|
|
224
|
+
function patchedDrain(this: any) {
|
|
225
|
+
const poolStats = getPoolStats(this);
|
|
226
|
+
|
|
227
|
+
const span = startCapturedSpan(
|
|
228
|
+
'Pool drain',
|
|
229
|
+
'custom',
|
|
230
|
+
{
|
|
231
|
+
...poolStats,
|
|
232
|
+
'pool.operation': 'drain',
|
|
233
|
+
library: 'generic-pool',
|
|
234
|
+
},
|
|
235
|
+
options
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
if (!span) return original.call(this);
|
|
239
|
+
|
|
240
|
+
return runWithCapturedSpan(span, () => {
|
|
241
|
+
try {
|
|
242
|
+
const result = original.call(this);
|
|
243
|
+
|
|
244
|
+
if (result && typeof result.then === 'function') {
|
|
245
|
+
return result.then(
|
|
246
|
+
(value: any) => { span.end(0); return value; },
|
|
247
|
+
(error: any) => {
|
|
248
|
+
span.end(500, { 'error.message': error?.message });
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
span.end(0);
|
|
255
|
+
return result;
|
|
256
|
+
} catch (error: any) {
|
|
257
|
+
span.end(500, { 'error.message': error?.message });
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
// createPool factory wrapping
|
|
268
|
+
// ---------------------------------------------------------------------------
|
|
269
|
+
|
|
270
|
+
const patchCreatePool = (genericPool: any, options?: SenzorOptions) => {
|
|
271
|
+
if (typeof genericPool?.createPool !== 'function') return;
|
|
272
|
+
|
|
273
|
+
patchMethod(
|
|
274
|
+
genericPool,
|
|
275
|
+
'createPool',
|
|
276
|
+
'senzor.generic-pool.createPool',
|
|
277
|
+
(original) =>
|
|
278
|
+
function patchedCreatePool(this: any, factory: any, config: any) {
|
|
279
|
+
const pool = original.call(this, factory, config);
|
|
280
|
+
|
|
281
|
+
if (pool && !pool.__senzorPatched) {
|
|
282
|
+
const proto = Object.getPrototypeOf(pool);
|
|
283
|
+
if (proto && !proto.__senzorPatched) {
|
|
284
|
+
patchPool(proto, options);
|
|
285
|
+
proto.__senzorPatched = true;
|
|
286
|
+
}
|
|
287
|
+
pool.__senzorPatched = true;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return pool;
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
// Public API
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
export const instrumentGenericPool = (options?: SenzorOptions) => {
|
|
300
|
+
hookRequire('generic-pool', (exports: any) => {
|
|
301
|
+
// Patch the createPool factory
|
|
302
|
+
patchCreatePool(exports, options);
|
|
303
|
+
|
|
304
|
+
// Also try to find the Pool prototype directly
|
|
305
|
+
if (exports?.Pool?.prototype) {
|
|
306
|
+
patchPool(exports.Pool.prototype, options);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Handle default export
|
|
310
|
+
if (exports?.default) {
|
|
311
|
+
patchCreatePool(exports.default, options);
|
|
312
|
+
if (exports.default.Pool?.prototype) {
|
|
313
|
+
patchPool(exports.default.Pool.prototype, options);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
};
|