@sentienguard/apm 1.0.7 → 1.0.9
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/README.md +141 -141
- package/package.json +14 -2
- package/src/aggregator.js +465 -463
- package/src/browser/instrumentation.js +8 -3
- package/src/config.js +40 -0
- package/src/dependencies.js +374 -231
- package/src/errors.js +132 -132
- package/src/index.d.ts +113 -0
- package/src/index.js +233 -225
- package/src/instrumentation.js +10 -0
- package/src/mongodb.js +579 -397
- package/src/normalizer.js +9 -2
- package/src/openai.js +520 -520
- package/src/spanExporter.js +232 -0
- package/src/tracing.js +114 -0
package/src/dependencies.js
CHANGED
|
@@ -1,231 +1,374 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dependency Tracking
|
|
3
|
-
* Automatically times outgoing HTTP calls (fetch, axios, node http/https).
|
|
4
|
-
*
|
|
5
|
-
* For each dependency:
|
|
6
|
-
* - name (e.g., "OpenAI API", "api.example.com")
|
|
7
|
-
* - type (http, db, cache)
|
|
8
|
-
* - response time
|
|
9
|
-
* - error flag
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import http from 'http';
|
|
13
|
-
import https from 'https';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let
|
|
19
|
-
let
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
{ pattern: /
|
|
27
|
-
{ pattern: /
|
|
28
|
-
{ pattern: /
|
|
29
|
-
{ pattern: /
|
|
30
|
-
{ pattern: /
|
|
31
|
-
{ pattern: /
|
|
32
|
-
{ pattern: /
|
|
33
|
-
{ pattern: /
|
|
34
|
-
{ pattern: /
|
|
35
|
-
{ pattern: /
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Tracking
|
|
3
|
+
* Automatically times outgoing HTTP calls (fetch, axios, node http/https).
|
|
4
|
+
*
|
|
5
|
+
* For each dependency:
|
|
6
|
+
* - name (e.g., "OpenAI API", "api.example.com")
|
|
7
|
+
* - type (http, db, cache)
|
|
8
|
+
* - response time
|
|
9
|
+
* - error flag
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import http from 'http';
|
|
13
|
+
import https from 'https';
|
|
14
|
+
import { context, propagation } from '@opentelemetry/api';
|
|
15
|
+
import { getAggregator } from './aggregator.js';
|
|
16
|
+
import { debug, getConfig } from './config.js';
|
|
17
|
+
|
|
18
|
+
let isInstrumented = false;
|
|
19
|
+
let originalHttpRequest = null;
|
|
20
|
+
let originalHttpsRequest = null;
|
|
21
|
+
let originalFetch = null;
|
|
22
|
+
let isFetchInstrumented = false;
|
|
23
|
+
|
|
24
|
+
// Known service patterns for better naming
|
|
25
|
+
const KNOWN_SERVICES = [
|
|
26
|
+
{ pattern: /openai\.com/i, name: 'OpenAI API' },
|
|
27
|
+
{ pattern: /anthropic\.com/i, name: 'Anthropic API' },
|
|
28
|
+
{ pattern: /api\.stripe\.com/i, name: 'Stripe API' },
|
|
29
|
+
{ pattern: /api\.sendgrid\.com/i, name: 'SendGrid' },
|
|
30
|
+
{ pattern: /api\.twilio\.com/i, name: 'Twilio API' },
|
|
31
|
+
{ pattern: /s3\.amazonaws\.com/i, name: 'AWS S3' },
|
|
32
|
+
{ pattern: /dynamodb\..+\.amazonaws\.com/i, name: 'DynamoDB' },
|
|
33
|
+
{ pattern: /sqs\..+\.amazonaws\.com/i, name: 'AWS SQS' },
|
|
34
|
+
{ pattern: /sns\..+\.amazonaws\.com/i, name: 'AWS SNS' },
|
|
35
|
+
{ pattern: /mongodb\.net/i, name: 'MongoDB Atlas' },
|
|
36
|
+
{ pattern: /redis/i, name: 'Redis' },
|
|
37
|
+
{ pattern: /postgresql|postgres/i, name: 'PostgreSQL' },
|
|
38
|
+
{ pattern: /mysql/i, name: 'MySQL' }
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Label for outgoing HTTP dependency (matches spanExporter peer labels when tracing local services).
|
|
43
|
+
*/
|
|
44
|
+
function resolveOutgoingPeerLabel(hostname, options) {
|
|
45
|
+
const cfg = getConfig();
|
|
46
|
+
const h = (hostname || '').split(':')[0];
|
|
47
|
+
const isLocal = h === 'localhost' || h === '127.0.0.1' || h === '::1';
|
|
48
|
+
if (isLocal && cfg.tracing?.traceLocalHttp) {
|
|
49
|
+
let port = '';
|
|
50
|
+
if (typeof options === 'string') {
|
|
51
|
+
try {
|
|
52
|
+
const u = new URL(options);
|
|
53
|
+
port = u.port || (u.protocol === 'https:' ? '443' : '80');
|
|
54
|
+
} catch {
|
|
55
|
+
// ignore
|
|
56
|
+
}
|
|
57
|
+
} else if (options && typeof options === 'object') {
|
|
58
|
+
port = options.port ? String(options.port) : '';
|
|
59
|
+
}
|
|
60
|
+
const map = cfg.tracing?.peerServiceMap || {};
|
|
61
|
+
if (port && map[port]) return map[port];
|
|
62
|
+
if (port) return `localhost:${port}`;
|
|
63
|
+
}
|
|
64
|
+
return getServiceName(hostname);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Extract a friendly name from hostname
|
|
69
|
+
*/
|
|
70
|
+
function getServiceName(hostname) {
|
|
71
|
+
if (!hostname) return 'unknown';
|
|
72
|
+
|
|
73
|
+
// Check known services
|
|
74
|
+
for (const service of KNOWN_SERVICES) {
|
|
75
|
+
if (service.pattern.test(hostname)) {
|
|
76
|
+
return service.name;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Default to hostname
|
|
81
|
+
return hostname;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Determine dependency type from hostname/path
|
|
86
|
+
*/
|
|
87
|
+
function getDependencyType(hostname, path) {
|
|
88
|
+
const lowerHost = (hostname || '').toLowerCase();
|
|
89
|
+
|
|
90
|
+
// Database indicators
|
|
91
|
+
if (/mongodb|postgres|mysql|dynamodb|redis|memcache/i.test(lowerHost)) {
|
|
92
|
+
return 'db';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Cache indicators
|
|
96
|
+
if (/redis|memcache|elasticache/i.test(lowerHost)) {
|
|
97
|
+
return 'cache';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Storage indicators
|
|
101
|
+
if (/s3\.amazonaws|storage\.googleapis|blob\.core\.windows/i.test(lowerHost)) {
|
|
102
|
+
return 'storage';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Default to HTTP
|
|
106
|
+
return 'http';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Check if this request should be excluded from tracking
|
|
111
|
+
*/
|
|
112
|
+
function resolvePortFromOptions(optionsOrUrl) {
|
|
113
|
+
try {
|
|
114
|
+
if (!optionsOrUrl) return '';
|
|
115
|
+
if (optionsOrUrl instanceof URL) {
|
|
116
|
+
return optionsOrUrl.port || (optionsOrUrl.protocol === 'https:' ? '443' : '80');
|
|
117
|
+
}
|
|
118
|
+
if (typeof optionsOrUrl === 'string') {
|
|
119
|
+
const u = new URL(optionsOrUrl);
|
|
120
|
+
return u.port || (u.protocol === 'https:' ? '443' : '80');
|
|
121
|
+
}
|
|
122
|
+
if (typeof optionsOrUrl === 'object') {
|
|
123
|
+
if (optionsOrUrl.port) return String(optionsOrUrl.port);
|
|
124
|
+
// Node supports host like "localhost:3001"
|
|
125
|
+
const host = optionsOrUrl.host || optionsOrUrl.hostname || '';
|
|
126
|
+
if (typeof host === 'string') {
|
|
127
|
+
const idx = host.lastIndexOf(':');
|
|
128
|
+
if (idx > -1) return host.slice(idx + 1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
// ignore
|
|
133
|
+
}
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function resolvePortFromEndpoint(endpointUrl) {
|
|
138
|
+
if (!endpointUrl) return '';
|
|
139
|
+
return endpointUrl.port || (endpointUrl.protocol === 'https:' ? '443' : '80');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function shouldExclude(hostname, optionsOrUrl) {
|
|
143
|
+
const config = getConfig();
|
|
144
|
+
|
|
145
|
+
// Don't track our own APM endpoint
|
|
146
|
+
if (config.endpoint) {
|
|
147
|
+
try {
|
|
148
|
+
const endpointUrl = new URL(config.endpoint);
|
|
149
|
+
if (hostname === endpointUrl.hostname) {
|
|
150
|
+
const reqPort = resolvePortFromOptions(optionsOrUrl);
|
|
151
|
+
const ingestPort = resolvePortFromEndpoint(endpointUrl);
|
|
152
|
+
// If we can't determine request port, be conservative and exclude.
|
|
153
|
+
if (!reqPort || reqPort === ingestPort) return true;
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
// Invalid endpoint URL, continue
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const h = (hostname || '').toLowerCase();
|
|
161
|
+
const isLocal = h === 'localhost' || h === '127.0.0.1' || h === '::1';
|
|
162
|
+
// Exclude localhost unless tracing local HTTP peers (multi-service dev)
|
|
163
|
+
if (isLocal) return !config.tracing?.traceLocalHttp;
|
|
164
|
+
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function safeParseUrl(input) {
|
|
169
|
+
try {
|
|
170
|
+
return new URL(String(input));
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function shouldExcludeUrl(u) {
|
|
177
|
+
if (!u) return true;
|
|
178
|
+
return shouldExclude(u.hostname, u);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function injectTraceHeaders(init) {
|
|
182
|
+
const headers = new Headers((init && init.headers) || {});
|
|
183
|
+
try {
|
|
184
|
+
propagation.inject(context.active(), headers, {
|
|
185
|
+
set: (carrier, key, value) => {
|
|
186
|
+
carrier.set(key, value);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
} catch {
|
|
190
|
+
// ignore
|
|
191
|
+
}
|
|
192
|
+
return { ...(init || {}), headers };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Instrument global fetch (Node 18+ / undici) to record dependency edges.
|
|
197
|
+
* This is needed because OTel HttpInstrumentation doesn't always cover fetch.
|
|
198
|
+
*/
|
|
199
|
+
export function instrumentFetch() {
|
|
200
|
+
if (isFetchInstrumented) return;
|
|
201
|
+
const f = globalThis.fetch;
|
|
202
|
+
if (typeof f !== 'function') return;
|
|
203
|
+
originalFetch = f;
|
|
204
|
+
|
|
205
|
+
globalThis.fetch = async function sentienguardFetch(input, init) {
|
|
206
|
+
const u = safeParseUrl(typeof input === 'string' ? input : input?.url);
|
|
207
|
+
if (shouldExcludeUrl(u)) {
|
|
208
|
+
return originalFetch.call(this, input, init);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const startTime = process.hrtime.bigint();
|
|
212
|
+
const cfg = getConfig();
|
|
213
|
+
const caller = cfg.service || 'unknown';
|
|
214
|
+
const hostname = u?.hostname || '';
|
|
215
|
+
const peerLabel = resolveOutgoingPeerLabel(hostname, u ? u.toString() : '');
|
|
216
|
+
const depType = getDependencyType(hostname, u?.pathname || '/');
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const res = await originalFetch.call(this, input, injectTraceHeaders(init));
|
|
220
|
+
const endTime = process.hrtime.bigint();
|
|
221
|
+
const latencyMs = Number(endTime - startTime) / 1e6;
|
|
222
|
+
const isError = (res?.status || 0) >= 400;
|
|
223
|
+
getAggregator().recordDependency(peerLabel, depType, latencyMs, isError);
|
|
224
|
+
debug(`Service call: ${caller} -> ${peerLabel} ${latencyMs.toFixed(2)}ms (${depType}) ${res?.status}`);
|
|
225
|
+
return res;
|
|
226
|
+
} catch (err) {
|
|
227
|
+
const endTime = process.hrtime.bigint();
|
|
228
|
+
const latencyMs = Number(endTime - startTime) / 1e6;
|
|
229
|
+
getAggregator().recordDependency(peerLabel, depType, latencyMs, true);
|
|
230
|
+
debug(`Service call: ${caller} -> ${peerLabel} ${latencyMs.toFixed(2)}ms (${depType}) error`);
|
|
231
|
+
throw err;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
isFetchInstrumented = true;
|
|
236
|
+
debug('Fetch dependency instrumentation enabled');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Wrap http/https request to track dependencies
|
|
241
|
+
*/
|
|
242
|
+
function wrapRequest(original, protocol) {
|
|
243
|
+
return function instrumentedRequest(options, callback) {
|
|
244
|
+
// Parse options to get hostname
|
|
245
|
+
let hostname = '';
|
|
246
|
+
let path = '/';
|
|
247
|
+
|
|
248
|
+
if (typeof options === 'string') {
|
|
249
|
+
try {
|
|
250
|
+
const url = new URL(options);
|
|
251
|
+
hostname = url.hostname;
|
|
252
|
+
path = url.pathname;
|
|
253
|
+
} catch {
|
|
254
|
+
// Invalid URL
|
|
255
|
+
}
|
|
256
|
+
} else if (options) {
|
|
257
|
+
hostname = options.hostname || options.host || '';
|
|
258
|
+
path = options.path || '/';
|
|
259
|
+
// Remove port from host if present
|
|
260
|
+
hostname = hostname.split(':')[0];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Check exclusions
|
|
264
|
+
if (shouldExclude(hostname, options)) {
|
|
265
|
+
return original.apply(this, arguments);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const startTime = process.hrtime.bigint();
|
|
269
|
+
const peerLabel = resolveOutgoingPeerLabel(hostname, options);
|
|
270
|
+
const depType = getDependencyType(hostname, path);
|
|
271
|
+
const caller = getConfig().service || 'unknown';
|
|
272
|
+
|
|
273
|
+
// Call original
|
|
274
|
+
const req = original.apply(this, arguments);
|
|
275
|
+
|
|
276
|
+
// Track response
|
|
277
|
+
req.on('response', (res) => {
|
|
278
|
+
const endTime = process.hrtime.bigint();
|
|
279
|
+
const latencyMs = Number(endTime - startTime) / 1e6;
|
|
280
|
+
const isError = res.statusCode >= 400;
|
|
281
|
+
|
|
282
|
+
const aggregator = getAggregator();
|
|
283
|
+
aggregator.recordDependency(peerLabel, depType, latencyMs, isError);
|
|
284
|
+
|
|
285
|
+
debug(
|
|
286
|
+
`Service call: ${caller} -> ${peerLabel} ${latencyMs.toFixed(2)}ms (${depType}) ${res.statusCode}`
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Track errors
|
|
291
|
+
req.on('error', () => {
|
|
292
|
+
const endTime = process.hrtime.bigint();
|
|
293
|
+
const latencyMs = Number(endTime - startTime) / 1e6;
|
|
294
|
+
|
|
295
|
+
const aggregator = getAggregator();
|
|
296
|
+
aggregator.recordDependency(peerLabel, depType, latencyMs, true);
|
|
297
|
+
|
|
298
|
+
debug(`Service call: ${caller} -> ${peerLabel} ${latencyMs.toFixed(2)}ms (${depType}) error`);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
return req;
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Instrument outgoing HTTP requests
|
|
307
|
+
*/
|
|
308
|
+
export function instrumentDependencies() {
|
|
309
|
+
if (isInstrumented) {
|
|
310
|
+
debug('Dependencies already instrumented, skipping');
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Store originals
|
|
315
|
+
originalHttpRequest = http.request;
|
|
316
|
+
originalHttpsRequest = https.request;
|
|
317
|
+
|
|
318
|
+
// Patch http.request
|
|
319
|
+
http.request = wrapRequest(originalHttpRequest, 'http');
|
|
320
|
+
http.get = function (options, callback) {
|
|
321
|
+
const req = http.request(options, callback);
|
|
322
|
+
req.end();
|
|
323
|
+
return req;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// Patch https.request
|
|
327
|
+
https.request = wrapRequest(originalHttpsRequest, 'https');
|
|
328
|
+
https.get = function (options, callback) {
|
|
329
|
+
const req = https.request(options, callback);
|
|
330
|
+
req.end();
|
|
331
|
+
return req;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
isInstrumented = true;
|
|
335
|
+
debug('Dependency instrumentation enabled');
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Remove instrumentation (for testing/cleanup)
|
|
340
|
+
*/
|
|
341
|
+
export function uninstrumentDependencies() {
|
|
342
|
+
if (!isInstrumented) return;
|
|
343
|
+
|
|
344
|
+
if (originalHttpRequest) {
|
|
345
|
+
http.request = originalHttpRequest;
|
|
346
|
+
http.get = function (options, callback) {
|
|
347
|
+
const req = http.request(options, callback);
|
|
348
|
+
req.end();
|
|
349
|
+
return req;
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (originalHttpsRequest) {
|
|
354
|
+
https.request = originalHttpsRequest;
|
|
355
|
+
https.get = function (options, callback) {
|
|
356
|
+
const req = https.request(options, callback);
|
|
357
|
+
req.end();
|
|
358
|
+
return req;
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
isInstrumented = false;
|
|
363
|
+
debug('Dependency instrumentation disabled');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export { getServiceName, getDependencyType };
|
|
367
|
+
|
|
368
|
+
export default {
|
|
369
|
+
instrumentDependencies,
|
|
370
|
+
instrumentFetch,
|
|
371
|
+
uninstrumentDependencies,
|
|
372
|
+
getServiceName,
|
|
373
|
+
getDependencyType
|
|
374
|
+
};
|