@pingops/otel 0.1.2 → 0.2.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/dist/index.cjs +95 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -31
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +29 -31
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +96 -89
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.d.mts
CHANGED
|
@@ -55,6 +55,26 @@ interface PingopsProcessorConfig {
|
|
|
55
55
|
* Capture response body.
|
|
56
56
|
*/
|
|
57
57
|
captureResponseBody?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Maximum size of request body to capture (bytes).
|
|
60
|
+
* Applies to both `http` and `undici` instrumentations.
|
|
61
|
+
*
|
|
62
|
+
* Note: this is the number of raw bytes observed at the instrumentation layer.
|
|
63
|
+
* For compressed bodies, this is the compressed size.
|
|
64
|
+
*
|
|
65
|
+
* @defaultValue 4096 (4 KB)
|
|
66
|
+
*/
|
|
67
|
+
maxRequestBodySize?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Maximum size of response body to capture (bytes).
|
|
70
|
+
* Applies to both `http` and `undici` instrumentations.
|
|
71
|
+
*
|
|
72
|
+
* Note: this is the number of raw bytes observed at the instrumentation layer.
|
|
73
|
+
* For compressed bodies, this is the compressed size.
|
|
74
|
+
*
|
|
75
|
+
* @defaultValue 4096 (4 KB)
|
|
76
|
+
*/
|
|
77
|
+
maxResponseBodySize?: number;
|
|
58
78
|
/**
|
|
59
79
|
* Domain allow list rules.
|
|
60
80
|
*/
|
|
@@ -167,33 +187,16 @@ declare function shutdownTracerProvider(): Promise<void>;
|
|
|
167
187
|
/**
|
|
168
188
|
* Registers instrumentations for Node.js environment.
|
|
169
189
|
* This function is idempotent and can be called multiple times safely.
|
|
190
|
+
* When the SDK is initialized, all HTTP requests are instrumented.
|
|
170
191
|
*
|
|
171
|
-
* Instrumentation behavior:
|
|
172
|
-
* - If global instrumentation is enabled: all HTTP requests are instrumented
|
|
173
|
-
* - If global instrumentation is NOT enabled: only requests within wrapHttp blocks are instrumented
|
|
174
|
-
*
|
|
175
|
-
* @param isGlobalInstrumentationEnabled - Function that checks if global instrumentation is enabled
|
|
176
192
|
* @returns Array of Instrumentation instances
|
|
177
193
|
*/
|
|
178
|
-
declare function getInstrumentations(
|
|
194
|
+
declare function getInstrumentations(): Instrumentation[];
|
|
179
195
|
//#endregion
|
|
180
196
|
//#region src/instrumentations/http/pingops-http.d.ts
|
|
181
197
|
declare const PingopsSemanticAttributes: {
|
|
182
198
|
HTTP_REQUEST_BODY: string;
|
|
183
199
|
HTTP_RESPONSE_BODY: string;
|
|
184
|
-
NETWORK_DNS_LOOKUP_DURATION: string;
|
|
185
|
-
NETWORK_TCP_CONNECT_DURATION: string;
|
|
186
|
-
NETWORK_TLS_HANDSHAKE_DURATION: string;
|
|
187
|
-
NETWORK_TTFB_DURATION: string;
|
|
188
|
-
NETWORK_CONTENT_TRANSFER_DURATION: string;
|
|
189
|
-
};
|
|
190
|
-
type NetworkTimings = {
|
|
191
|
-
startAt?: number;
|
|
192
|
-
dnsLookupAt?: number;
|
|
193
|
-
tcpConnectionAt?: number;
|
|
194
|
-
tlsHandshakeAt?: number;
|
|
195
|
-
firstByteAt?: number;
|
|
196
|
-
endAt?: number;
|
|
197
200
|
};
|
|
198
201
|
interface PingopsInstrumentationConfig {
|
|
199
202
|
/**
|
|
@@ -210,11 +213,6 @@ interface PingopsInstrumentationConfig {
|
|
|
210
213
|
declare const PingopsHttpSemanticAttributes: {
|
|
211
214
|
HTTP_REQUEST_BODY: string;
|
|
212
215
|
HTTP_RESPONSE_BODY: string;
|
|
213
|
-
NETWORK_DNS_LOOKUP_DURATION: string;
|
|
214
|
-
NETWORK_TCP_CONNECT_DURATION: string;
|
|
215
|
-
NETWORK_TLS_HANDSHAKE_DURATION: string;
|
|
216
|
-
NETWORK_TTFB_DURATION: string;
|
|
217
|
-
NETWORK_CONTENT_TRANSFER_DURATION: string;
|
|
218
216
|
};
|
|
219
217
|
interface PingopsHttpInstrumentationConfig extends HttpInstrumentationConfig, PingopsInstrumentationConfig {}
|
|
220
218
|
declare class PingopsHttpInstrumentation extends HttpInstrumentation {
|
|
@@ -226,13 +224,13 @@ declare class PingopsHttpInstrumentation extends HttpInstrumentation {
|
|
|
226
224
|
//#endregion
|
|
227
225
|
//#region src/instrumentations/http/http.d.ts
|
|
228
226
|
/**
|
|
229
|
-
* Creates an HTTP instrumentation instance
|
|
227
|
+
* Creates an HTTP instrumentation instance.
|
|
228
|
+
* All outgoing HTTP requests are instrumented when the SDK is initialized.
|
|
230
229
|
*
|
|
231
|
-
* @param isGlobalInstrumentationEnabled - Function that checks if global instrumentation is enabled
|
|
232
230
|
* @param config - Optional configuration for the instrumentation
|
|
233
231
|
* @returns PingopsHttpInstrumentation instance
|
|
234
232
|
*/
|
|
235
|
-
declare function createHttpInstrumentation(
|
|
233
|
+
declare function createHttpInstrumentation(config?: Partial<PingopsHttpInstrumentationConfig>): PingopsHttpInstrumentation;
|
|
236
234
|
//#endregion
|
|
237
235
|
//#region src/instrumentations/undici/types.d.ts
|
|
238
236
|
interface UndiciRequest {
|
|
@@ -331,12 +329,12 @@ declare class UndiciInstrumentation extends InstrumentationBase<UndiciInstrument
|
|
|
331
329
|
//#endregion
|
|
332
330
|
//#region src/instrumentations/undici/undici.d.ts
|
|
333
331
|
/**
|
|
334
|
-
* Creates an Undici instrumentation instance
|
|
332
|
+
* Creates an Undici instrumentation instance.
|
|
333
|
+
* All requests are instrumented when the SDK is initialized.
|
|
335
334
|
*
|
|
336
|
-
* @param isGlobalInstrumentationEnabled - Function that checks if global instrumentation is enabled
|
|
337
335
|
* @returns UndiciInstrumentation instance
|
|
338
336
|
*/
|
|
339
|
-
declare function createUndiciInstrumentation(
|
|
337
|
+
declare function createUndiciInstrumentation(): UndiciInstrumentation;
|
|
340
338
|
//#endregion
|
|
341
|
-
export {
|
|
339
|
+
export { PingopsHttpInstrumentation, type PingopsHttpInstrumentationConfig, PingopsHttpSemanticAttributes, type PingopsInstrumentationConfig, type PingopsProcessorConfig, PingopsSemanticAttributes, PingopsSpanProcessor, createHttpInstrumentation, createUndiciInstrumentation, getInstrumentations, getPingopsTracerProvider, setPingopsTracerProvider, shutdownTracerProvider };
|
|
342
340
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config.ts","../src/span-processor.ts","../src/tracer-provider.ts","../src/instrumentations/index.ts","../src/instrumentations/http/pingops-http.ts","../src/instrumentations/http/http.ts","../src/instrumentations/undici/types.ts","../src/instrumentations/undici/pingops-undici.ts","../src/instrumentations/undici/undici.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;AAgBA;AAKA;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config.ts","../src/span-processor.ts","../src/tracer-provider.ts","../src/instrumentations/index.ts","../src/instrumentations/http/pingops-http.ts","../src/instrumentations/http/http.ts","../src/instrumentations/undici/types.ts","../src/instrumentations/undici/pingops-undici.ts","../src/instrumentations/undici/undici.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BatchSpanProcessor, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
2
2
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
3
|
-
import { PINGOPS_CAPTURE_REQUEST_BODY, PINGOPS_CAPTURE_RESPONSE_BODY,
|
|
3
|
+
import { HTTP_RESPONSE_CONTENT_ENCODING, PINGOPS_CAPTURE_REQUEST_BODY, PINGOPS_CAPTURE_RESPONSE_BODY, bufferToBodyString, createLogger, extractSpanPayload, getPropagatedAttributesFromContext, isCompressedContentEncoding, isSpanEligible, shouldCaptureSpan } from "@pingops/core";
|
|
4
4
|
import { INVALID_SPAN_CONTEXT, SpanKind, SpanStatusCode, ValueType, context, propagation, trace } from "@opentelemetry/api";
|
|
5
5
|
import "@opentelemetry/sdk-trace-node";
|
|
6
6
|
import "@opentelemetry/resources";
|
|
@@ -100,7 +100,9 @@ var PingopsSpanProcessor = class {
|
|
|
100
100
|
setGlobalConfig({
|
|
101
101
|
captureRequestBody: config.captureRequestBody,
|
|
102
102
|
captureResponseBody: config.captureResponseBody,
|
|
103
|
-
domainAllowList: config.domainAllowList
|
|
103
|
+
domainAllowList: config.domainAllowList,
|
|
104
|
+
maxRequestBodySize: config.maxRequestBodySize,
|
|
105
|
+
maxResponseBodySize: config.maxResponseBodySize
|
|
104
106
|
});
|
|
105
107
|
logger$1.info("Initialized PingopsSpanProcessor", {
|
|
106
108
|
baseUrl: config.baseUrl,
|
|
@@ -332,19 +334,13 @@ async function shutdownTracerProvider() {
|
|
|
332
334
|
//#region src/instrumentations/http/pingops-http.ts
|
|
333
335
|
/**
|
|
334
336
|
* Pingops HTTP instrumentation that extends HttpInstrumentation
|
|
335
|
-
* with request/response body capture
|
|
337
|
+
* with request/response body capture
|
|
336
338
|
*/
|
|
337
339
|
const DEFAULT_MAX_REQUEST_BODY_SIZE$1 = 4 * 1024;
|
|
338
340
|
const DEFAULT_MAX_RESPONSE_BODY_SIZE$1 = 4 * 1024;
|
|
339
|
-
const NETWORK_TIMINGS_PROP_NAME = "__networkTimings";
|
|
340
341
|
const PingopsSemanticAttributes = {
|
|
341
342
|
HTTP_REQUEST_BODY: "http.request.body",
|
|
342
|
-
HTTP_RESPONSE_BODY: "http.response.body"
|
|
343
|
-
NETWORK_DNS_LOOKUP_DURATION: "net.dns.lookup.duration",
|
|
344
|
-
NETWORK_TCP_CONNECT_DURATION: "net.tcp.connect.duration",
|
|
345
|
-
NETWORK_TLS_HANDSHAKE_DURATION: "net.tls.handshake.duration",
|
|
346
|
-
NETWORK_TTFB_DURATION: "net.ttfb.duration",
|
|
347
|
-
NETWORK_CONTENT_TRANSFER_DURATION: "net.content.transfer.duration"
|
|
343
|
+
HTTP_RESPONSE_BODY: "http.response.body"
|
|
348
344
|
};
|
|
349
345
|
/**
|
|
350
346
|
* Manually flattens a nested object into dot-notation keys
|
|
@@ -372,30 +368,6 @@ function setAttributeValue(span, attrName, attrValue) {
|
|
|
372
368
|
} else span.setAttribute(attrName, attrValue);
|
|
373
369
|
}
|
|
374
370
|
/**
|
|
375
|
-
* Processes network timings and sets them as span attributes (no spans created)
|
|
376
|
-
*/
|
|
377
|
-
function processNetworkTimings(span, networkTimings) {
|
|
378
|
-
if (networkTimings.startAt && networkTimings.dnsLookupAt) span.setAttribute(PingopsSemanticAttributes.NETWORK_DNS_LOOKUP_DURATION, networkTimings.dnsLookupAt - networkTimings.startAt);
|
|
379
|
-
if (networkTimings.dnsLookupAt && networkTimings.tcpConnectionAt) span.setAttribute(PingopsSemanticAttributes.NETWORK_TCP_CONNECT_DURATION, networkTimings.tcpConnectionAt - networkTimings.dnsLookupAt);
|
|
380
|
-
if (networkTimings.tcpConnectionAt && networkTimings.tlsHandshakeAt) span.setAttribute(PingopsSemanticAttributes.NETWORK_TLS_HANDSHAKE_DURATION, networkTimings.tlsHandshakeAt - networkTimings.tcpConnectionAt);
|
|
381
|
-
const startTTFB = networkTimings.tlsHandshakeAt || networkTimings.tcpConnectionAt;
|
|
382
|
-
if (networkTimings.firstByteAt && startTTFB) span.setAttribute(PingopsSemanticAttributes.NETWORK_TTFB_DURATION, networkTimings.firstByteAt - startTTFB);
|
|
383
|
-
if (networkTimings.firstByteAt && networkTimings.endAt) span.setAttribute(PingopsSemanticAttributes.NETWORK_CONTENT_TRANSFER_DURATION, networkTimings.endAt - networkTimings.firstByteAt);
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Initializes network timings on a span
|
|
387
|
-
*/
|
|
388
|
-
function initializeNetworkTimings(span) {
|
|
389
|
-
const networkTimings = { startAt: Date.now() };
|
|
390
|
-
Object.defineProperty(span, NETWORK_TIMINGS_PROP_NAME, {
|
|
391
|
-
enumerable: false,
|
|
392
|
-
configurable: true,
|
|
393
|
-
writable: false,
|
|
394
|
-
value: networkTimings
|
|
395
|
-
});
|
|
396
|
-
return networkTimings;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
371
|
* Extracts domain from URL
|
|
400
372
|
*/
|
|
401
373
|
function extractDomainFromUrl$1(url) {
|
|
@@ -459,26 +431,66 @@ function captureRequestBody(span, data, maxSize, semanticAttr, url) {
|
|
|
459
431
|
/**
|
|
460
432
|
* Captures response body from chunks
|
|
461
433
|
*/
|
|
462
|
-
function captureResponseBody(span, chunks, semanticAttr, url) {
|
|
434
|
+
function captureResponseBody(span, chunks, semanticAttr, responseHeaders, url) {
|
|
463
435
|
if (!shouldCaptureResponseBody$1(url)) return;
|
|
464
436
|
if (chunks && chunks.length) try {
|
|
465
|
-
const
|
|
466
|
-
|
|
437
|
+
const concatedChunks = Buffer.concat(chunks);
|
|
438
|
+
const contentEncoding = responseHeaders?.["content-encoding"];
|
|
439
|
+
if (isCompressedContentEncoding(contentEncoding)) {
|
|
440
|
+
setAttributeValue(span, semanticAttr, concatedChunks.toString("base64"));
|
|
441
|
+
const encStr = typeof contentEncoding === "string" ? contentEncoding : Array.isArray(contentEncoding) ? contentEncoding.map(String).join(", ") : void 0;
|
|
442
|
+
if (encStr) setAttributeValue(span, HTTP_RESPONSE_CONTENT_ENCODING, encStr);
|
|
443
|
+
} else {
|
|
444
|
+
const bodyStr = bufferToBodyString(concatedChunks);
|
|
445
|
+
if (bodyStr != null) setAttributeValue(span, semanticAttr, bodyStr);
|
|
446
|
+
}
|
|
467
447
|
} catch (e) {
|
|
468
448
|
console.error("Error occurred while capturing response body:", e);
|
|
469
449
|
}
|
|
470
450
|
}
|
|
471
451
|
/**
|
|
452
|
+
* Extracts headers from a request object (ClientRequest or IncomingMessage)
|
|
453
|
+
* Handles both types efficiently by checking for available methods/properties
|
|
454
|
+
*/
|
|
455
|
+
function extractRequestHeaders(request) {
|
|
456
|
+
if ("headers" in request && request.headers) return request.headers;
|
|
457
|
+
if (typeof request.getHeaders === "function") try {
|
|
458
|
+
const headers = request.getHeaders();
|
|
459
|
+
const result = {};
|
|
460
|
+
for (const [key, value] of Object.entries(headers)) if (value !== void 0) result[key] = typeof value === "number" ? String(value) : Array.isArray(value) ? value.map(String) : String(value);
|
|
461
|
+
return result;
|
|
462
|
+
} catch {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Extracts headers from a response object (ServerResponse or IncomingMessage)
|
|
469
|
+
* Handles both types efficiently by checking for available methods/properties
|
|
470
|
+
*/
|
|
471
|
+
function extractResponseHeaders(response) {
|
|
472
|
+
if ("headers" in response && response.headers) return response.headers;
|
|
473
|
+
if (typeof response.getHeaders === "function") try {
|
|
474
|
+
const headers = response.getHeaders();
|
|
475
|
+
const result = {};
|
|
476
|
+
for (const [key, value] of Object.entries(headers)) if (value !== void 0) result[key] = typeof value === "number" ? String(value) : Array.isArray(value) ? value.map(String) : String(value);
|
|
477
|
+
return result;
|
|
478
|
+
} catch {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
472
484
|
* Captures HTTP request headers as span attributes
|
|
473
485
|
*/
|
|
474
486
|
function captureRequestHeaders(span, headers) {
|
|
475
|
-
for (const [key, value] of Object.entries(headers)) if (value !== void 0) span.setAttribute(`
|
|
487
|
+
for (const [key, value] of Object.entries(headers)) if (value !== void 0) span.setAttribute(`http.request.header.${key.toLowerCase()}`, Array.isArray(value) ? value.join(",") : String(value));
|
|
476
488
|
}
|
|
477
489
|
/**
|
|
478
490
|
* Captures HTTP response headers as span attributes
|
|
479
491
|
*/
|
|
480
492
|
function captureResponseHeaders(span, headers) {
|
|
481
|
-
for (const [key, value] of Object.entries(headers)) if (value !== void 0) span.setAttribute(`
|
|
493
|
+
for (const [key, value] of Object.entries(headers)) if (value !== void 0) span.setAttribute(`http.response.header.${key.toLowerCase()}`, Array.isArray(value) ? value.join(",") : String(value));
|
|
482
494
|
}
|
|
483
495
|
const PingopsHttpSemanticAttributes = PingopsSemanticAttributes;
|
|
484
496
|
var PingopsHttpInstrumentation = class extends HttpInstrumentation {
|
|
@@ -495,10 +507,9 @@ var PingopsHttpInstrumentation = class extends HttpInstrumentation {
|
|
|
495
507
|
}
|
|
496
508
|
_createRequestHook(originalRequestHook, config) {
|
|
497
509
|
return (span, request) => {
|
|
498
|
-
const headers = request
|
|
510
|
+
const headers = extractRequestHeaders(request);
|
|
499
511
|
if (headers) captureRequestHeaders(span, headers);
|
|
500
512
|
if (request instanceof ClientRequest) {
|
|
501
|
-
const networkTimings = initializeNetworkTimings(span);
|
|
502
513
|
const maxRequestBodySize = config?.maxRequestBodySize || DEFAULT_MAX_REQUEST_BODY_SIZE$1;
|
|
503
514
|
const url = request.path && request.getHeader("host") ? `${request.protocol || "http:"}//${request.getHeader("host")}${request.path}` : void 0;
|
|
504
515
|
const originalWrite = request.write.bind(request);
|
|
@@ -511,27 +522,15 @@ var PingopsHttpInstrumentation = class extends HttpInstrumentation {
|
|
|
511
522
|
if (typeof data === "string" || data instanceof Buffer) captureRequestBody(span, data, maxRequestBodySize, PingopsSemanticAttributes.HTTP_REQUEST_BODY, url);
|
|
512
523
|
return originalEnd(data);
|
|
513
524
|
};
|
|
514
|
-
request.on("socket", (socket) => {
|
|
515
|
-
socket.on("lookup", () => {
|
|
516
|
-
networkTimings.dnsLookupAt = Date.now();
|
|
517
|
-
});
|
|
518
|
-
socket.on("connect", () => {
|
|
519
|
-
networkTimings.tcpConnectionAt = Date.now();
|
|
520
|
-
});
|
|
521
|
-
socket.on("secureConnect", () => {
|
|
522
|
-
networkTimings.tlsHandshakeAt = Date.now();
|
|
523
|
-
});
|
|
524
|
-
});
|
|
525
525
|
}
|
|
526
526
|
if (originalRequestHook) originalRequestHook(span, request);
|
|
527
527
|
};
|
|
528
528
|
}
|
|
529
529
|
_createResponseHook(originalResponseHook, config) {
|
|
530
530
|
return (span, response) => {
|
|
531
|
-
const headers = response
|
|
531
|
+
const headers = extractResponseHeaders(response);
|
|
532
532
|
if (headers) captureResponseHeaders(span, headers);
|
|
533
533
|
if (response instanceof IncomingMessage) {
|
|
534
|
-
const networkTimings = span[NETWORK_TIMINGS_PROP_NAME];
|
|
535
534
|
const maxResponseBodySize = config?.maxResponseBodySize || DEFAULT_MAX_RESPONSE_BODY_SIZE$1;
|
|
536
535
|
const url = response.url || void 0;
|
|
537
536
|
let chunks = [];
|
|
@@ -546,14 +545,7 @@ var PingopsHttpInstrumentation = class extends HttpInstrumentation {
|
|
|
546
545
|
}
|
|
547
546
|
});
|
|
548
547
|
response.prependOnceListener("end", () => {
|
|
549
|
-
|
|
550
|
-
networkTimings.endAt = Date.now();
|
|
551
|
-
processNetworkTimings(span, networkTimings);
|
|
552
|
-
}
|
|
553
|
-
captureResponseBody(span, chunks, PingopsSemanticAttributes.HTTP_RESPONSE_BODY, url);
|
|
554
|
-
});
|
|
555
|
-
if (networkTimings) response.once("readable", () => {
|
|
556
|
-
networkTimings.firstByteAt = Date.now();
|
|
548
|
+
captureResponseBody(span, chunks, PingopsSemanticAttributes.HTTP_RESPONSE_BODY, headers, url);
|
|
557
549
|
});
|
|
558
550
|
}
|
|
559
551
|
if (originalResponseHook) originalResponseHook(span, response);
|
|
@@ -567,19 +559,19 @@ var PingopsHttpInstrumentation = class extends HttpInstrumentation {
|
|
|
567
559
|
* HTTP instrumentation for OpenTelemetry
|
|
568
560
|
*/
|
|
569
561
|
/**
|
|
570
|
-
* Creates an HTTP instrumentation instance
|
|
562
|
+
* Creates an HTTP instrumentation instance.
|
|
563
|
+
* All outgoing HTTP requests are instrumented when the SDK is initialized.
|
|
571
564
|
*
|
|
572
|
-
* @param isGlobalInstrumentationEnabled - Function that checks if global instrumentation is enabled
|
|
573
565
|
* @param config - Optional configuration for the instrumentation
|
|
574
566
|
* @returns PingopsHttpInstrumentation instance
|
|
575
567
|
*/
|
|
576
|
-
function createHttpInstrumentation(
|
|
568
|
+
function createHttpInstrumentation(config) {
|
|
569
|
+
const globalConfig$1 = getGlobalConfig();
|
|
577
570
|
return new PingopsHttpInstrumentation({
|
|
578
571
|
ignoreIncomingRequestHook: () => true,
|
|
579
|
-
ignoreOutgoingRequestHook: () =>
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
},
|
|
572
|
+
ignoreOutgoingRequestHook: () => false,
|
|
573
|
+
maxRequestBodySize: globalConfig$1?.maxRequestBodySize,
|
|
574
|
+
maxResponseBodySize: globalConfig$1?.maxResponseBodySize,
|
|
583
575
|
...config
|
|
584
576
|
});
|
|
585
577
|
}
|
|
@@ -836,9 +828,19 @@ var UndiciInstrumentation = class extends InstrumentationBase {
|
|
|
836
828
|
if (!record) return;
|
|
837
829
|
const { span, attributes, startTime } = record;
|
|
838
830
|
if (shouldCaptureResponseBody(record.url)) {
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
831
|
+
const maxResponseBodySize = this.getConfig().maxResponseBodySize ?? DEFAULT_MAX_RESPONSE_BODY_SIZE;
|
|
832
|
+
const contentEncoding = record.attributes?.["http.response.header.content-encoding"] ?? void 0;
|
|
833
|
+
const contentType = record.attributes?.["http.response.header.content-type"] ?? void 0;
|
|
834
|
+
if (record.responseBodySize === Infinity) span.setAttribute(HTTP_RESPONSE_BODY, `[truncated response body; exceeded maxResponseBodySize=${maxResponseBodySize}; content-type=${contentType ?? "unknown"}; content-encoding=${contentEncoding ?? "identity"}]`);
|
|
835
|
+
else if (record.responseBodyChunks.length > 0) try {
|
|
836
|
+
const responseBodyBuffer = Buffer.concat(record.responseBodyChunks);
|
|
837
|
+
if (isCompressedContentEncoding(contentEncoding)) {
|
|
838
|
+
span.setAttribute(HTTP_RESPONSE_BODY, responseBodyBuffer.toString("base64"));
|
|
839
|
+
if (contentEncoding) span.setAttribute(HTTP_RESPONSE_CONTENT_ENCODING, contentEncoding);
|
|
840
|
+
} else {
|
|
841
|
+
const bodyStr = bufferToBodyString(responseBodyBuffer);
|
|
842
|
+
if (bodyStr != null) span.setAttribute(HTTP_RESPONSE_BODY, bodyStr);
|
|
843
|
+
}
|
|
842
844
|
} catch (e) {
|
|
843
845
|
this._diag.error("Error occurred while capturing response body:", e);
|
|
844
846
|
}
|
|
@@ -877,7 +879,10 @@ var UndiciInstrumentation = class extends InstrumentationBase {
|
|
|
877
879
|
if (record.requestBodySize + chunk.length <= maxRequestBodySize) {
|
|
878
880
|
record.requestBodyChunks.push(chunk);
|
|
879
881
|
record.requestBodySize += chunk.length;
|
|
880
|
-
} else
|
|
882
|
+
} else {
|
|
883
|
+
record.requestBodySize = Infinity;
|
|
884
|
+
record.requestBodyChunks = [];
|
|
885
|
+
}
|
|
881
886
|
}
|
|
882
887
|
onBodySent({ request }) {
|
|
883
888
|
const record = this._recordFromReq.get(request);
|
|
@@ -886,7 +891,10 @@ var UndiciInstrumentation = class extends InstrumentationBase {
|
|
|
886
891
|
record.requestBodyChunks = [];
|
|
887
892
|
return;
|
|
888
893
|
}
|
|
889
|
-
if (record.
|
|
894
|
+
if (record.requestBodySize === Infinity) {
|
|
895
|
+
const maxRequestBodySize = this.getConfig().maxRequestBodySize ?? DEFAULT_MAX_REQUEST_BODY_SIZE;
|
|
896
|
+
record.span.setAttribute(HTTP_REQUEST_BODY, `[truncated request body; exceeded maxRequestBodySize=${maxRequestBodySize}]`);
|
|
897
|
+
} else if (record.requestBodyChunks.length > 0) try {
|
|
890
898
|
const requestBody = Buffer.concat(record.requestBodyChunks).toString("utf-8");
|
|
891
899
|
if (requestBody) record.span.setAttribute(HTTP_REQUEST_BODY, requestBody);
|
|
892
900
|
} catch (e) {
|
|
@@ -902,7 +910,10 @@ var UndiciInstrumentation = class extends InstrumentationBase {
|
|
|
902
910
|
if (record.responseBodySize + chunk.length <= maxResponseBodySize) {
|
|
903
911
|
record.responseBodyChunks.push(chunk);
|
|
904
912
|
record.responseBodySize += chunk.length;
|
|
905
|
-
} else
|
|
913
|
+
} else {
|
|
914
|
+
record.responseBodySize = Infinity;
|
|
915
|
+
record.responseBodyChunks = [];
|
|
916
|
+
}
|
|
906
917
|
}
|
|
907
918
|
recordRequestDuration(attributes, startTime) {
|
|
908
919
|
const metricsAttributes = {};
|
|
@@ -941,18 +952,18 @@ var UndiciInstrumentation = class extends InstrumentationBase {
|
|
|
941
952
|
* Undici instrumentation for OpenTelemetry
|
|
942
953
|
*/
|
|
943
954
|
/**
|
|
944
|
-
* Creates an Undici instrumentation instance
|
|
955
|
+
* Creates an Undici instrumentation instance.
|
|
956
|
+
* All requests are instrumented when the SDK is initialized.
|
|
945
957
|
*
|
|
946
|
-
* @param isGlobalInstrumentationEnabled - Function that checks if global instrumentation is enabled
|
|
947
958
|
* @returns UndiciInstrumentation instance
|
|
948
959
|
*/
|
|
949
|
-
function createUndiciInstrumentation(
|
|
960
|
+
function createUndiciInstrumentation() {
|
|
961
|
+
const globalConfig$1 = getGlobalConfig();
|
|
950
962
|
return new UndiciInstrumentation({
|
|
951
963
|
enabled: true,
|
|
952
|
-
ignoreRequestHook: () =>
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}
|
|
964
|
+
ignoreRequestHook: () => false,
|
|
965
|
+
maxRequestBodySize: globalConfig$1?.maxRequestBodySize,
|
|
966
|
+
maxResponseBodySize: globalConfig$1?.maxResponseBodySize
|
|
956
967
|
});
|
|
957
968
|
}
|
|
958
969
|
|
|
@@ -962,18 +973,14 @@ let installed = false;
|
|
|
962
973
|
/**
|
|
963
974
|
* Registers instrumentations for Node.js environment.
|
|
964
975
|
* This function is idempotent and can be called multiple times safely.
|
|
976
|
+
* When the SDK is initialized, all HTTP requests are instrumented.
|
|
965
977
|
*
|
|
966
|
-
* Instrumentation behavior:
|
|
967
|
-
* - If global instrumentation is enabled: all HTTP requests are instrumented
|
|
968
|
-
* - If global instrumentation is NOT enabled: only requests within wrapHttp blocks are instrumented
|
|
969
|
-
*
|
|
970
|
-
* @param isGlobalInstrumentationEnabled - Function that checks if global instrumentation is enabled
|
|
971
978
|
* @returns Array of Instrumentation instances
|
|
972
979
|
*/
|
|
973
|
-
function getInstrumentations(
|
|
980
|
+
function getInstrumentations() {
|
|
974
981
|
if (installed) return [];
|
|
975
982
|
installed = true;
|
|
976
|
-
return [createHttpInstrumentation(
|
|
983
|
+
return [createHttpInstrumentation(), createUndiciInstrumentation()];
|
|
977
984
|
}
|
|
978
985
|
|
|
979
986
|
//#endregion
|