@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.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(isGlobalInstrumentationEnabled: () => boolean): Instrumentation[];
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(isGlobalInstrumentationEnabled: () => boolean, config?: Partial<PingopsHttpInstrumentationConfig>): PingopsHttpInstrumentation;
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(isGlobalInstrumentationEnabled: () => boolean): UndiciInstrumentation;
337
+ declare function createUndiciInstrumentation(): UndiciInstrumentation;
340
338
  //#endregion
341
- export { type NetworkTimings, PingopsHttpInstrumentation, type PingopsHttpInstrumentationConfig, PingopsHttpSemanticAttributes, type PingopsInstrumentationConfig, type PingopsProcessorConfig, PingopsSemanticAttributes, PingopsSpanProcessor, createHttpInstrumentation, createUndiciInstrumentation, getInstrumentations, getPingopsTracerProvider, setPingopsTracerProvider, shutdownTracerProvider };
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
@@ -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":"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"}
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;;;;;AAsGgC,KA3GpB,iBAAA,GA2GoB,WAAA,GAAA,SAAA;;;;ACAnB,UDtGI,sBAAA,CCsGiB;EAkBZ;;;EAoGR,MAAA,CAAA,EAAA,MAAA;EAiGe;;;EAvN6B,OAAA,EAAA,MAAA;;;;ACxB1D;EA6BgB,KAAA,CAAA,EAAA,OAAA;EA2EM;;;;EC1LN;;;;ECWH;AAKb;AAoXA;EAEiB,eAAA,CAAA,EAAA,MAAA,EAAA;EAGJ;;;;ECzYG;;;EAEb,mBAAA,CAAA,EAAA,OAAA;EAA0B;;;;AChB7B;AAuBA;AAMA;AAIA;;EACS,kBAAA,CAAA,EAAA,MAAA;EAAe;;AAGxB;;;;;;;EAOiB,mBAAA,CAAA,EAAA,MAAqB;EAAK;;;EACjB,eAAA,CAAA,ENwCN,UMxCM,EAAA;EAKT;;;EAK2B,cAAA,CAAA,ENmCzB,UMnCyB,EAAA;EAAtB;;;;EAI6B,eAAA,CAAA,ENqC/B,qBMrC+B;EAAlC;;;;EANc,SAAA,CAAA,EAAA,MAAA;;;;ACoI/B;EAA+D,YAAA,CAAA,EAAA,MAAA;EAMzC;;;;;;ACrLtB;;;;eR8Ge;;;;;;AG1Gf;;;;ACWA;AAKiB,cH0FJ,oBAAA,YAAgC,aG1FA,CAAA;EAoXhC,QAAA,SAAA;EAEI,QAAA,MAAA;EAGJ;;;;ACzYb;EACmB,WAAA,CAAA,MAAA,EJ2HG,sBI3HH;EAAR;;;gBJ4LK,qBAAqB;;;AK3MrC;AAuBA;AAMA;AAIA;;;;EACyB,KAAA,CAAA,IAAA,EL4MX,YK5MW,CAAA,EAAA,IAAA;EAGR;;;;;EAIsC,UAAA,CAAA,CAAA,ELsS1B,OKtS0B,CAAA,IAAA,CAAA;EAAY;AAGnE;;;;EAC0B,QAAA,CAAA,CAAA,ELoTC,OKpTD,CAAA,IAAA,CAAA;AAK1B;;;;;;;;;ALsEA;;;;AAsHc,iBC9IE,wBAAA,CD8IF,QAAA,EC7IF,cD6IE,GAAA,IAAA,CAAA,EAAA,IAAA;;;;;;;;AC9Id;AA6BA;AA2EsB,iBA3EN,wBAAA,CAAA,CA2EuC,EA3EX,cA2EW;;;;iBAAjC,sBAAA,CAAA,GAA0B;;;;;;;AF3LhD;AAKA;;AAwEmB,iBG5EH,mBAAA,CAAA,CH4EG,EG5EoB,eH4EpB,EAAA;;;cIjEN;;;AJZb,CAAA;AAKiB,UIYA,4BAAA,CJZsB;EAmEnB;;;;EAmCY,kBAAA,CAAA,EAAA,MAAA;;;;ACAhC;EAkBsB,mBAAA,CAAA,EAAA,MAAA;;AAiEe,cGuMxB,6BHvMwB,EAAA;EAmCvB,iBAAA,EAAA,MAAA;EAiGe,kBAAA,EAAA,MAAA;CAkBF;AAzOkB,UG4R5B,gCAAA,SACP,yBH7RmC,EG6RR,4BH7RQ,CAAA;cG+RhC,0BAAA,SAAmC,mBAAA;uBACzB;;EFxTP,QAAA,kBAAA;EA6BA,QAAA,mBAAwB;AA2ExC;;;;;;;AF3LA;AAKA;;AAwEmB,iBK5EH,yBAAA,CL4EG,MAAA,CAAA,EK3ER,OL2EQ,CK3EA,gCL2EA,CAAA,CAAA,EK1EhB,0BL0EgB;;;UM1FF,aAAA;;;;;;ANajB;AAKA;;EAwEmB,OAAA,EAAA,MAAA,GAAA,CAAA,MAAA,GAAA,MAAA,EAAA,CAAA,EAAA;EAMC;;;;;;ECwBP,OAAA,EAAA,OAAA;EAkBS,UAAA,EAAA,OAAA;EAiEN,aAAA,EAAA,MAAA,GAAA,IAAA;EAAqB,WAAA,EAAA,MAAA,GAAA,IAAA;EAmCvB,IAAA,EAAA,GAAA;;AAmHa,UK1UV,cAAA,CL0UU;EAzOkB,OAAA,EKhGlC,MLgGkC,EAAA;EAAa,UAAA,EAAA,MAAA;;;UK3FzC,0BAA0B;EJmE3B,CAAA,OAAA,EIlEJ,CJkEI,CAAA,EAAA,OAAA;AA6BhB;AA2EsB,UIvKL,mBJuK2B,CAAA,IIvKH,aJuKc,CAAA,CAAA;SItK9C,iBAAe;;UAGP,mCACD,8BACC;EHzBD,CAAA,IAAA,EG2BP,MH3BO,EAAA,IAAA,EAAA;aG2BgB;cAAuB;;AFhBvD;AAKiB,UEcA,qBFd4B,CAAA,IEcF,aFdE,CAAA,CAAA;EAoXhC,CAAA,OAAA,EErWD,CFqWC,CAAA,EErWG,UFqWH;AAEb;AAGa,UErWI,2BFqWuB,CACjB,cErWP,aFqWO,EAAA,eEpWN,cFmWkD,CAAA,SElWzD,qBFkWyD,CAAA;;sBEhW7C,sBAAsB;;EDzC5B,WAAA,CAAA,EC2CA,mBD3CyB,CC2CL,WD3CK,CAAA;EACtB;EAAR,YAAA,CAAA,EC4CM,oBD5CN,CC4C2B,WD5C3B,EC4CwC,YD5CxC,CAAA;EACR;EAA0B,aAAA,CAAA,EC6CX,qBD7CW,CC6CW,WD7CX,CAAA;;;;EChBZ,uBAAa,CAAA,EAAA;IAuBb,cAAc,CAAA,EAAA,MAAA,EACpB;IAKM,eAAA,CAAA,EAAA,MAAqB,EAAA;EAIrB,CAAA;EAAwB;;;;EAIxB,kBAAA,CAAA,EAAA,MAAoB;EACrB;;;;EAGuC,mBAAA,CAAA,EAAA,MAAA;;;;cCgJ1C,qBAAA,SAA8B,oBAAoB;;;;uBAMzC;;EPlLV,OAAA,CAAA,CAAA,EAAA,IAAA;EAKK,MAAA,CAAA,CAAA,EAAA,IAAA;EAmEG,UAAA,wBAAA,CAAA,CAAA,EAAA,IAAA;EAKD,QAAA,kBAAA;EAMC,QAAA,mBAAA;EAwBL,QAAA,gBAAA;EAAiB,QAAA,gBAAA;;;;ECAnB,QAAA,eAAqB;EAkBZ,QAAA,UAAA;EAiEN,QAAA,mBAAA;EAAqB,QAAA,qBAAA;EAmCvB,QAAA,gBAAA;;;;;;;;ADjOd;AAKA;AAmEoB,iBQ3EJ,2BAAA,CAAA,CR2EI,EQ3E2B,qBR2E3B"}
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, PINGOPS_HTTP_ENABLED, createLogger, extractSpanPayload, getPropagatedAttributesFromContext, isSpanEligible, shouldCaptureSpan } from "@pingops/core";
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 and network timing metrics
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 responseBody = Buffer.concat(chunks).toString("utf8");
466
- if (responseBody) setAttributeValue(span, semanticAttr, responseBody);
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(`pingops.http.request.header.${key.toLowerCase()}`, Array.isArray(value) ? value.join(",") : String(value));
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(`pingops.http.response.header.${key.toLowerCase()}`, Array.isArray(value) ? value.join(",") : String(value));
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.headers;
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.headers;
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
- if (networkTimings) {
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(isGlobalInstrumentationEnabled, config) {
568
+ function createHttpInstrumentation(config) {
569
+ const globalConfig$1 = getGlobalConfig();
577
570
  return new PingopsHttpInstrumentation({
578
571
  ignoreIncomingRequestHook: () => true,
579
- ignoreOutgoingRequestHook: () => {
580
- if (isGlobalInstrumentationEnabled()) return false;
581
- return context.active().getValue(PINGOPS_HTTP_ENABLED) !== true;
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
- if (record.responseBodyChunks.length > 0 && record.responseBodySize !== Infinity) try {
840
- const responseBody = Buffer.concat(record.responseBodyChunks).toString("utf-8");
841
- if (responseBody) span.setAttribute(HTTP_RESPONSE_BODY, responseBody);
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 if (record.requestBodyChunks.length === 0) record.requestBodySize = Infinity;
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.requestBodyChunks.length > 0 && record.requestBodySize !== Infinity) try {
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 if (record.responseBodyChunks.length === 0) record.responseBodySize = Infinity;
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(isGlobalInstrumentationEnabled) {
960
+ function createUndiciInstrumentation() {
961
+ const globalConfig$1 = getGlobalConfig();
950
962
  return new UndiciInstrumentation({
951
963
  enabled: true,
952
- ignoreRequestHook: () => {
953
- if (isGlobalInstrumentationEnabled()) return false;
954
- return context.active().getValue(PINGOPS_HTTP_ENABLED) !== true;
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(isGlobalInstrumentationEnabled) {
980
+ function getInstrumentations() {
974
981
  if (installed) return [];
975
982
  installed = true;
976
- return [createHttpInstrumentation(isGlobalInstrumentationEnabled), createUndiciInstrumentation(isGlobalInstrumentationEnabled)];
983
+ return [createHttpInstrumentation(), createUndiciInstrumentation()];
977
984
  }
978
985
 
979
986
  //#endregion