@pingops/otel 0.2.6 → 0.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/dist/index.cjs +121 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -21
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +22 -21
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +122 -133
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -134,6 +134,7 @@ var PingopsSpanProcessor = class {
|
|
|
134
134
|
});
|
|
135
135
|
this.config = {
|
|
136
136
|
debug: config.debug ?? false,
|
|
137
|
+
sdkVersion: config.sdkVersion,
|
|
137
138
|
headersAllowList: config.headersAllowList,
|
|
138
139
|
headersDenyList: config.headersDenyList,
|
|
139
140
|
domainAllowList: config.domainAllowList,
|
|
@@ -171,6 +172,7 @@ var PingopsSpanProcessor = class {
|
|
|
171
172
|
spanId: spanContext.spanId,
|
|
172
173
|
traceId: spanContext.traceId
|
|
173
174
|
});
|
|
175
|
+
if (this.config.sdkVersion) span.setAttribute("pingops.sdk.version", this.config.sdkVersion);
|
|
174
176
|
const propagatedAttributes = (0, _pingops_core.getPropagatedAttributesFromContext)(parentContext);
|
|
175
177
|
if (Object.keys(propagatedAttributes).length > 0) {
|
|
176
178
|
for (const [key, value] of Object.entries(propagatedAttributes)) if (typeof value === "string" || Array.isArray(value)) span.setAttribute(key, value);
|
|
@@ -423,6 +425,7 @@ function shouldIgnoreOutboundInstrumentation(requestUrl) {
|
|
|
423
425
|
*/
|
|
424
426
|
function resolveOutboundSpanParentContext(activeContext, requestUrl) {
|
|
425
427
|
if (!(0, _opentelemetry_core.isTracingSuppressed)(activeContext)) return activeContext;
|
|
428
|
+
if (activeContext.getValue(_pingops_core.PINGOPS_INTENTIONAL_SUPPRESSION) === true) return activeContext;
|
|
426
429
|
if (isExporterRequestUrl(requestUrl)) return activeContext;
|
|
427
430
|
if (!hasLoggedSuppressionLeakWarning) {
|
|
428
431
|
logger.warn("Detected suppressed context for outbound user request; running instrumentation on ROOT_CONTEXT to prevent Noop spans from suppression leakage");
|
|
@@ -431,18 +434,74 @@ function resolveOutboundSpanParentContext(activeContext, requestUrl) {
|
|
|
431
434
|
return _opentelemetry_api.ROOT_CONTEXT;
|
|
432
435
|
}
|
|
433
436
|
|
|
437
|
+
//#endregion
|
|
438
|
+
//#region src/instrumentations/body-utils.ts
|
|
439
|
+
const HTTP_REQUEST_BODY = "http.request.body";
|
|
440
|
+
const HTTP_RESPONSE_BODY = "http.response.body";
|
|
441
|
+
const HTTP_REQUEST_BODY_SIZE = "http.request.body.size";
|
|
442
|
+
const HTTP_RESPONSE_BODY_SIZE = "http.response.body.size";
|
|
443
|
+
const DEFAULT_MAX_REQUEST_BODY_SIZE = 10 * 1024;
|
|
444
|
+
const DEFAULT_MAX_RESPONSE_BODY_SIZE = 10 * 1024;
|
|
445
|
+
/**
|
|
446
|
+
* Gets domain rule configuration for a given URL.
|
|
447
|
+
*/
|
|
448
|
+
function getDomainRule(url$1, domainAllowList) {
|
|
449
|
+
if (!domainAllowList) return;
|
|
450
|
+
const domain = (0, _pingops_core.extractDomainFromUrl)(url$1);
|
|
451
|
+
for (const rule of domainAllowList) if (domain === rule.domain || domain.endsWith(`.${rule.domain}`) || domain === rule.domain.slice(1)) return rule;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Determines if request body should be captured based on priority:
|
|
455
|
+
* context > domain rule > global config > default (false).
|
|
456
|
+
*/
|
|
457
|
+
function shouldCaptureRequestBody(url$1) {
|
|
458
|
+
const contextValue = _opentelemetry_api.context.active().getValue(_pingops_core.PINGOPS_CAPTURE_REQUEST_BODY);
|
|
459
|
+
if (contextValue !== void 0) return contextValue;
|
|
460
|
+
if (url$1) {
|
|
461
|
+
const domainRule = getDomainRule(url$1, getGlobalConfig()?.domainAllowList);
|
|
462
|
+
if (domainRule?.captureRequestBody !== void 0) return domainRule.captureRequestBody;
|
|
463
|
+
}
|
|
464
|
+
const globalConfig$1 = getGlobalConfig();
|
|
465
|
+
if (globalConfig$1?.captureRequestBody !== void 0) return globalConfig$1.captureRequestBody;
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Determines if response body should be captured based on priority:
|
|
470
|
+
* context > domain rule > global config > default (false).
|
|
471
|
+
*/
|
|
472
|
+
function shouldCaptureResponseBody(url$1) {
|
|
473
|
+
const contextValue = _opentelemetry_api.context.active().getValue(_pingops_core.PINGOPS_CAPTURE_RESPONSE_BODY);
|
|
474
|
+
if (contextValue !== void 0) return contextValue;
|
|
475
|
+
if (url$1) {
|
|
476
|
+
const domainRule = getDomainRule(url$1, getGlobalConfig()?.domainAllowList);
|
|
477
|
+
if (domainRule?.captureResponseBody !== void 0) return domainRule.captureResponseBody;
|
|
478
|
+
}
|
|
479
|
+
const globalConfig$1 = getGlobalConfig();
|
|
480
|
+
if (globalConfig$1?.captureResponseBody !== void 0) return globalConfig$1.captureResponseBody;
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Normalizes supported HTTP chunk types into a Buffer.
|
|
485
|
+
*/
|
|
486
|
+
function toBufferChunk(data) {
|
|
487
|
+
if (typeof data === "string") return Buffer.from(data);
|
|
488
|
+
if (Buffer.isBuffer(data)) return data;
|
|
489
|
+
if (data instanceof Uint8Array) return Buffer.from(data);
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
|
|
434
493
|
//#endregion
|
|
435
494
|
//#region src/instrumentations/http/pingops-http.ts
|
|
436
495
|
/**
|
|
437
496
|
* Pingops HTTP instrumentation that extends HttpInstrumentation
|
|
438
497
|
* with request/response body capture
|
|
439
498
|
*/
|
|
440
|
-
const DEFAULT_MAX_REQUEST_BODY_SIZE$1 = 4 * 1024;
|
|
441
|
-
const DEFAULT_MAX_RESPONSE_BODY_SIZE$1 = 4 * 1024;
|
|
442
499
|
const LEGACY_ATTR_HTTP_URL = "http.url";
|
|
443
500
|
const PingopsSemanticAttributes = {
|
|
444
|
-
HTTP_REQUEST_BODY
|
|
445
|
-
HTTP_RESPONSE_BODY
|
|
501
|
+
HTTP_REQUEST_BODY,
|
|
502
|
+
HTTP_RESPONSE_BODY,
|
|
503
|
+
HTTP_REQUEST_BODY_SIZE,
|
|
504
|
+
HTTP_RESPONSE_BODY_SIZE
|
|
446
505
|
};
|
|
447
506
|
/**
|
|
448
507
|
* Manually flattens a nested object into dot-notation keys
|
|
@@ -455,7 +514,7 @@ function isPrimitiveArray(value) {
|
|
|
455
514
|
}
|
|
456
515
|
function flatten(obj, prefix = "") {
|
|
457
516
|
const result = {};
|
|
458
|
-
for (const key in obj) if (Object.
|
|
517
|
+
for (const key in obj) if (Object.hasOwn(obj, key)) {
|
|
459
518
|
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
460
519
|
const value = obj[key];
|
|
461
520
|
if (isPlainObject(value)) Object.assign(result, flatten(value, newKey));
|
|
@@ -474,61 +533,12 @@ function setAttributeValue(span, attrName, attrValue) {
|
|
|
474
533
|
} else if (isPlainObject(attrValue)) span.setAttributes(flatten({ [attrName]: attrValue }));
|
|
475
534
|
}
|
|
476
535
|
/**
|
|
477
|
-
*
|
|
478
|
-
*/
|
|
479
|
-
function extractDomainFromUrl$1(url$1) {
|
|
480
|
-
try {
|
|
481
|
-
return new URL(url$1).hostname;
|
|
482
|
-
} catch {
|
|
483
|
-
const match = url$1.match(/^(?:https?:\/\/)?([^/]+)/);
|
|
484
|
-
return match ? match[1] : "";
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Gets domain rule configuration for a given URL
|
|
489
|
-
*/
|
|
490
|
-
function getDomainRule$1(url$1, domainAllowList) {
|
|
491
|
-
if (!domainAllowList) return;
|
|
492
|
-
const domain = extractDomainFromUrl$1(url$1);
|
|
493
|
-
for (const rule of domainAllowList) if (domain === rule.domain || domain.endsWith(`.${rule.domain}`) || domain === rule.domain.slice(1)) return rule;
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* Determines if request body should be captured based on priority:
|
|
497
|
-
* context > domain rule > global config > default (false)
|
|
498
|
-
*/
|
|
499
|
-
function shouldCaptureRequestBody$1(url$1) {
|
|
500
|
-
const contextValue = _opentelemetry_api.context.active().getValue(_pingops_core.PINGOPS_CAPTURE_REQUEST_BODY);
|
|
501
|
-
if (contextValue !== void 0) return contextValue;
|
|
502
|
-
if (url$1) {
|
|
503
|
-
const domainRule = getDomainRule$1(url$1, getGlobalConfig()?.domainAllowList);
|
|
504
|
-
if (domainRule?.captureRequestBody !== void 0) return domainRule.captureRequestBody;
|
|
505
|
-
}
|
|
506
|
-
const globalConfig$1 = getGlobalConfig();
|
|
507
|
-
if (globalConfig$1?.captureRequestBody !== void 0) return globalConfig$1.captureRequestBody;
|
|
508
|
-
return false;
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Determines if response body should be captured based on priority:
|
|
512
|
-
* context > domain rule > global config > default (false)
|
|
513
|
-
*/
|
|
514
|
-
function shouldCaptureResponseBody$1(url$1) {
|
|
515
|
-
const contextValue = _opentelemetry_api.context.active().getValue(_pingops_core.PINGOPS_CAPTURE_RESPONSE_BODY);
|
|
516
|
-
if (contextValue !== void 0) return contextValue;
|
|
517
|
-
if (url$1) {
|
|
518
|
-
const domainRule = getDomainRule$1(url$1, getGlobalConfig()?.domainAllowList);
|
|
519
|
-
if (domainRule?.captureResponseBody !== void 0) return domainRule.captureResponseBody;
|
|
520
|
-
}
|
|
521
|
-
const globalConfig$1 = getGlobalConfig();
|
|
522
|
-
if (globalConfig$1?.captureResponseBody !== void 0) return globalConfig$1.captureResponseBody;
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* Captures request body from string or Buffer data
|
|
536
|
+
* Captures request body from a chunk buffer.
|
|
527
537
|
*/
|
|
528
538
|
function captureRequestBody(span, data, maxSize, semanticAttr, url$1) {
|
|
529
|
-
if (!shouldCaptureRequestBody
|
|
539
|
+
if (!shouldCaptureRequestBody(url$1)) return;
|
|
530
540
|
if (data.length && data.length <= maxSize) try {
|
|
531
|
-
const requestBody =
|
|
541
|
+
const requestBody = data.toString("utf-8");
|
|
532
542
|
if (requestBody) setAttributeValue(span, semanticAttr, requestBody);
|
|
533
543
|
} catch (e) {
|
|
534
544
|
console.error("Error occurred while capturing request body:", e);
|
|
@@ -538,12 +548,12 @@ function captureRequestBody(span, data, maxSize, semanticAttr, url$1) {
|
|
|
538
548
|
* Captures response body from chunks
|
|
539
549
|
*/
|
|
540
550
|
function captureResponseBody(span, chunks, semanticAttr, responseHeaders, url$1, maxSize) {
|
|
541
|
-
if (!shouldCaptureResponseBody
|
|
551
|
+
if (!shouldCaptureResponseBody(url$1)) return;
|
|
542
552
|
if (chunks === null) {
|
|
543
553
|
const contentEncoding = responseHeaders?.["content-encoding"];
|
|
544
554
|
const contentType = responseHeaders?.["content-type"];
|
|
545
555
|
const toHeaderString = (value) => typeof value === "string" ? value : Array.isArray(value) ? value.join(", ") : "unknown";
|
|
546
|
-
setAttributeValue(span, semanticAttr, `[truncated response body; exceeded maxResponseBodySize=${maxSize ?? DEFAULT_MAX_RESPONSE_BODY_SIZE
|
|
556
|
+
setAttributeValue(span, semanticAttr, `[truncated response body; exceeded maxResponseBodySize=${maxSize ?? DEFAULT_MAX_RESPONSE_BODY_SIZE}; content-type=${toHeaderString(contentType)}; content-encoding=${toHeaderString(contentEncoding)}]`);
|
|
547
557
|
return;
|
|
548
558
|
}
|
|
549
559
|
if (chunks.length) try {
|
|
@@ -662,7 +672,9 @@ var PingopsHttpInstrumentation = class extends _opentelemetry_instrumentation_ht
|
|
|
662
672
|
const headers = extractRequestHeaders(request);
|
|
663
673
|
if (headers) captureRequestHeaders(span, headers);
|
|
664
674
|
if (request instanceof http.ClientRequest) {
|
|
665
|
-
const maxRequestBodySize = config?.maxRequestBodySize || DEFAULT_MAX_REQUEST_BODY_SIZE
|
|
675
|
+
const maxRequestBodySize = config?.maxRequestBodySize || DEFAULT_MAX_REQUEST_BODY_SIZE;
|
|
676
|
+
let requestBodySize = 0;
|
|
677
|
+
span.setAttribute(PingopsSemanticAttributes.HTTP_REQUEST_BODY_SIZE, requestBodySize);
|
|
666
678
|
const hostHeader = request.getHeader("host");
|
|
667
679
|
const host = typeof hostHeader === "string" ? hostHeader : Array.isArray(hostHeader) ? hostHeader.join(",") : typeof hostHeader === "number" ? String(hostHeader) : void 0;
|
|
668
680
|
const url$1 = request.path && host ? `${request.protocol || "http:"}//${host}${request.path}` : void 0;
|
|
@@ -675,11 +687,21 @@ var PingopsHttpInstrumentation = class extends _opentelemetry_instrumentation_ht
|
|
|
675
687
|
const originalWrite = request.write.bind(request);
|
|
676
688
|
const originalEnd = request.end.bind(request);
|
|
677
689
|
request.write = ((data, ...rest) => {
|
|
678
|
-
|
|
690
|
+
const chunkBuffer = toBufferChunk(data);
|
|
691
|
+
if (chunkBuffer) {
|
|
692
|
+
requestBodySize += chunkBuffer.length;
|
|
693
|
+
span.setAttribute(PingopsSemanticAttributes.HTTP_REQUEST_BODY_SIZE, requestBodySize);
|
|
694
|
+
captureRequestBody(span, chunkBuffer, maxRequestBodySize, PingopsSemanticAttributes.HTTP_REQUEST_BODY, url$1);
|
|
695
|
+
}
|
|
679
696
|
return originalWrite(data, ...rest);
|
|
680
697
|
});
|
|
681
698
|
request.end = ((data, ...rest) => {
|
|
682
|
-
|
|
699
|
+
const chunkBuffer = toBufferChunk(data);
|
|
700
|
+
if (chunkBuffer) {
|
|
701
|
+
requestBodySize += chunkBuffer.length;
|
|
702
|
+
span.setAttribute(PingopsSemanticAttributes.HTTP_REQUEST_BODY_SIZE, requestBodySize);
|
|
703
|
+
captureRequestBody(span, chunkBuffer, maxRequestBodySize, PingopsSemanticAttributes.HTTP_REQUEST_BODY, url$1);
|
|
704
|
+
}
|
|
683
705
|
return originalEnd(data, ...rest);
|
|
684
706
|
});
|
|
685
707
|
}
|
|
@@ -697,19 +719,19 @@ var PingopsHttpInstrumentation = class extends _opentelemetry_instrumentation_ht
|
|
|
697
719
|
span.setAttribute(_opentelemetry_semantic_conventions.ATTR_URL_PATH, path);
|
|
698
720
|
if (query) span.setAttribute(_opentelemetry_semantic_conventions.ATTR_URL_QUERY, query);
|
|
699
721
|
}
|
|
700
|
-
const maxResponseBodySize = config?.maxResponseBodySize || DEFAULT_MAX_RESPONSE_BODY_SIZE
|
|
722
|
+
const maxResponseBodySize = config?.maxResponseBodySize || DEFAULT_MAX_RESPONSE_BODY_SIZE;
|
|
701
723
|
const url$1 = response.url || void 0;
|
|
702
724
|
let chunks = [];
|
|
703
725
|
let totalSize = 0;
|
|
704
|
-
|
|
726
|
+
span.setAttribute(PingopsSemanticAttributes.HTTP_RESPONSE_BODY_SIZE, 0);
|
|
727
|
+
const shouldCapture = shouldCaptureResponseBody(url$1);
|
|
705
728
|
response.prependListener("data", (chunk) => {
|
|
706
|
-
if (!chunk
|
|
707
|
-
|
|
708
|
-
if (typeof chunk === "string") chunkBuffer = Buffer.from(chunk);
|
|
709
|
-
else if (Buffer.isBuffer(chunk)) chunkBuffer = chunk;
|
|
710
|
-
else if (chunk instanceof Uint8Array) chunkBuffer = Buffer.from(chunk);
|
|
729
|
+
if (!chunk) return;
|
|
730
|
+
const chunkBuffer = toBufferChunk(chunk);
|
|
711
731
|
if (!chunkBuffer) return;
|
|
712
732
|
totalSize += chunkBuffer.length;
|
|
733
|
+
span.setAttribute(PingopsSemanticAttributes.HTTP_RESPONSE_BODY_SIZE, totalSize);
|
|
734
|
+
if (!shouldCapture) return;
|
|
713
735
|
if (chunks && totalSize <= maxResponseBodySize) chunks.push(chunkBuffer);
|
|
714
736
|
else chunks = null;
|
|
715
737
|
});
|
|
@@ -717,6 +739,7 @@ var PingopsHttpInstrumentation = class extends _opentelemetry_instrumentation_ht
|
|
|
717
739
|
const finalizeCapture = () => {
|
|
718
740
|
if (finalized) return;
|
|
719
741
|
finalized = true;
|
|
742
|
+
span.setAttribute(PingopsSemanticAttributes.HTTP_RESPONSE_BODY_SIZE, totalSize);
|
|
720
743
|
captureResponseBody(span, chunks, PingopsSemanticAttributes.HTTP_RESPONSE_BODY, headers, url$1, maxResponseBodySize);
|
|
721
744
|
};
|
|
722
745
|
response.prependOnceListener("end", finalizeCapture);
|
|
@@ -765,59 +788,6 @@ function createHttpInstrumentation(config) {
|
|
|
765
788
|
|
|
766
789
|
//#endregion
|
|
767
790
|
//#region src/instrumentations/undici/pingops-undici.ts
|
|
768
|
-
const DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024;
|
|
769
|
-
const DEFAULT_MAX_RESPONSE_BODY_SIZE = 4 * 1024;
|
|
770
|
-
const HTTP_REQUEST_BODY = "http.request.body";
|
|
771
|
-
const HTTP_RESPONSE_BODY = "http.response.body";
|
|
772
|
-
/**
|
|
773
|
-
* Extracts domain from URL
|
|
774
|
-
*/
|
|
775
|
-
function extractDomainFromUrl(url$1) {
|
|
776
|
-
try {
|
|
777
|
-
return new url.URL(url$1).hostname;
|
|
778
|
-
} catch {
|
|
779
|
-
const match = url$1.match(/^(?:https?:\/\/)?([^/]+)/);
|
|
780
|
-
return match ? match[1] : "";
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Gets domain rule configuration for a given URL
|
|
785
|
-
*/
|
|
786
|
-
function getDomainRule(url$1, domainAllowList) {
|
|
787
|
-
if (!domainAllowList) return;
|
|
788
|
-
const domain = extractDomainFromUrl(url$1);
|
|
789
|
-
for (const rule of domainAllowList) if (domain === rule.domain || domain.endsWith(`.${rule.domain}`) || domain === rule.domain.slice(1)) return rule;
|
|
790
|
-
}
|
|
791
|
-
/**
|
|
792
|
-
* Determines if request body should be captured based on priority:
|
|
793
|
-
* context > domain rule > global config > default (false)
|
|
794
|
-
*/
|
|
795
|
-
function shouldCaptureRequestBody(url$1) {
|
|
796
|
-
const contextValue = _opentelemetry_api.context.active().getValue(_pingops_core.PINGOPS_CAPTURE_REQUEST_BODY);
|
|
797
|
-
if (contextValue !== void 0) return contextValue;
|
|
798
|
-
if (url$1) {
|
|
799
|
-
const domainRule = getDomainRule(url$1, getGlobalConfig()?.domainAllowList);
|
|
800
|
-
if (domainRule?.captureRequestBody !== void 0) return domainRule.captureRequestBody;
|
|
801
|
-
}
|
|
802
|
-
const globalConfig$1 = getGlobalConfig();
|
|
803
|
-
if (globalConfig$1?.captureRequestBody !== void 0) return globalConfig$1.captureRequestBody;
|
|
804
|
-
return false;
|
|
805
|
-
}
|
|
806
|
-
/**
|
|
807
|
-
* Determines if response body should be captured based on priority:
|
|
808
|
-
* context > domain rule > global config > default (false)
|
|
809
|
-
*/
|
|
810
|
-
function shouldCaptureResponseBody(url$1) {
|
|
811
|
-
const contextValue = _opentelemetry_api.context.active().getValue(_pingops_core.PINGOPS_CAPTURE_RESPONSE_BODY);
|
|
812
|
-
if (contextValue !== void 0) return contextValue;
|
|
813
|
-
if (url$1) {
|
|
814
|
-
const domainRule = getDomainRule(url$1, getGlobalConfig()?.domainAllowList);
|
|
815
|
-
if (domainRule?.captureResponseBody !== void 0) return domainRule.captureResponseBody;
|
|
816
|
-
}
|
|
817
|
-
const globalConfig$1 = getGlobalConfig();
|
|
818
|
-
if (globalConfig$1?.captureResponseBody !== void 0) return globalConfig$1.captureResponseBody;
|
|
819
|
-
return false;
|
|
820
|
-
}
|
|
821
791
|
var UndiciInstrumentation = class extends _opentelemetry_instrumentation.InstrumentationBase {
|
|
822
792
|
_recordFromReq = /* @__PURE__ */ new WeakMap();
|
|
823
793
|
constructor(config = {}) {
|
|
@@ -925,7 +895,9 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
925
895
|
[_opentelemetry_semantic_conventions.ATTR_URL_FULL]: requestUrl.toString(),
|
|
926
896
|
[_opentelemetry_semantic_conventions.ATTR_URL_PATH]: requestUrl.pathname,
|
|
927
897
|
[_opentelemetry_semantic_conventions.ATTR_URL_QUERY]: requestUrl.search,
|
|
928
|
-
[_opentelemetry_semantic_conventions.ATTR_URL_SCHEME]: urlScheme
|
|
898
|
+
[_opentelemetry_semantic_conventions.ATTR_URL_SCHEME]: urlScheme,
|
|
899
|
+
[HTTP_REQUEST_BODY_SIZE]: 0,
|
|
900
|
+
[HTTP_RESPONSE_BODY_SIZE]: 0
|
|
929
901
|
};
|
|
930
902
|
const schemePorts = {
|
|
931
903
|
https: "443",
|
|
@@ -968,6 +940,10 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
968
940
|
responseBodyChunks: [],
|
|
969
941
|
requestBodySize: 0,
|
|
970
942
|
responseBodySize: 0,
|
|
943
|
+
requestBodyCaptureSize: 0,
|
|
944
|
+
responseBodyCaptureSize: 0,
|
|
945
|
+
requestBodyCaptureExceeded: false,
|
|
946
|
+
responseBodyCaptureExceeded: false,
|
|
971
947
|
url: requestUrl.toString()
|
|
972
948
|
});
|
|
973
949
|
}
|
|
@@ -1014,11 +990,13 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
1014
990
|
const record = this._recordFromReq.get(request);
|
|
1015
991
|
if (!record) return;
|
|
1016
992
|
const { span, attributes, startTime } = record;
|
|
993
|
+
span.setAttribute(HTTP_REQUEST_BODY_SIZE, record.requestBodySize);
|
|
994
|
+
span.setAttribute(HTTP_RESPONSE_BODY_SIZE, record.responseBodySize);
|
|
1017
995
|
if (shouldCaptureResponseBody(record.url)) {
|
|
1018
996
|
const maxResponseBodySize = this.getConfig().maxResponseBodySize ?? DEFAULT_MAX_RESPONSE_BODY_SIZE;
|
|
1019
997
|
const contentEncoding = record.attributes?.["http.response.header.content-encoding"] ?? void 0;
|
|
1020
998
|
const contentType = record.attributes?.["http.response.header.content-type"] ?? void 0;
|
|
1021
|
-
if (record.
|
|
999
|
+
if (record.responseBodyCaptureExceeded) span.setAttribute(HTTP_RESPONSE_BODY, `[truncated response body; exceeded maxResponseBodySize=${maxResponseBodySize}; content-type=${contentType ?? "unknown"}; content-encoding=${contentEncoding ?? "identity"}]`);
|
|
1022
1000
|
else if (record.responseBodyChunks.length > 0) try {
|
|
1023
1001
|
const responseBodyBuffer = Buffer.concat(record.responseBodyChunks);
|
|
1024
1002
|
if ((0, _pingops_core.isCompressedContentEncoding)(contentEncoding)) {
|
|
@@ -1040,8 +1018,10 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
1040
1018
|
const record = this._recordFromReq.get(request);
|
|
1041
1019
|
if (!record) return;
|
|
1042
1020
|
const { span, attributes, startTime } = record;
|
|
1021
|
+
span.setAttribute(HTTP_REQUEST_BODY_SIZE, record.requestBodySize);
|
|
1022
|
+
span.setAttribute(HTTP_RESPONSE_BODY_SIZE, record.responseBodySize);
|
|
1043
1023
|
if (shouldCaptureRequestBody(record.url)) {
|
|
1044
|
-
if (record.requestBodyChunks.length > 0 && record.
|
|
1024
|
+
if (record.requestBodyChunks.length > 0 && !record.requestBodyCaptureExceeded) try {
|
|
1045
1025
|
const requestBody = Buffer.concat(record.requestBodyChunks).toString("utf-8");
|
|
1046
1026
|
if (requestBody) span.setAttribute(HTTP_REQUEST_BODY, requestBody);
|
|
1047
1027
|
} catch (e) {
|
|
@@ -1062,24 +1042,29 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
1062
1042
|
onBodyChunkSent({ request, chunk }) {
|
|
1063
1043
|
const record = this._recordFromReq.get(request);
|
|
1064
1044
|
if (!record) return;
|
|
1045
|
+
record.requestBodySize += chunk.length;
|
|
1065
1046
|
if (!shouldCaptureRequestBody(record.url)) return;
|
|
1066
1047
|
const maxRequestBodySize = this.getConfig().maxRequestBodySize ?? DEFAULT_MAX_REQUEST_BODY_SIZE;
|
|
1067
|
-
if (record.
|
|
1048
|
+
if (!record.requestBodyCaptureExceeded && record.requestBodyCaptureSize + chunk.length <= maxRequestBodySize) {
|
|
1068
1049
|
record.requestBodyChunks.push(chunk);
|
|
1069
|
-
record.
|
|
1050
|
+
record.requestBodyCaptureSize += chunk.length;
|
|
1070
1051
|
} else {
|
|
1071
|
-
record.
|
|
1052
|
+
record.requestBodyCaptureExceeded = true;
|
|
1072
1053
|
record.requestBodyChunks = [];
|
|
1054
|
+
record.requestBodyCaptureSize = 0;
|
|
1073
1055
|
}
|
|
1074
1056
|
}
|
|
1075
1057
|
onBodySent({ request }) {
|
|
1076
1058
|
const record = this._recordFromReq.get(request);
|
|
1077
1059
|
if (!record) return;
|
|
1060
|
+
record.span.setAttribute(HTTP_REQUEST_BODY_SIZE, record.requestBodySize);
|
|
1078
1061
|
if (!shouldCaptureRequestBody(record.url)) {
|
|
1079
1062
|
record.requestBodyChunks = [];
|
|
1063
|
+
record.requestBodyCaptureSize = 0;
|
|
1064
|
+
record.requestBodyCaptureExceeded = false;
|
|
1080
1065
|
return;
|
|
1081
1066
|
}
|
|
1082
|
-
if (record.
|
|
1067
|
+
if (record.requestBodyCaptureExceeded) {
|
|
1083
1068
|
const maxRequestBodySize = this.getConfig().maxRequestBodySize ?? DEFAULT_MAX_REQUEST_BODY_SIZE;
|
|
1084
1069
|
record.span.setAttribute(HTTP_REQUEST_BODY, `[truncated request body; exceeded maxRequestBodySize=${maxRequestBodySize}]`);
|
|
1085
1070
|
} else if (record.requestBodyChunks.length > 0) try {
|
|
@@ -1089,18 +1074,22 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
1089
1074
|
this._diag.error("Error occurred while capturing request body:", e);
|
|
1090
1075
|
}
|
|
1091
1076
|
record.requestBodyChunks = [];
|
|
1077
|
+
record.requestBodyCaptureSize = 0;
|
|
1078
|
+
record.requestBodyCaptureExceeded = false;
|
|
1092
1079
|
}
|
|
1093
1080
|
onBodyChunkReceived({ request, chunk }) {
|
|
1094
1081
|
const record = this._recordFromReq.get(request);
|
|
1095
1082
|
if (!record) return;
|
|
1083
|
+
record.responseBodySize += chunk.length;
|
|
1096
1084
|
if (!shouldCaptureResponseBody(record.url)) return;
|
|
1097
1085
|
const maxResponseBodySize = this.getConfig().maxResponseBodySize ?? DEFAULT_MAX_RESPONSE_BODY_SIZE;
|
|
1098
|
-
if (record.
|
|
1086
|
+
if (!record.responseBodyCaptureExceeded && record.responseBodyCaptureSize + chunk.length <= maxResponseBodySize) {
|
|
1099
1087
|
record.responseBodyChunks.push(chunk);
|
|
1100
|
-
record.
|
|
1088
|
+
record.responseBodyCaptureSize += chunk.length;
|
|
1101
1089
|
} else {
|
|
1102
|
-
record.
|
|
1090
|
+
record.responseBodyCaptureExceeded = true;
|
|
1103
1091
|
record.responseBodyChunks = [];
|
|
1092
|
+
record.responseBodyCaptureSize = 0;
|
|
1104
1093
|
}
|
|
1105
1094
|
}
|
|
1106
1095
|
recordRequestDuration(attributes, startTime) {
|