@pingops/otel 0.2.4 → 0.2.5
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 +55 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +56 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -439,6 +439,7 @@ function resolveOutboundSpanParentContext(activeContext, requestUrl) {
|
|
|
439
439
|
*/
|
|
440
440
|
const DEFAULT_MAX_REQUEST_BODY_SIZE$1 = 4 * 1024;
|
|
441
441
|
const DEFAULT_MAX_RESPONSE_BODY_SIZE$1 = 4 * 1024;
|
|
442
|
+
const LEGACY_ATTR_HTTP_URL = "http.url";
|
|
442
443
|
const PingopsSemanticAttributes = {
|
|
443
444
|
HTTP_REQUEST_BODY: "http.request.body",
|
|
444
445
|
HTTP_RESPONSE_BODY: "http.response.body"
|
|
@@ -446,12 +447,18 @@ const PingopsSemanticAttributes = {
|
|
|
446
447
|
/**
|
|
447
448
|
* Manually flattens a nested object into dot-notation keys
|
|
448
449
|
*/
|
|
450
|
+
function isPlainObject(value) {
|
|
451
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Buffer);
|
|
452
|
+
}
|
|
453
|
+
function isPrimitiveArray(value) {
|
|
454
|
+
return value.every((item) => typeof item === "string" || typeof item === "number" || typeof item === "boolean");
|
|
455
|
+
}
|
|
449
456
|
function flatten(obj, prefix = "") {
|
|
450
457
|
const result = {};
|
|
451
458
|
for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
452
459
|
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
453
460
|
const value = obj[key];
|
|
454
|
-
if (
|
|
461
|
+
if (isPlainObject(value)) Object.assign(result, flatten(value, newKey));
|
|
455
462
|
else result[newKey] = value;
|
|
456
463
|
}
|
|
457
464
|
return result;
|
|
@@ -462,11 +469,9 @@ function flatten(obj, prefix = "") {
|
|
|
462
469
|
function setAttributeValue(span, attrName, attrValue) {
|
|
463
470
|
if (typeof attrValue === "string" || typeof attrValue === "number" || typeof attrValue === "boolean") span.setAttribute(attrName, attrValue);
|
|
464
471
|
else if (attrValue instanceof Buffer) span.setAttribute(attrName, attrValue.toString("utf8"));
|
|
465
|
-
else if (
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
if (typeof firstElement === "string" || typeof firstElement === "number" || typeof firstElement === "boolean") span.setAttribute(attrName, attrValue);
|
|
469
|
-
} else span.setAttribute(attrName, attrValue);
|
|
472
|
+
else if (Array.isArray(attrValue)) {
|
|
473
|
+
if (attrValue.length === 0 || isPrimitiveArray(attrValue)) span.setAttribute(attrName, attrValue);
|
|
474
|
+
} else if (isPlainObject(attrValue)) span.setAttributes(flatten({ [attrName]: attrValue }));
|
|
470
475
|
}
|
|
471
476
|
/**
|
|
472
477
|
* Extracts domain from URL
|
|
@@ -532,9 +537,16 @@ function captureRequestBody(span, data, maxSize, semanticAttr, url$1) {
|
|
|
532
537
|
/**
|
|
533
538
|
* Captures response body from chunks
|
|
534
539
|
*/
|
|
535
|
-
function captureResponseBody(span, chunks, semanticAttr, responseHeaders, url$1) {
|
|
540
|
+
function captureResponseBody(span, chunks, semanticAttr, responseHeaders, url$1, maxSize) {
|
|
536
541
|
if (!shouldCaptureResponseBody$1(url$1)) return;
|
|
537
|
-
if (chunks
|
|
542
|
+
if (chunks === null) {
|
|
543
|
+
const contentEncoding = responseHeaders?.["content-encoding"];
|
|
544
|
+
const contentType = responseHeaders?.["content-type"];
|
|
545
|
+
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$1}; content-type=${toHeaderString(contentType)}; content-encoding=${toHeaderString(contentEncoding)}]`);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (chunks.length) try {
|
|
538
550
|
const concatedChunks = Buffer.concat(chunks);
|
|
539
551
|
const contentEncoding = responseHeaders?.["content-encoding"];
|
|
540
552
|
if ((0, _pingops_core.isCompressedContentEncoding)(contentEncoding)) {
|
|
@@ -597,7 +609,7 @@ function extractRequestUrlFromSpanOptions(options) {
|
|
|
597
609
|
const attrs = options.attributes;
|
|
598
610
|
if (!attrs) return;
|
|
599
611
|
if (typeof attrs[_opentelemetry_semantic_conventions.ATTR_URL_FULL] === "string") return attrs[_opentelemetry_semantic_conventions.ATTR_URL_FULL];
|
|
600
|
-
if (typeof attrs[
|
|
612
|
+
if (typeof attrs[LEGACY_ATTR_HTTP_URL] === "string") return attrs[LEGACY_ATTR_HTTP_URL];
|
|
601
613
|
const scheme = typeof attrs[_opentelemetry_semantic_conventions.ATTR_URL_SCHEME] === "string" ? attrs[_opentelemetry_semantic_conventions.ATTR_URL_SCHEME] : "http";
|
|
602
614
|
const host = typeof attrs[_opentelemetry_semantic_conventions.ATTR_SERVER_ADDRESS] === "string" ? attrs[_opentelemetry_semantic_conventions.ATTR_SERVER_ADDRESS] : void 0;
|
|
603
615
|
if (!host) return;
|
|
@@ -636,17 +648,19 @@ var PingopsHttpInstrumentation = class extends _opentelemetry_instrumentation_ht
|
|
|
636
648
|
if (headers) captureRequestHeaders(span, headers);
|
|
637
649
|
if (request instanceof http.ClientRequest) {
|
|
638
650
|
const maxRequestBodySize = config?.maxRequestBodySize || DEFAULT_MAX_REQUEST_BODY_SIZE$1;
|
|
639
|
-
const
|
|
651
|
+
const hostHeader = request.getHeader("host");
|
|
652
|
+
const host = typeof hostHeader === "string" ? hostHeader : Array.isArray(hostHeader) ? hostHeader.join(",") : typeof hostHeader === "number" ? String(hostHeader) : void 0;
|
|
653
|
+
const url$1 = request.path && host ? `${request.protocol || "http:"}//${host}${request.path}` : void 0;
|
|
640
654
|
const originalWrite = request.write.bind(request);
|
|
641
655
|
const originalEnd = request.end.bind(request);
|
|
642
|
-
request.write = (data) => {
|
|
656
|
+
request.write = ((data, ...rest) => {
|
|
643
657
|
if (typeof data === "string" || data instanceof Buffer) captureRequestBody(span, data, maxRequestBodySize, PingopsSemanticAttributes.HTTP_REQUEST_BODY, url$1);
|
|
644
|
-
return originalWrite(data);
|
|
645
|
-
};
|
|
646
|
-
request.end = (data) => {
|
|
658
|
+
return originalWrite(data, ...rest);
|
|
659
|
+
});
|
|
660
|
+
request.end = ((data, ...rest) => {
|
|
647
661
|
if (typeof data === "string" || data instanceof Buffer) captureRequestBody(span, data, maxRequestBodySize, PingopsSemanticAttributes.HTTP_REQUEST_BODY, url$1);
|
|
648
|
-
return originalEnd(data);
|
|
649
|
-
};
|
|
662
|
+
return originalEnd(data, ...rest);
|
|
663
|
+
});
|
|
650
664
|
}
|
|
651
665
|
if (originalRequestHook) originalRequestHook(span, request);
|
|
652
666
|
};
|
|
@@ -663,15 +677,24 @@ var PingopsHttpInstrumentation = class extends _opentelemetry_instrumentation_ht
|
|
|
663
677
|
const shouldCapture = shouldCaptureResponseBody$1(url$1);
|
|
664
678
|
response.prependListener("data", (chunk) => {
|
|
665
679
|
if (!chunk || !shouldCapture) return;
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
680
|
+
let chunkBuffer = null;
|
|
681
|
+
if (typeof chunk === "string") chunkBuffer = Buffer.from(chunk);
|
|
682
|
+
else if (Buffer.isBuffer(chunk)) chunkBuffer = chunk;
|
|
683
|
+
else if (chunk instanceof Uint8Array) chunkBuffer = Buffer.from(chunk);
|
|
684
|
+
if (!chunkBuffer) return;
|
|
685
|
+
totalSize += chunkBuffer.length;
|
|
686
|
+
if (chunks && totalSize <= maxResponseBodySize) chunks.push(chunkBuffer);
|
|
687
|
+
else chunks = null;
|
|
674
688
|
});
|
|
689
|
+
let finalized = false;
|
|
690
|
+
const finalizeCapture = () => {
|
|
691
|
+
if (finalized) return;
|
|
692
|
+
finalized = true;
|
|
693
|
+
captureResponseBody(span, chunks, PingopsSemanticAttributes.HTTP_RESPONSE_BODY, headers, url$1, maxResponseBodySize);
|
|
694
|
+
};
|
|
695
|
+
response.prependOnceListener("end", finalizeCapture);
|
|
696
|
+
response.prependOnceListener("close", finalizeCapture);
|
|
697
|
+
response.prependOnceListener("aborted", finalizeCapture);
|
|
675
698
|
}
|
|
676
699
|
if (originalResponseHook) originalResponseHook(span, response);
|
|
677
700
|
};
|
|
@@ -925,11 +948,11 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
925
948
|
const record = this._recordFromReq.get(request);
|
|
926
949
|
if (!record) return;
|
|
927
950
|
const { span } = record;
|
|
928
|
-
const
|
|
929
|
-
const
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
951
|
+
const spanAttributes = {};
|
|
952
|
+
const remoteAddress = typeof socket.remoteAddress === "string" ? socket.remoteAddress : void 0;
|
|
953
|
+
const remotePort = typeof socket.remotePort === "number" ? socket.remotePort : void 0;
|
|
954
|
+
if (remoteAddress) spanAttributes[_opentelemetry_semantic_conventions.ATTR_NETWORK_PEER_ADDRESS] = remoteAddress;
|
|
955
|
+
if (remotePort !== void 0) spanAttributes[_opentelemetry_semantic_conventions.ATTR_NETWORK_PEER_PORT] = remotePort;
|
|
933
956
|
const headersMap = this.parseRequestHeaders(request);
|
|
934
957
|
for (const [name, value] of headersMap.entries()) {
|
|
935
958
|
const attrValue = Array.isArray(value) ? value.join(", ") : value;
|
|
@@ -998,14 +1021,15 @@ var UndiciInstrumentation = class extends _opentelemetry_instrumentation.Instrum
|
|
|
998
1021
|
this._diag.error("Error occurred while capturing request body:", e);
|
|
999
1022
|
}
|
|
1000
1023
|
}
|
|
1024
|
+
const errorMessage = error.message;
|
|
1001
1025
|
span.recordException(error);
|
|
1002
1026
|
span.setStatus({
|
|
1003
1027
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
1004
|
-
message:
|
|
1028
|
+
message: errorMessage
|
|
1005
1029
|
});
|
|
1006
1030
|
span.end();
|
|
1007
1031
|
this._recordFromReq.delete(request);
|
|
1008
|
-
attributes[_opentelemetry_semantic_conventions.ATTR_ERROR_TYPE] =
|
|
1032
|
+
attributes[_opentelemetry_semantic_conventions.ATTR_ERROR_TYPE] = errorMessage;
|
|
1009
1033
|
this.recordRequestDuration(attributes, startTime);
|
|
1010
1034
|
}
|
|
1011
1035
|
onBodyChunkSent({ request, chunk }) {
|