@senzops/apm-node 1.2.8 → 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/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,291 @@
|
|
|
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
|
+
// DataLoader Instrumentation
|
|
8
|
+
//
|
|
9
|
+
// Instruments the `dataloader` package — the standard batching/caching
|
|
10
|
+
// utility for solving N+1 queries in GraphQL resolvers, REST APIs,
|
|
11
|
+
// and any data-fetching layer.
|
|
12
|
+
//
|
|
13
|
+
// Patches DataLoader.prototype methods:
|
|
14
|
+
// - load(key) — single key lookup (batched)
|
|
15
|
+
// - loadMany(keys) — multi-key lookup (batched)
|
|
16
|
+
// - prime(key, val) — cache priming
|
|
17
|
+
// - clear(key) — single cache eviction
|
|
18
|
+
// - clearAll() — full cache clear
|
|
19
|
+
//
|
|
20
|
+
// The key insight: load() calls are batched by DataLoader and dispatched
|
|
21
|
+
// together via the batch function. We instrument both the individual
|
|
22
|
+
// load() calls AND the batch dispatch to show:
|
|
23
|
+
// 1. Per-key latency (includes batching wait time)
|
|
24
|
+
// 2. Batch execution performance
|
|
25
|
+
//
|
|
26
|
+
// Captured attributes:
|
|
27
|
+
// - dataloader.operation: load, loadMany, prime, clear, clearAll, batch
|
|
28
|
+
// - dataloader.key_count: number of keys in the batch
|
|
29
|
+
// - dataloader.name: DataLoader instance name (if available)
|
|
30
|
+
// - dataloader.cache_hit: whether result came from cache
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// DataLoader prototype patching
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
const patchDataLoader = (DataLoader: any, options?: SenzorOptions) => {
|
|
38
|
+
const proto = DataLoader?.prototype;
|
|
39
|
+
if (!proto) return;
|
|
40
|
+
|
|
41
|
+
// --- load(key) → Promise<value> ---
|
|
42
|
+
patchMethod(
|
|
43
|
+
proto,
|
|
44
|
+
'load',
|
|
45
|
+
'senzor.dataloader.load',
|
|
46
|
+
(original) =>
|
|
47
|
+
function patchedLoad(this: any, key: any) {
|
|
48
|
+
const loaderName = this.name || this._name || 'DataLoader';
|
|
49
|
+
|
|
50
|
+
const span = startCapturedSpan(
|
|
51
|
+
`${loaderName} load`,
|
|
52
|
+
'function',
|
|
53
|
+
{
|
|
54
|
+
'dataloader.operation': 'load',
|
|
55
|
+
'dataloader.name': loaderName,
|
|
56
|
+
library: 'dataloader',
|
|
57
|
+
},
|
|
58
|
+
options
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
if (!span) return original.call(this, key);
|
|
62
|
+
|
|
63
|
+
return runWithCapturedSpan(span, () => {
|
|
64
|
+
try {
|
|
65
|
+
const result = original.call(this, key);
|
|
66
|
+
|
|
67
|
+
if (result && typeof result.then === 'function') {
|
|
68
|
+
return result.then(
|
|
69
|
+
(value: any) => {
|
|
70
|
+
span.end(0);
|
|
71
|
+
return value;
|
|
72
|
+
},
|
|
73
|
+
(error: any) => {
|
|
74
|
+
span.end(500, {
|
|
75
|
+
'error.message': error?.message,
|
|
76
|
+
'error.type': error?.name || 'Error',
|
|
77
|
+
});
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
span.end(0);
|
|
84
|
+
return result;
|
|
85
|
+
} catch (error: any) {
|
|
86
|
+
span.end(500, { 'error.message': error?.message });
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// --- loadMany(keys) → Promise<value[]> ---
|
|
94
|
+
patchMethod(
|
|
95
|
+
proto,
|
|
96
|
+
'loadMany',
|
|
97
|
+
'senzor.dataloader.loadMany',
|
|
98
|
+
(original) =>
|
|
99
|
+
function patchedLoadMany(this: any, keys: any[]) {
|
|
100
|
+
const loaderName = this.name || this._name || 'DataLoader';
|
|
101
|
+
const keyCount = Array.isArray(keys) ? keys.length : 0;
|
|
102
|
+
|
|
103
|
+
const span = startCapturedSpan(
|
|
104
|
+
`${loaderName} loadMany`,
|
|
105
|
+
'function',
|
|
106
|
+
{
|
|
107
|
+
'dataloader.operation': 'loadMany',
|
|
108
|
+
'dataloader.name': loaderName,
|
|
109
|
+
'dataloader.key_count': keyCount,
|
|
110
|
+
library: 'dataloader',
|
|
111
|
+
},
|
|
112
|
+
options
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (!span) return original.call(this, keys);
|
|
116
|
+
|
|
117
|
+
return runWithCapturedSpan(span, () => {
|
|
118
|
+
try {
|
|
119
|
+
const result = original.call(this, keys);
|
|
120
|
+
|
|
121
|
+
if (result && typeof result.then === 'function') {
|
|
122
|
+
return result.then(
|
|
123
|
+
(values: any) => {
|
|
124
|
+
// Count errors in results
|
|
125
|
+
const errorCount = Array.isArray(values)
|
|
126
|
+
? values.filter((v: any) => v instanceof Error).length
|
|
127
|
+
: 0;
|
|
128
|
+
|
|
129
|
+
span.end(errorCount > 0 ? 207 : 0, {
|
|
130
|
+
'dataloader.key_count': keyCount,
|
|
131
|
+
'dataloader.error_count': errorCount,
|
|
132
|
+
});
|
|
133
|
+
return values;
|
|
134
|
+
},
|
|
135
|
+
(error: any) => {
|
|
136
|
+
span.end(500, { 'error.message': error?.message });
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
span.end(0);
|
|
143
|
+
return result;
|
|
144
|
+
} catch (error: any) {
|
|
145
|
+
span.end(500, { 'error.message': error?.message });
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// --- Wrap the batch function dispatch ---
|
|
153
|
+
// DataLoader calls the batch function internally. We intercept it
|
|
154
|
+
// by wrapping the constructor or the internal _batchLoadFn.
|
|
155
|
+
// Since we can't easily wrap the constructor via patchMethod,
|
|
156
|
+
// we patch _batchScheduleFn or override the dispatch mechanism.
|
|
157
|
+
|
|
158
|
+
// Patch the internal _batch method if it exists
|
|
159
|
+
const batchMethodName = '_dispatchBatch' in proto
|
|
160
|
+
? '_dispatchBatch'
|
|
161
|
+
: '_dispatch' in proto
|
|
162
|
+
? '_dispatch'
|
|
163
|
+
: null;
|
|
164
|
+
|
|
165
|
+
if (batchMethodName && typeof proto[batchMethodName] === 'function') {
|
|
166
|
+
patchMethod(
|
|
167
|
+
proto,
|
|
168
|
+
batchMethodName,
|
|
169
|
+
`senzor.dataloader.${batchMethodName}`,
|
|
170
|
+
(original) =>
|
|
171
|
+
function patchedDispatch(this: any, ...args: any[]) {
|
|
172
|
+
const loaderName = this.name || this._name || 'DataLoader';
|
|
173
|
+
// The batch queue holds pending keys
|
|
174
|
+
const batchSize = this._queue?.length || this._batch?.length || 0;
|
|
175
|
+
|
|
176
|
+
const span = startCapturedSpan(
|
|
177
|
+
`${loaderName} batch dispatch`,
|
|
178
|
+
'function',
|
|
179
|
+
{
|
|
180
|
+
'dataloader.operation': 'batch',
|
|
181
|
+
'dataloader.name': loaderName,
|
|
182
|
+
'dataloader.batch_size': batchSize,
|
|
183
|
+
library: 'dataloader',
|
|
184
|
+
},
|
|
185
|
+
options
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
if (!span) return original.apply(this, args);
|
|
189
|
+
|
|
190
|
+
return runWithCapturedSpan(span, () => {
|
|
191
|
+
try {
|
|
192
|
+
const result = original.apply(this, args);
|
|
193
|
+
// Batch dispatch is sync; the batch function's promise
|
|
194
|
+
// is resolved internally. End span after dispatch.
|
|
195
|
+
span.end(0, { 'dataloader.batch_size': batchSize });
|
|
196
|
+
return result;
|
|
197
|
+
} catch (error: any) {
|
|
198
|
+
span.end(500, { 'error.message': error?.message });
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// --- prime(key, value) ---
|
|
207
|
+
if (typeof proto.prime === 'function') {
|
|
208
|
+
patchMethod(
|
|
209
|
+
proto,
|
|
210
|
+
'prime',
|
|
211
|
+
'senzor.dataloader.prime',
|
|
212
|
+
(original) =>
|
|
213
|
+
function patchedPrime(this: any, key: any, value: any) {
|
|
214
|
+
const loaderName = this.name || this._name || 'DataLoader';
|
|
215
|
+
|
|
216
|
+
const span = startCapturedSpan(
|
|
217
|
+
`${loaderName} prime`,
|
|
218
|
+
'function',
|
|
219
|
+
{
|
|
220
|
+
'dataloader.operation': 'prime',
|
|
221
|
+
'dataloader.name': loaderName,
|
|
222
|
+
library: 'dataloader',
|
|
223
|
+
},
|
|
224
|
+
options
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
if (!span) return original.call(this, key, value);
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const result = original.call(this, key, value);
|
|
231
|
+
span.end(0);
|
|
232
|
+
return result;
|
|
233
|
+
} catch (error: any) {
|
|
234
|
+
span.end(500, { 'error.message': error?.message });
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// --- clearAll() ---
|
|
242
|
+
if (typeof proto.clearAll === 'function') {
|
|
243
|
+
patchMethod(
|
|
244
|
+
proto,
|
|
245
|
+
'clearAll',
|
|
246
|
+
'senzor.dataloader.clearAll',
|
|
247
|
+
(original) =>
|
|
248
|
+
function patchedClearAll(this: any) {
|
|
249
|
+
const loaderName = this.name || this._name || 'DataLoader';
|
|
250
|
+
|
|
251
|
+
const span = startCapturedSpan(
|
|
252
|
+
`${loaderName} clearAll`,
|
|
253
|
+
'function',
|
|
254
|
+
{
|
|
255
|
+
'dataloader.operation': 'clearAll',
|
|
256
|
+
'dataloader.name': loaderName,
|
|
257
|
+
library: 'dataloader',
|
|
258
|
+
},
|
|
259
|
+
options
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
if (!span) return original.call(this);
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const result = original.call(this);
|
|
266
|
+
span.end(0);
|
|
267
|
+
return result;
|
|
268
|
+
} catch (error: any) {
|
|
269
|
+
span.end(500, { 'error.message': error?.message });
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
// Public API
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
export const instrumentDataloader = (options?: SenzorOptions) => {
|
|
282
|
+
hookRequire('dataloader', (exports: any) => {
|
|
283
|
+
// dataloader exports the constructor directly
|
|
284
|
+
patchDataLoader(exports, options);
|
|
285
|
+
|
|
286
|
+
// Handle default export (ESM interop)
|
|
287
|
+
if (exports?.default?.prototype) {
|
|
288
|
+
patchDataLoader(exports.default, options);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { SenzorOptions } from '../core/types';
|
|
2
|
+
import { patchMethod } from './patch';
|
|
3
|
+
import { runWithCapturedSpan, startCapturedSpan } from './span';
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// DNS Instrumentation
|
|
7
|
+
//
|
|
8
|
+
// Instruments Node.js core `dns` module:
|
|
9
|
+
// - dns.lookup() — resolves a hostname to an address (uses OS resolver)
|
|
10
|
+
// - dns.resolve() — resolves using DNS protocol (network call)
|
|
11
|
+
// - dns.resolve4() — A records
|
|
12
|
+
// - dns.resolve6() — AAAA records
|
|
13
|
+
// - dns.resolveMx() — MX records
|
|
14
|
+
// - dns.resolveTxt() — TXT records
|
|
15
|
+
// - dns.resolveSrv() — SRV records
|
|
16
|
+
// - dns.resolveCname() — CNAME records
|
|
17
|
+
// - dns.resolveNs() — NS records
|
|
18
|
+
// - dns.reverse() — reverse DNS lookup
|
|
19
|
+
//
|
|
20
|
+
// Follows OTel semantic conventions: dns.hostname, network.peer.address
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Patch a single DNS method that accepts (hostname, [options], callback).
|
|
25
|
+
*/
|
|
26
|
+
const patchDnsMethod = (
|
|
27
|
+
dnsModule: any,
|
|
28
|
+
methodName: string,
|
|
29
|
+
options?: SenzorOptions
|
|
30
|
+
) => {
|
|
31
|
+
patchMethod(
|
|
32
|
+
dnsModule,
|
|
33
|
+
methodName,
|
|
34
|
+
`senzor.dns.${methodName}`,
|
|
35
|
+
(original) =>
|
|
36
|
+
function patchedDnsMethod(this: any, ...args: any[]) {
|
|
37
|
+
// Extract hostname (always the first argument)
|
|
38
|
+
const hostname = typeof args[0] === 'string' ? args[0] : 'unknown';
|
|
39
|
+
|
|
40
|
+
const span = startCapturedSpan(
|
|
41
|
+
`DNS ${methodName}`,
|
|
42
|
+
'custom',
|
|
43
|
+
{
|
|
44
|
+
'dns.hostname': hostname,
|
|
45
|
+
'dns.operation': methodName,
|
|
46
|
+
},
|
|
47
|
+
options
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (!span) return original.apply(this, args);
|
|
51
|
+
|
|
52
|
+
// Find and wrap the callback (always the last argument)
|
|
53
|
+
const callbackIdx = args.findIndex(
|
|
54
|
+
(arg: any, idx: number) => typeof arg === 'function' && idx === args.length - 1
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (callbackIdx >= 0) {
|
|
58
|
+
const originalCallback = args[callbackIdx];
|
|
59
|
+
args[callbackIdx] = function wrappedDnsCallback(
|
|
60
|
+
err: NodeJS.ErrnoException | null,
|
|
61
|
+
...results: any[]
|
|
62
|
+
) {
|
|
63
|
+
if (err) {
|
|
64
|
+
span.end(500, {
|
|
65
|
+
'error.message': err.message,
|
|
66
|
+
'error.type': err.code || err.name || 'DnsError',
|
|
67
|
+
'dns.error_code': err.code,
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
// For lookup, first result is address, second is family
|
|
71
|
+
const meta: Record<string, any> = {};
|
|
72
|
+
if (methodName === 'lookup' && results[0]) {
|
|
73
|
+
meta['network.peer.address'] = results[0];
|
|
74
|
+
meta['dns.address_family'] = results[1] === 6 ? 'IPv6' : 'IPv4';
|
|
75
|
+
} else if (methodName === 'resolve4' || methodName === 'resolve6') {
|
|
76
|
+
meta['dns.result_count'] = Array.isArray(results[0]) ? results[0].length : 0;
|
|
77
|
+
} else if (methodName === 'resolve') {
|
|
78
|
+
meta['dns.result_count'] = Array.isArray(results[0]) ? results[0].length : 0;
|
|
79
|
+
}
|
|
80
|
+
span.end(0, meta);
|
|
81
|
+
}
|
|
82
|
+
return originalCallback.call(this, err, ...results);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return runWithCapturedSpan(span, () => {
|
|
87
|
+
try {
|
|
88
|
+
return original.apply(this, args);
|
|
89
|
+
} catch (error: any) {
|
|
90
|
+
span.end(500, {
|
|
91
|
+
'error.message': error?.message,
|
|
92
|
+
'error.type': error?.name || 'Error',
|
|
93
|
+
});
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Patch dns.promises methods (returns promises instead of using callbacks).
|
|
103
|
+
*/
|
|
104
|
+
const patchDnsPromisesMethod = (
|
|
105
|
+
promises: any,
|
|
106
|
+
methodName: string,
|
|
107
|
+
options?: SenzorOptions
|
|
108
|
+
) => {
|
|
109
|
+
patchMethod(
|
|
110
|
+
promises,
|
|
111
|
+
methodName,
|
|
112
|
+
`senzor.dns.promises.${methodName}`,
|
|
113
|
+
(original) =>
|
|
114
|
+
function patchedDnsPromiseMethod(this: any, ...args: any[]) {
|
|
115
|
+
const hostname = typeof args[0] === 'string' ? args[0] : 'unknown';
|
|
116
|
+
|
|
117
|
+
const span = startCapturedSpan(
|
|
118
|
+
`DNS ${methodName}`,
|
|
119
|
+
'custom',
|
|
120
|
+
{
|
|
121
|
+
'dns.hostname': hostname,
|
|
122
|
+
'dns.operation': methodName,
|
|
123
|
+
},
|
|
124
|
+
options
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (!span) return original.apply(this, args);
|
|
128
|
+
|
|
129
|
+
return runWithCapturedSpan(span, async () => {
|
|
130
|
+
try {
|
|
131
|
+
const result = await original.apply(this, args);
|
|
132
|
+
|
|
133
|
+
const meta: Record<string, any> = {};
|
|
134
|
+
if (methodName === 'lookup' && result) {
|
|
135
|
+
meta['network.peer.address'] = result.address;
|
|
136
|
+
meta['dns.address_family'] = result.family === 6 ? 'IPv6' : 'IPv4';
|
|
137
|
+
} else if (Array.isArray(result)) {
|
|
138
|
+
meta['dns.result_count'] = result.length;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
span.end(0, meta);
|
|
142
|
+
return result;
|
|
143
|
+
} catch (error: any) {
|
|
144
|
+
span.end(500, {
|
|
145
|
+
'error.message': error?.message,
|
|
146
|
+
'error.type': error?.code || error?.name || 'DnsError',
|
|
147
|
+
'dns.error_code': error?.code,
|
|
148
|
+
});
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Public API
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
export const instrumentDns = (options?: SenzorOptions) => {
|
|
161
|
+
let dns: any;
|
|
162
|
+
try {
|
|
163
|
+
dns = require('dns');
|
|
164
|
+
} catch {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!dns) return;
|
|
169
|
+
|
|
170
|
+
// Callback-based methods
|
|
171
|
+
const callbackMethods = [
|
|
172
|
+
'lookup',
|
|
173
|
+
'resolve',
|
|
174
|
+
'resolve4',
|
|
175
|
+
'resolve6',
|
|
176
|
+
'resolveMx',
|
|
177
|
+
'resolveTxt',
|
|
178
|
+
'resolveSrv',
|
|
179
|
+
'resolveCname',
|
|
180
|
+
'resolveNs',
|
|
181
|
+
'resolvePtr',
|
|
182
|
+
'resolveSoa',
|
|
183
|
+
'resolveNaptr',
|
|
184
|
+
'resolveCaa',
|
|
185
|
+
'reverse',
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
for (const method of callbackMethods) {
|
|
189
|
+
if (typeof dns[method] === 'function') {
|
|
190
|
+
patchDnsMethod(dns, method, options);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Promise-based methods (dns.promises / dns/promises)
|
|
195
|
+
const promises = dns.promises;
|
|
196
|
+
if (promises) {
|
|
197
|
+
const promiseMethods = [
|
|
198
|
+
'lookup',
|
|
199
|
+
'resolve',
|
|
200
|
+
'resolve4',
|
|
201
|
+
'resolve6',
|
|
202
|
+
'resolveMx',
|
|
203
|
+
'resolveTxt',
|
|
204
|
+
'resolveSrv',
|
|
205
|
+
'resolveCname',
|
|
206
|
+
'resolveNs',
|
|
207
|
+
'resolvePtr',
|
|
208
|
+
'resolveSoa',
|
|
209
|
+
'resolveNaptr',
|
|
210
|
+
'resolveCaa',
|
|
211
|
+
'reverse',
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
for (const method of promiseMethods) {
|
|
215
|
+
if (typeof promises[method] === 'function') {
|
|
216
|
+
patchDnsPromisesMethod(promises, method, options);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|