@reproapp/node-sdk 0.0.5 → 0.0.7
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.ts +16 -10
- package/dist/index.js +630 -580
- package/package.json +2 -2
- package/src/index.ts +739 -647
- package/test/circular-capture.test.js +1 -1
- package/test/disable-subtree.test.js +1 -1
- package/test/kafka-runtime-privacy-policy.test.js +451 -18
- package/test/request-flush-timing.test.js +123 -0
- package/test/runtime-privacy-materialization.test.js +76 -0
package/dist/index.js
CHANGED
|
@@ -736,6 +736,9 @@ function traceEventCandidateFromRecord(event) {
|
|
|
736
736
|
library: inferLibraryNameFromFile(sourceFileForLibrary ?? event.file),
|
|
737
737
|
};
|
|
738
738
|
}
|
|
739
|
+
function shouldOmitJsonBuiltinTraceValues(event) {
|
|
740
|
+
return event.fn === 'JSON.parse' || event.fn === 'JSON.stringify';
|
|
741
|
+
}
|
|
739
742
|
function preparePendingTraceEventsForFlush(events) {
|
|
740
743
|
const prepared = [];
|
|
741
744
|
const excludedSpanIds = new Set();
|
|
@@ -755,6 +758,13 @@ function preparePendingTraceEventsForFlush(events) {
|
|
|
755
758
|
}
|
|
756
759
|
if (event.__reproPending) {
|
|
757
760
|
event.__reproPending.candidate = candidate;
|
|
761
|
+
if (shouldOmitJsonBuiltinTraceValues(candidate)) {
|
|
762
|
+
delete event.__reproPending.argsRaw;
|
|
763
|
+
delete event.__reproPending.returnValueRaw;
|
|
764
|
+
if (event.__reproPending.errorRaw === undefined) {
|
|
765
|
+
delete event.__reproPending;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
758
768
|
}
|
|
759
769
|
delete event.__reproSourceFile;
|
|
760
770
|
prepared.push(event);
|
|
@@ -807,6 +817,12 @@ const SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = (() => {
|
|
|
807
817
|
return env;
|
|
808
818
|
return 1000;
|
|
809
819
|
})();
|
|
820
|
+
const SDK_BACKGROUND_MAX_DEFER_MS = (() => {
|
|
821
|
+
const env = Number(process.env.REPRO_SDK_BACKGROUND_MAX_DEFER_MS);
|
|
822
|
+
if (Number.isFinite(env) && env >= 0)
|
|
823
|
+
return Math.trunc(env);
|
|
824
|
+
return 2000;
|
|
825
|
+
})();
|
|
810
826
|
const SDK_BACKGROUND_WORK_TIMEOUT_MS = (() => {
|
|
811
827
|
const env = Number(process.env.REPRO_SDK_BACKGROUND_WORK_TIMEOUT_MS);
|
|
812
828
|
if (Number.isFinite(env) && env >= 0)
|
|
@@ -844,6 +860,7 @@ const TRACE_MATERIALIZE_WORKER_IDLE_SHUTDOWN_MS = (() => {
|
|
|
844
860
|
return 500;
|
|
845
861
|
})();
|
|
846
862
|
let activeClientRequestCount = 0;
|
|
863
|
+
let oldestActiveClientRequestAt = null;
|
|
847
864
|
let lastClientActivityAt = 0;
|
|
848
865
|
let sdkBackgroundQuietUntil = 0;
|
|
849
866
|
const sdkBackgroundQueue = [];
|
|
@@ -863,6 +880,12 @@ function noteClientActivity(now = Date.now()) {
|
|
|
863
880
|
}
|
|
864
881
|
function getSdkBackgroundDelayMs(now = Date.now()) {
|
|
865
882
|
if (hasActiveClientRequests()) {
|
|
883
|
+
if (oldestActiveClientRequestAt !== null && SDK_BACKGROUND_MAX_DEFER_MS >= 0) {
|
|
884
|
+
const activeForMs = now - oldestActiveClientRequestAt;
|
|
885
|
+
if (activeForMs >= SDK_BACKGROUND_MAX_DEFER_MS)
|
|
886
|
+
return 0;
|
|
887
|
+
return Math.min(SDK_BACKGROUND_IDLE_DELAY_MS, Math.max(0, SDK_BACKGROUND_MAX_DEFER_MS - activeForMs));
|
|
888
|
+
}
|
|
866
889
|
return SDK_BACKGROUND_IDLE_DELAY_MS;
|
|
867
890
|
}
|
|
868
891
|
const sinceLastActivity = now - lastClientActivityAt;
|
|
@@ -1077,12 +1100,21 @@ function shouldOffloadPendingTraceEvents(events) {
|
|
|
1077
1100
|
const pending = event.__reproPending;
|
|
1078
1101
|
if (!pending)
|
|
1079
1102
|
continue;
|
|
1080
|
-
if (pending.argsRaw !== undefined)
|
|
1103
|
+
if (pending.argsRaw !== undefined) {
|
|
1104
|
+
if (traceInlineValueExceedsLimit(pending.argsRaw))
|
|
1105
|
+
return false;
|
|
1081
1106
|
pendingValueCount += 1;
|
|
1082
|
-
|
|
1107
|
+
}
|
|
1108
|
+
if (pending.returnValueRaw !== undefined) {
|
|
1109
|
+
if (traceInlineValueExceedsLimit(pending.returnValueRaw))
|
|
1110
|
+
return false;
|
|
1083
1111
|
pendingValueCount += 1;
|
|
1084
|
-
|
|
1112
|
+
}
|
|
1113
|
+
if (pending.errorRaw !== undefined) {
|
|
1114
|
+
if (traceInlineValueExceedsLimit(pending.errorRaw))
|
|
1115
|
+
return false;
|
|
1085
1116
|
pendingValueCount += 1;
|
|
1117
|
+
}
|
|
1086
1118
|
if (pendingValueCount >= TRACE_MATERIALIZE_OFFTHREAD_MIN_VALUES) {
|
|
1087
1119
|
return true;
|
|
1088
1120
|
}
|
|
@@ -1095,6 +1127,9 @@ function beginClientRequest() {
|
|
|
1095
1127
|
sdkBackgroundQuietUntil = Math.max(sdkBackgroundQuietUntil, now + SDK_BACKGROUND_BUSY_IDLE_DELAY_MS);
|
|
1096
1128
|
}
|
|
1097
1129
|
noteClientActivity(now);
|
|
1130
|
+
if (activeClientRequestCount === 0) {
|
|
1131
|
+
oldestActiveClientRequestAt = now;
|
|
1132
|
+
}
|
|
1098
1133
|
activeClientRequestCount += 1;
|
|
1099
1134
|
if (sdkBackgroundTimer) {
|
|
1100
1135
|
try {
|
|
@@ -1108,6 +1143,7 @@ function endClientRequest() {
|
|
|
1108
1143
|
activeClientRequestCount = Math.max(0, activeClientRequestCount - 1);
|
|
1109
1144
|
noteClientActivity();
|
|
1110
1145
|
if (!hasActiveClientRequests()) {
|
|
1146
|
+
oldestActiveClientRequestAt = null;
|
|
1111
1147
|
(0, client_1.kickIngestQueueDrain)();
|
|
1112
1148
|
if (sdkBackgroundTimer) {
|
|
1113
1149
|
try {
|
|
@@ -1609,26 +1645,17 @@ const TRACE_VALUE_MAX_DEPTH = 3;
|
|
|
1609
1645
|
const TRACE_VALUE_MAX_KEYS = 20;
|
|
1610
1646
|
const TRACE_VALUE_MAX_ITEMS = 20;
|
|
1611
1647
|
const TRACE_VALUE_MAX_STRING = 2000;
|
|
1612
|
-
const TRACE_FULL_VALUE_MAX_DEPTH =
|
|
1613
|
-
const TRACE_FULL_VALUE_MAX_KEYS =
|
|
1614
|
-
const TRACE_FULL_VALUE_MAX_ITEMS =
|
|
1615
|
-
const TRACE_FULL_VALUE_MAX_STRING =
|
|
1616
|
-
const
|
|
1617
|
-
const
|
|
1618
|
-
const TRACE_FULL_VALUE_FALLBACK_ITEMS = 100;
|
|
1619
|
-
const TRACE_FULL_VALUE_FALLBACK_STRING = 8000;
|
|
1620
|
-
const TRACE_FULL_VALUE_MAX_SERIALIZED_CHARS = 128 * 1024;
|
|
1621
|
-
const INLINE_PRIVACY_MAX_SERIALIZED_CHARS = (() => {
|
|
1622
|
-
const env = Number(process.env.REPRO_SDK_INLINE_PRIVACY_MAX_SERIALIZED_CHARS);
|
|
1648
|
+
const TRACE_FULL_VALUE_MAX_DEPTH = Number.MAX_SAFE_INTEGER;
|
|
1649
|
+
const TRACE_FULL_VALUE_MAX_KEYS = Number.MAX_SAFE_INTEGER;
|
|
1650
|
+
const TRACE_FULL_VALUE_MAX_ITEMS = Number.MAX_SAFE_INTEGER;
|
|
1651
|
+
const TRACE_FULL_VALUE_MAX_STRING = Number.MAX_SAFE_INTEGER;
|
|
1652
|
+
const TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS = (() => {
|
|
1653
|
+
const env = Number(process.env.REPRO_SDK_TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS);
|
|
1623
1654
|
if (Number.isFinite(env) && env > 0)
|
|
1624
1655
|
return Math.trunc(env);
|
|
1625
1656
|
return 8 * 1024;
|
|
1626
1657
|
})();
|
|
1627
|
-
const
|
|
1628
|
-
const INLINE_PRIVACY_PREVIEW_MAX_KEYS = 12;
|
|
1629
|
-
const INLINE_PRIVACY_PREVIEW_MAX_ITEMS = 12;
|
|
1630
|
-
const INLINE_PRIVACY_PREVIEW_MAX_STRING = 512;
|
|
1631
|
-
const INLINE_PRIVACY_PREVIEW_JSON_PARSE_MAX_CHARS = 128 * 1024;
|
|
1658
|
+
const TRACE_VALUE_SIZE_EXCEEDED = Symbol('trace-value-size-exceeded');
|
|
1632
1659
|
const TRACE_BATCH_SIZE = 100;
|
|
1633
1660
|
const TRACE_FLUSH_DELAY_MS = 20;
|
|
1634
1661
|
// Choose how to order trace events in payloads.
|
|
@@ -1954,7 +1981,7 @@ function sanitizeTraceValue(value, depth = 0, seen = new WeakMap(), options = {}
|
|
|
1954
1981
|
if (existingPath)
|
|
1955
1982
|
return circularReference(existingPath);
|
|
1956
1983
|
seen.set(value, valuePath);
|
|
1957
|
-
if (depth >= TRACE_VALUE_MAX_DEPTH) {
|
|
1984
|
+
if (!options.disableTruncation && depth >= TRACE_VALUE_MAX_DEPTH) {
|
|
1958
1985
|
const shallow = safeJson(value);
|
|
1959
1986
|
if (shallow !== undefined) {
|
|
1960
1987
|
return shallow;
|
|
@@ -1965,9 +1992,10 @@ function sanitizeTraceValue(value, depth = 0, seen = new WeakMap(), options = {}
|
|
|
1965
1992
|
: { __truncated: `depth>${TRACE_VALUE_MAX_DEPTH}` };
|
|
1966
1993
|
}
|
|
1967
1994
|
if (Array.isArray(value)) {
|
|
1968
|
-
const
|
|
1995
|
+
const sourceItems = options.disableTruncation ? value : value.slice(0, TRACE_VALUE_MAX_ITEMS);
|
|
1996
|
+
const out = sourceItems
|
|
1969
1997
|
.map((item, index) => sanitizeTraceValue(item, depth + 1, seen, options, childCapturePath(valuePath, index)));
|
|
1970
|
-
if (value.length > TRACE_VALUE_MAX_ITEMS) {
|
|
1998
|
+
if (!options.disableTruncation && value.length > TRACE_VALUE_MAX_ITEMS) {
|
|
1971
1999
|
out.push(`…(${value.length - TRACE_VALUE_MAX_ITEMS} more items)`);
|
|
1972
2000
|
}
|
|
1973
2001
|
return out;
|
|
@@ -1976,13 +2004,13 @@ function sanitizeTraceValue(value, depth = 0, seen = new WeakMap(), options = {}
|
|
|
1976
2004
|
const out = {};
|
|
1977
2005
|
let index = 0;
|
|
1978
2006
|
for (const [k, v] of value) {
|
|
1979
|
-
if (index >= TRACE_VALUE_MAX_ITEMS)
|
|
2007
|
+
if (!options.disableTruncation && index >= TRACE_VALUE_MAX_ITEMS)
|
|
1980
2008
|
break;
|
|
1981
2009
|
const key = normalizeCollectionKeyForCapture(k, index);
|
|
1982
2010
|
out[key] = sanitizeTraceValue(v, depth + 1, seen, options, childCapturePath(valuePath, key));
|
|
1983
2011
|
index += 1;
|
|
1984
2012
|
}
|
|
1985
|
-
if (value.size > TRACE_VALUE_MAX_ITEMS) {
|
|
2013
|
+
if (!options.disableTruncation && value.size > TRACE_VALUE_MAX_ITEMS) {
|
|
1986
2014
|
out.__truncatedEntries = value.size - TRACE_VALUE_MAX_ITEMS;
|
|
1987
2015
|
}
|
|
1988
2016
|
return out;
|
|
@@ -1990,11 +2018,11 @@ function sanitizeTraceValue(value, depth = 0, seen = new WeakMap(), options = {}
|
|
|
1990
2018
|
if (value instanceof Set) {
|
|
1991
2019
|
const arr = [];
|
|
1992
2020
|
for (const item of value) {
|
|
1993
|
-
if (arr.length >= TRACE_VALUE_MAX_ITEMS)
|
|
2021
|
+
if (!options.disableTruncation && arr.length >= TRACE_VALUE_MAX_ITEMS)
|
|
1994
2022
|
break;
|
|
1995
2023
|
arr.push(sanitizeTraceValue(item, depth + 1, seen, options, childCapturePath(valuePath, arr.length)));
|
|
1996
2024
|
}
|
|
1997
|
-
if (value.size > TRACE_VALUE_MAX_ITEMS) {
|
|
2025
|
+
if (!options.disableTruncation && value.size > TRACE_VALUE_MAX_ITEMS) {
|
|
1998
2026
|
arr.push(`…(${value.size - TRACE_VALUE_MAX_ITEMS} more items)`);
|
|
1999
2027
|
}
|
|
2000
2028
|
return arr;
|
|
@@ -2002,7 +2030,8 @@ function sanitizeTraceValue(value, depth = 0, seen = new WeakMap(), options = {}
|
|
|
2002
2030
|
const ctor = value?.constructor?.name;
|
|
2003
2031
|
const result = {};
|
|
2004
2032
|
const keys = Object.keys(value);
|
|
2005
|
-
|
|
2033
|
+
const visibleKeys = options.disableTruncation ? keys : keys.slice(0, TRACE_VALUE_MAX_KEYS);
|
|
2034
|
+
for (const key of visibleKeys) {
|
|
2006
2035
|
try {
|
|
2007
2036
|
result[key] = sanitizeTraceValue(value[key], depth + 1, seen, options, childCapturePath(valuePath, key));
|
|
2008
2037
|
}
|
|
@@ -2010,7 +2039,7 @@ function sanitizeTraceValue(value, depth = 0, seen = new WeakMap(), options = {}
|
|
|
2010
2039
|
result[key] = `[Cannot serialize: ${err?.message || 'unknown error'}]`;
|
|
2011
2040
|
}
|
|
2012
2041
|
}
|
|
2013
|
-
if (keys.length > TRACE_VALUE_MAX_KEYS) {
|
|
2042
|
+
if (!options.disableTruncation && keys.length > TRACE_VALUE_MAX_KEYS) {
|
|
2014
2043
|
result.__truncatedKeys = keys.length - TRACE_VALUE_MAX_KEYS;
|
|
2015
2044
|
}
|
|
2016
2045
|
if (ctor && ctor !== 'Object') {
|
|
@@ -2024,7 +2053,10 @@ function sanitizeTraceArgs(values) {
|
|
|
2024
2053
|
return values.map((v, index) => sanitizeTraceValue(v, 0, new WeakMap(), {}, `$[${index}]`));
|
|
2025
2054
|
}
|
|
2026
2055
|
function sanitizeTraceValueForPrivacy(value) {
|
|
2027
|
-
return sanitizeTraceValue(value, 0, new WeakMap(), { preserveLongStrings: true });
|
|
2056
|
+
return sanitizeTraceValue(value, 0, new WeakMap(), { preserveLongStrings: true, disableTruncation: true });
|
|
2057
|
+
}
|
|
2058
|
+
function sanitizeMaterializedTraceValue(value) {
|
|
2059
|
+
return sanitizeTraceValue(value, 0, new WeakMap(), { preserveLongStrings: true, disableTruncation: true });
|
|
2028
2060
|
}
|
|
2029
2061
|
function sanitizeTraceArgsForPrivacy(values) {
|
|
2030
2062
|
if (!Array.isArray(values))
|
|
@@ -2036,6 +2068,9 @@ function normalizeRawTraceArgs(values) {
|
|
|
2036
2068
|
return values;
|
|
2037
2069
|
return [values];
|
|
2038
2070
|
}
|
|
2071
|
+
function hasMeaningfulRawTraceError(error) {
|
|
2072
|
+
return error !== undefined && error !== null;
|
|
2073
|
+
}
|
|
2039
2074
|
async function materializePendingTraceEvents(events, params) {
|
|
2040
2075
|
for (const evt of events) {
|
|
2041
2076
|
const pending = evt.__reproPending;
|
|
@@ -2043,74 +2078,16 @@ async function materializePendingTraceEvents(events, params) {
|
|
|
2043
2078
|
continue;
|
|
2044
2079
|
delete evt.__reproPending;
|
|
2045
2080
|
const candidate = pending.candidate ?? traceEventCandidateFromRecord(evt);
|
|
2081
|
+
const omitJsonBuiltinValues = shouldOmitJsonBuiltinTraceValues(candidate);
|
|
2046
2082
|
const activePrivacy = params.resolvePrivacy();
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
captureHeaders: params.cfg.captureHeaders,
|
|
2050
|
-
maskReq: params.maskReq,
|
|
2051
|
-
trace: candidate,
|
|
2052
|
-
masking: params.masking,
|
|
2053
|
-
privacy: activePrivacy,
|
|
2054
|
-
};
|
|
2055
|
-
if (pending.argsRaw !== undefined) {
|
|
2056
|
-
const argsPreview = sanitizeTraceArgsForPrivacy(pending.argsRaw);
|
|
2057
|
-
const argsMaterialization = await materializeInlinePrivacyValueAsync('trace.args', argsPreview, params.cfg, params.maskReq, candidate, params.masking, activePrivacy);
|
|
2058
|
-
if (argsMaterialization.skipped) {
|
|
2059
|
-
evt.argsMaterialization = argsMaterialization.skipped;
|
|
2060
|
-
if (argsMaterialization.value !== undefined) {
|
|
2061
|
-
evt.args = sanitizeTraceValue(argsMaterialization.value);
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
else {
|
|
2065
|
-
evt.args = sanitizeTraceValue(argsMaterialization.value);
|
|
2066
|
-
evt.argsValueCapture = await maybeCaptureFullTraceValueAsync({
|
|
2067
|
-
target: 'trace.args',
|
|
2068
|
-
rawValue: pending.argsRaw,
|
|
2069
|
-
previewValue: evt.args,
|
|
2070
|
-
event: evt,
|
|
2071
|
-
capture,
|
|
2072
|
-
});
|
|
2073
|
-
}
|
|
2083
|
+
if (!omitJsonBuiltinValues && pending.argsRaw !== undefined) {
|
|
2084
|
+
evt.args = sanitizeMaterializedTraceValue(await materializeTracePrivacyValueAsync('trace.args', sanitizeTraceArgsForPrivacy(pending.argsRaw), params.cfg, params.maskReq, candidate, params.masking, activePrivacy));
|
|
2074
2085
|
}
|
|
2075
|
-
if (pending.returnValueRaw !== undefined) {
|
|
2076
|
-
|
|
2077
|
-
const returnValueMaterialization = await materializeInlinePrivacyValueAsync('trace.returnValue', returnValuePreview, params.cfg, params.maskReq, candidate, params.masking, activePrivacy);
|
|
2078
|
-
if (returnValueMaterialization.skipped) {
|
|
2079
|
-
evt.returnValueMaterialization = returnValueMaterialization.skipped;
|
|
2080
|
-
if (returnValueMaterialization.value !== undefined) {
|
|
2081
|
-
evt.returnValue = sanitizeTraceValue(returnValueMaterialization.value);
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
else {
|
|
2085
|
-
evt.returnValue = sanitizeTraceValue(returnValueMaterialization.value);
|
|
2086
|
-
evt.returnValueCapture = await maybeCaptureFullTraceValueAsync({
|
|
2087
|
-
target: 'trace.returnValue',
|
|
2088
|
-
rawValue: pending.returnValueRaw,
|
|
2089
|
-
previewValue: evt.returnValue,
|
|
2090
|
-
event: evt,
|
|
2091
|
-
capture,
|
|
2092
|
-
});
|
|
2093
|
-
}
|
|
2086
|
+
if (!omitJsonBuiltinValues && pending.returnValueRaw !== undefined) {
|
|
2087
|
+
evt.returnValue = sanitizeMaterializedTraceValue(await materializeTracePrivacyValueAsync('trace.returnValue', sanitizeTraceValueForPrivacy(pending.returnValueRaw), params.cfg, params.maskReq, candidate, params.masking, activePrivacy));
|
|
2094
2088
|
}
|
|
2095
2089
|
if (pending.errorRaw !== undefined) {
|
|
2096
|
-
|
|
2097
|
-
const errorMaterialization = await materializeInlinePrivacyValueAsync('trace.error', errorPreview, params.cfg, params.maskReq, candidate, params.masking, activePrivacy);
|
|
2098
|
-
if (errorMaterialization.skipped) {
|
|
2099
|
-
evt.errorMaterialization = errorMaterialization.skipped;
|
|
2100
|
-
if (errorMaterialization.value !== undefined) {
|
|
2101
|
-
evt.error = sanitizeTraceValue(errorMaterialization.value);
|
|
2102
|
-
}
|
|
2103
|
-
}
|
|
2104
|
-
else {
|
|
2105
|
-
evt.error = sanitizeTraceValue(errorMaterialization.value);
|
|
2106
|
-
evt.errorValueCapture = await maybeCaptureFullTraceValueAsync({
|
|
2107
|
-
target: 'trace.error',
|
|
2108
|
-
rawValue: pending.errorRaw,
|
|
2109
|
-
previewValue: evt.error,
|
|
2110
|
-
event: evt,
|
|
2111
|
-
capture,
|
|
2112
|
-
});
|
|
2113
|
-
}
|
|
2090
|
+
evt.error = sanitizeMaterializedTraceValue(await materializeTracePrivacyValueAsync('trace.error', sanitizeTraceValueForPrivacy(pending.errorRaw), params.cfg, params.maskReq, candidate, params.masking, activePrivacy));
|
|
2114
2091
|
}
|
|
2115
2092
|
}
|
|
2116
2093
|
return events;
|
|
@@ -2120,10 +2097,6 @@ function stripPendingTraceValues(events, reason) {
|
|
|
2120
2097
|
if (!evt.__reproPending)
|
|
2121
2098
|
continue;
|
|
2122
2099
|
delete evt.__reproPending;
|
|
2123
|
-
evt.valueMaterialization = {
|
|
2124
|
-
status: 'skipped',
|
|
2125
|
-
reason,
|
|
2126
|
-
};
|
|
2127
2100
|
}
|
|
2128
2101
|
return events;
|
|
2129
2102
|
}
|
|
@@ -2203,7 +2176,7 @@ function sanitizeRequestSnapshot(value) {
|
|
|
2203
2176
|
if (value === undefined)
|
|
2204
2177
|
return undefined;
|
|
2205
2178
|
try {
|
|
2206
|
-
return sanitizeTraceValue(value);
|
|
2179
|
+
return sanitizeTraceValue(value, 0, new WeakMap(), { preserveLongStrings: true, disableTruncation: true });
|
|
2207
2180
|
}
|
|
2208
2181
|
catch {
|
|
2209
2182
|
if (value === null)
|
|
@@ -2396,6 +2369,21 @@ function shareRuntimePrivacyState(source, target) {
|
|
|
2396
2369
|
function shouldCapturePrivacyRaw(cfg) {
|
|
2397
2370
|
return cfg.privacy?.captureRaw === true;
|
|
2398
2371
|
}
|
|
2372
|
+
function normalizeValueForRuntimePrivacy(value) {
|
|
2373
|
+
if (value === undefined || value === null) {
|
|
2374
|
+
return value;
|
|
2375
|
+
}
|
|
2376
|
+
try {
|
|
2377
|
+
return sanitizeTraceValue(value, 0, new WeakMap(), {
|
|
2378
|
+
preserveLongStrings: true,
|
|
2379
|
+
disableTruncation: true,
|
|
2380
|
+
});
|
|
2381
|
+
}
|
|
2382
|
+
catch {
|
|
2383
|
+
const fallback = safeJson(value);
|
|
2384
|
+
return fallback === undefined ? value : fallback;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2399
2387
|
function resolveRuntimePrivacyStartupMaxWaitMs(cfg) {
|
|
2400
2388
|
const value = Number(cfg?.startupMaxWaitMs);
|
|
2401
2389
|
if (!Number.isFinite(value)) {
|
|
@@ -2560,7 +2548,8 @@ function applyPrivacyThenMask(target, value, cfg, req, trace, masking, privacy,
|
|
|
2560
2548
|
if (shouldCapturePrivacyRaw(cfg)) {
|
|
2561
2549
|
return value;
|
|
2562
2550
|
}
|
|
2563
|
-
const
|
|
2551
|
+
const privacyInput = normalizeValueForRuntimePrivacy(value);
|
|
2552
|
+
const transformed = (0, privacy_1.applyRuntimePrivacyPolicy)(privacy, target, privacyInput, {
|
|
2564
2553
|
routeKey: req.key,
|
|
2565
2554
|
trace: trace
|
|
2566
2555
|
? {
|
|
@@ -2579,7 +2568,8 @@ async function applyPrivacyThenMaskAsync(target, value, cfg, req, trace, masking
|
|
|
2579
2568
|
if (shouldCapturePrivacyRaw(cfg)) {
|
|
2580
2569
|
return value;
|
|
2581
2570
|
}
|
|
2582
|
-
const
|
|
2571
|
+
const privacyInput = normalizeValueForRuntimePrivacy(value);
|
|
2572
|
+
const transformed = await (0, privacy_1.applyRuntimePrivacyPolicyAsync)(privacy, target, privacyInput, {
|
|
2583
2573
|
routeKey: req.key,
|
|
2584
2574
|
trace: trace
|
|
2585
2575
|
? {
|
|
@@ -2594,174 +2584,43 @@ async function applyPrivacyThenMaskAsync(target, value, cfg, req, trace, masking
|
|
|
2594
2584
|
});
|
|
2595
2585
|
return applyMasking(target, transformed, req, trace, masking);
|
|
2596
2586
|
}
|
|
2597
|
-
function
|
|
2598
|
-
return (
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
return value;
|
|
2612
|
-
const type = typeof value;
|
|
2613
|
-
if (type === 'string') {
|
|
2614
|
-
if (value.length <= INLINE_PRIVACY_PREVIEW_MAX_STRING) {
|
|
2615
|
-
return preserveScalarValue ? value : { __type: 'string', length: value.length };
|
|
2616
|
-
}
|
|
2617
|
-
const trimmed = value.trim();
|
|
2618
|
-
const mayBeJson = trimmed.startsWith('{') || trimmed.startsWith('[');
|
|
2619
|
-
if (mayBeJson && value.length <= INLINE_PRIVACY_PREVIEW_JSON_PARSE_MAX_CHARS) {
|
|
2620
|
-
try {
|
|
2621
|
-
return {
|
|
2622
|
-
__type: 'json-string',
|
|
2623
|
-
length: value.length,
|
|
2624
|
-
parsed: buildOversizedInlinePreview(JSON.parse(value), depth + 1, seen, false),
|
|
2625
|
-
};
|
|
2626
|
-
}
|
|
2627
|
-
catch { }
|
|
2628
|
-
}
|
|
2629
|
-
return {
|
|
2630
|
-
__type: 'string',
|
|
2631
|
-
length: value.length,
|
|
2632
|
-
truncated: true,
|
|
2633
|
-
};
|
|
2634
|
-
}
|
|
2635
|
-
if (type === 'number' || type === 'boolean')
|
|
2636
|
-
return preserveScalarValue ? value : { __type: type };
|
|
2637
|
-
if (type === 'bigint')
|
|
2638
|
-
return preserveScalarValue ? `${value.toString()}n` : { __type: 'bigint' };
|
|
2639
|
-
if (type === 'symbol')
|
|
2640
|
-
return preserveScalarValue ? value.toString() : { __type: 'symbol' };
|
|
2641
|
-
if (type === 'function')
|
|
2642
|
-
return `[Function${value.name ? ` ${value.name}` : ''}]`;
|
|
2643
|
-
if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
2644
|
-
return {
|
|
2645
|
-
__type: Buffer.isBuffer(value) ? 'Buffer' : 'Uint8Array',
|
|
2646
|
-
length: value.length,
|
|
2647
|
-
preview: value.length ? Buffer.from(value).slice(0, 32).toString('hex') : '',
|
|
2648
|
-
};
|
|
2649
|
-
}
|
|
2650
|
-
if (value instanceof Date)
|
|
2651
|
-
return preserveScalarValue ? value.toISOString() : { __type: 'Date' };
|
|
2652
|
-
if (value instanceof RegExp)
|
|
2653
|
-
return preserveScalarValue ? value.toString() : { __type: 'RegExp' };
|
|
2654
|
-
if (value instanceof Error) {
|
|
2655
|
-
return {
|
|
2656
|
-
__type: 'Error',
|
|
2657
|
-
name: value.name,
|
|
2658
|
-
message: preserveScalarValue ? value.message : { __type: 'string', length: value.message.length },
|
|
2659
|
-
};
|
|
2660
|
-
}
|
|
2661
|
-
if (value instanceof WeakMap || value instanceof WeakSet) {
|
|
2662
|
-
return { __type: getCtorName(value) || 'WeakCollection', uninspectable: true };
|
|
2663
|
-
}
|
|
2664
|
-
if (type !== 'object')
|
|
2665
|
-
return preserveScalarValue ? String(value) : { __type: type };
|
|
2666
|
-
if (seen.has(value))
|
|
2667
|
-
return { __type: 'circular-reference' };
|
|
2668
|
-
seen.add(value);
|
|
2669
|
-
if (Array.isArray(value)) {
|
|
2670
|
-
const items = value
|
|
2671
|
-
.slice(0, INLINE_PRIVACY_PREVIEW_MAX_ITEMS)
|
|
2672
|
-
.map((item) => buildOversizedInlinePreview(item, depth + 1, seen, true));
|
|
2673
|
-
if (value.length > INLINE_PRIVACY_PREVIEW_MAX_ITEMS) {
|
|
2674
|
-
items.push({ __truncatedItems: value.length - INLINE_PRIVACY_PREVIEW_MAX_ITEMS });
|
|
2675
|
-
}
|
|
2676
|
-
return items;
|
|
2677
|
-
}
|
|
2678
|
-
if (value instanceof Map) {
|
|
2679
|
-
const out = { __type: 'Map', size: value.size };
|
|
2680
|
-
let index = 0;
|
|
2681
|
-
for (const [key, item] of value.entries()) {
|
|
2682
|
-
if (index >= INLINE_PRIVACY_PREVIEW_MAX_ITEMS)
|
|
2683
|
-
break;
|
|
2684
|
-
out[normalizeCollectionKeyForCapture(key, index)] = buildOversizedInlinePreview(item, depth + 1, seen, false);
|
|
2685
|
-
index += 1;
|
|
2686
|
-
}
|
|
2687
|
-
if (value.size > INLINE_PRIVACY_PREVIEW_MAX_ITEMS) {
|
|
2688
|
-
out.__truncatedEntries = value.size - INLINE_PRIVACY_PREVIEW_MAX_ITEMS;
|
|
2689
|
-
}
|
|
2690
|
-
return out;
|
|
2587
|
+
function traceInlineValueExceedsLimit(value) {
|
|
2588
|
+
return boundedSerializedTraceValueLength(value, TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS).exceeded;
|
|
2589
|
+
}
|
|
2590
|
+
function limitInlinePrivacyValue(target, value) {
|
|
2591
|
+
void target;
|
|
2592
|
+
return { value };
|
|
2593
|
+
}
|
|
2594
|
+
function limitRawInlinePrivacyValue(target, value) {
|
|
2595
|
+
const limited = limitInlinePrivacyValue(target, value);
|
|
2596
|
+
return limited.skipped ? limited : null;
|
|
2597
|
+
}
|
|
2598
|
+
function materializeInlinePrivacyValue(target, value, cfg, req, trace, masking, privacy, db) {
|
|
2599
|
+
if (value === undefined || shouldCapturePrivacyRaw(cfg)) {
|
|
2600
|
+
return { value };
|
|
2691
2601
|
}
|
|
2692
|
-
|
|
2693
|
-
const
|
|
2694
|
-
|
|
2695
|
-
for (const item of value.values()) {
|
|
2696
|
-
if (index >= INLINE_PRIVACY_PREVIEW_MAX_ITEMS)
|
|
2697
|
-
break;
|
|
2698
|
-
items.push(buildOversizedInlinePreview(item, depth + 1, seen, false));
|
|
2699
|
-
index += 1;
|
|
2700
|
-
}
|
|
2701
|
-
if (value.size > INLINE_PRIVACY_PREVIEW_MAX_ITEMS) {
|
|
2702
|
-
items.push({ __truncatedItems: value.size - INLINE_PRIVACY_PREVIEW_MAX_ITEMS });
|
|
2703
|
-
}
|
|
2704
|
-
return {
|
|
2705
|
-
__type: 'Set',
|
|
2706
|
-
size: value.size,
|
|
2707
|
-
items,
|
|
2708
|
-
};
|
|
2602
|
+
try {
|
|
2603
|
+
const valueAfterPrivacy = applyPrivacyThenMask(target, value, cfg, req, trace, masking, privacy, db);
|
|
2604
|
+
return { value: valueAfterPrivacy };
|
|
2709
2605
|
}
|
|
2710
|
-
|
|
2711
|
-
const ctor = getCtorName(value);
|
|
2712
|
-
if (depth >= INLINE_PRIVACY_PREVIEW_MAX_DEPTH) {
|
|
2606
|
+
catch {
|
|
2713
2607
|
return {
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2608
|
+
value: undefined,
|
|
2609
|
+
skipped: {
|
|
2610
|
+
status: 'skipped',
|
|
2611
|
+
reason: 'inline_privacy_failed',
|
|
2612
|
+
target,
|
|
2613
|
+
},
|
|
2719
2614
|
};
|
|
2720
2615
|
}
|
|
2721
|
-
const out = ctor && ctor !== 'Object' ? { __type: ctor } : {};
|
|
2722
|
-
for (const key of keys.slice(0, INLINE_PRIVACY_PREVIEW_MAX_KEYS)) {
|
|
2723
|
-
try {
|
|
2724
|
-
out[key] = buildOversizedInlinePreview(value[key], depth + 1, seen, false);
|
|
2725
|
-
}
|
|
2726
|
-
catch (err) {
|
|
2727
|
-
out[key] = { __type: 'uninspectable', message: err?.message || 'unknown error' };
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
if (keys.length > INLINE_PRIVACY_PREVIEW_MAX_KEYS) {
|
|
2731
|
-
out.__truncatedKeys = keys.length - INLINE_PRIVACY_PREVIEW_MAX_KEYS;
|
|
2732
|
-
}
|
|
2733
|
-
return out;
|
|
2734
2616
|
}
|
|
2735
2617
|
async function materializeInlinePrivacyValueAsync(target, value, cfg, req, trace, masking, privacy, db) {
|
|
2736
2618
|
if (value === undefined || shouldCapturePrivacyRaw(cfg)) {
|
|
2737
2619
|
return { value };
|
|
2738
2620
|
}
|
|
2739
|
-
if (shouldBoundInlinePrivacyTarget(target)) {
|
|
2740
|
-
const serialized = stableSerializeTraceValue(value);
|
|
2741
|
-
const serializedLength = serialized?.length ?? 0;
|
|
2742
|
-
if (serializedLength > INLINE_PRIVACY_MAX_SERIALIZED_CHARS) {
|
|
2743
|
-
let preview = buildOversizedInlinePreview(value);
|
|
2744
|
-
try {
|
|
2745
|
-
preview = await applyPrivacyThenMaskAsync(target, preview, cfg, req, trace, masking, privacy, db);
|
|
2746
|
-
}
|
|
2747
|
-
catch { }
|
|
2748
|
-
return {
|
|
2749
|
-
value: preview,
|
|
2750
|
-
skipped: {
|
|
2751
|
-
status: 'skipped',
|
|
2752
|
-
reason: 'inline_value_too_large',
|
|
2753
|
-
target,
|
|
2754
|
-
serializedLength,
|
|
2755
|
-
limit: INLINE_PRIVACY_MAX_SERIALIZED_CHARS,
|
|
2756
|
-
preview: 'bounded',
|
|
2757
|
-
},
|
|
2758
|
-
};
|
|
2759
|
-
}
|
|
2760
|
-
}
|
|
2761
2621
|
try {
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
};
|
|
2622
|
+
const valueAfterPrivacy = await applyPrivacyThenMaskAsync(target, value, cfg, req, trace, masking, privacy, db);
|
|
2623
|
+
return { value: valueAfterPrivacy };
|
|
2765
2624
|
}
|
|
2766
2625
|
catch {
|
|
2767
2626
|
return {
|
|
@@ -2774,6 +2633,18 @@ async function materializeInlinePrivacyValueAsync(target, value, cfg, req, trace
|
|
|
2774
2633
|
};
|
|
2775
2634
|
}
|
|
2776
2635
|
}
|
|
2636
|
+
function materializeTracePrivacyValue(target, value, cfg, req, trace, masking, privacy) {
|
|
2637
|
+
if (value === undefined || shouldCapturePrivacyRaw(cfg)) {
|
|
2638
|
+
return value;
|
|
2639
|
+
}
|
|
2640
|
+
return applyPrivacyThenMask(target, value, cfg, req, trace, masking, privacy);
|
|
2641
|
+
}
|
|
2642
|
+
async function materializeTracePrivacyValueAsync(target, value, cfg, req, trace, masking, privacy) {
|
|
2643
|
+
if (value === undefined || shouldCapturePrivacyRaw(cfg)) {
|
|
2644
|
+
return value;
|
|
2645
|
+
}
|
|
2646
|
+
return applyPrivacyThenMaskAsync(target, value, cfg, req, trace, masking, privacy);
|
|
2647
|
+
}
|
|
2777
2648
|
function maskWhenRequiresTrace(when) {
|
|
2778
2649
|
return Boolean(when.fn ||
|
|
2779
2650
|
when.functionName ||
|
|
@@ -3035,6 +2906,130 @@ function stableSerializeTraceValue(value) {
|
|
|
3035
2906
|
return null;
|
|
3036
2907
|
}
|
|
3037
2908
|
}
|
|
2909
|
+
function boundedSerializedTraceValueLength(value, limit) {
|
|
2910
|
+
let length = 0;
|
|
2911
|
+
const seen = new WeakSet();
|
|
2912
|
+
const add = (amount) => {
|
|
2913
|
+
length += amount;
|
|
2914
|
+
if (length > limit) {
|
|
2915
|
+
throw TRACE_VALUE_SIZE_EXCEEDED;
|
|
2916
|
+
}
|
|
2917
|
+
};
|
|
2918
|
+
const addString = (input) => {
|
|
2919
|
+
if (length + input.length + 2 > limit) {
|
|
2920
|
+
throw TRACE_VALUE_SIZE_EXCEEDED;
|
|
2921
|
+
}
|
|
2922
|
+
add(JSON.stringify(input).length);
|
|
2923
|
+
};
|
|
2924
|
+
const walk = (input) => {
|
|
2925
|
+
if (input === undefined) {
|
|
2926
|
+
addString('__undefined__');
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
if (input === null) {
|
|
2930
|
+
add(4);
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
const inputType = typeof input;
|
|
2934
|
+
if (inputType === 'string') {
|
|
2935
|
+
addString(input);
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
if (inputType === 'number' || inputType === 'boolean') {
|
|
2939
|
+
add(JSON.stringify(input)?.length ?? String(input).length);
|
|
2940
|
+
return;
|
|
2941
|
+
}
|
|
2942
|
+
if (inputType === 'bigint') {
|
|
2943
|
+
addString(`${input.toString()}n`);
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
if (inputType === 'symbol') {
|
|
2947
|
+
addString(input.toString());
|
|
2948
|
+
return;
|
|
2949
|
+
}
|
|
2950
|
+
if (inputType === 'function') {
|
|
2951
|
+
addString('[Function]');
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2954
|
+
if (Array.isArray(input)) {
|
|
2955
|
+
add(1);
|
|
2956
|
+
input.forEach((item, index) => {
|
|
2957
|
+
if (index > 0)
|
|
2958
|
+
add(1);
|
|
2959
|
+
walk(item);
|
|
2960
|
+
});
|
|
2961
|
+
add(1);
|
|
2962
|
+
return;
|
|
2963
|
+
}
|
|
2964
|
+
if (input instanceof Map) {
|
|
2965
|
+
add(1);
|
|
2966
|
+
let index = 0;
|
|
2967
|
+
for (const [key, item] of input.entries()) {
|
|
2968
|
+
if (index > 0)
|
|
2969
|
+
add(1);
|
|
2970
|
+
addString(normalizeCollectionKeyForCapture(key, index));
|
|
2971
|
+
add(1);
|
|
2972
|
+
walk(item);
|
|
2973
|
+
index += 1;
|
|
2974
|
+
}
|
|
2975
|
+
add(1);
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
if (input instanceof Set) {
|
|
2979
|
+
add(1);
|
|
2980
|
+
let index = 0;
|
|
2981
|
+
for (const item of input.values()) {
|
|
2982
|
+
if (index > 0)
|
|
2983
|
+
add(1);
|
|
2984
|
+
walk(item);
|
|
2985
|
+
index += 1;
|
|
2986
|
+
}
|
|
2987
|
+
add(1);
|
|
2988
|
+
return;
|
|
2989
|
+
}
|
|
2990
|
+
if (input instanceof WeakMap || input instanceof WeakSet) {
|
|
2991
|
+
addString(`[${getCtorName(input) || 'WeakCollection'}: uninspectable]`);
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2994
|
+
if (input && typeof input === 'object') {
|
|
2995
|
+
if (seen.has(input)) {
|
|
2996
|
+
addString('[Circular]');
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2999
|
+
seen.add(input);
|
|
3000
|
+
add(1);
|
|
3001
|
+
let index = 0;
|
|
3002
|
+
for (const key of Object.keys(input).sort()) {
|
|
3003
|
+
if (index > 0)
|
|
3004
|
+
add(1);
|
|
3005
|
+
addString(key);
|
|
3006
|
+
add(1);
|
|
3007
|
+
try {
|
|
3008
|
+
walk(input[key]);
|
|
3009
|
+
}
|
|
3010
|
+
catch (err) {
|
|
3011
|
+
if (err === TRACE_VALUE_SIZE_EXCEEDED)
|
|
3012
|
+
throw err;
|
|
3013
|
+
addString(`[Cannot serialize: ${err?.message || 'unknown error'}]`);
|
|
3014
|
+
}
|
|
3015
|
+
index += 1;
|
|
3016
|
+
}
|
|
3017
|
+
add(1);
|
|
3018
|
+
return;
|
|
3019
|
+
}
|
|
3020
|
+
addString(String(input));
|
|
3021
|
+
};
|
|
3022
|
+
try {
|
|
3023
|
+
walk(value);
|
|
3024
|
+
return { exceeded: false, length };
|
|
3025
|
+
}
|
|
3026
|
+
catch (err) {
|
|
3027
|
+
if (err === TRACE_VALUE_SIZE_EXCEEDED) {
|
|
3028
|
+
return { exceeded: true, length };
|
|
3029
|
+
}
|
|
3030
|
+
return { exceeded: true, length: limit + 1 };
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3038
3033
|
function normalizeCollectionKeyForCapture(value, index) {
|
|
3039
3034
|
const mongoId = coerceMongoId(value);
|
|
3040
3035
|
if (mongoId !== null)
|
|
@@ -3496,12 +3491,6 @@ function createCapturedValueEntry(params) {
|
|
|
3496
3491
|
maxItems: TRACE_FULL_VALUE_MAX_ITEMS,
|
|
3497
3492
|
maxString: TRACE_FULL_VALUE_MAX_STRING,
|
|
3498
3493
|
};
|
|
3499
|
-
const fallbackLimits = {
|
|
3500
|
-
maxDepth: TRACE_FULL_VALUE_FALLBACK_DEPTH,
|
|
3501
|
-
maxKeys: TRACE_FULL_VALUE_FALLBACK_KEYS,
|
|
3502
|
-
maxItems: TRACE_FULL_VALUE_FALLBACK_ITEMS,
|
|
3503
|
-
maxString: TRACE_FULL_VALUE_FALLBACK_STRING,
|
|
3504
|
-
};
|
|
3505
3494
|
const buildMaskedCandidate = (limits) => {
|
|
3506
3495
|
const projected = params.target === 'request.headers'
|
|
3507
3496
|
? sanitizeHeaders(params.rawValue, params.capture.captureHeaders)
|
|
@@ -3519,14 +3508,6 @@ function createCapturedValueEntry(params) {
|
|
|
3519
3508
|
if (!candidateSerialized || candidateSerialized === previewSerialized) {
|
|
3520
3509
|
return undefined;
|
|
3521
3510
|
}
|
|
3522
|
-
let truncatedForStorage = false;
|
|
3523
|
-
if (candidateSerialized.length > TRACE_FULL_VALUE_MAX_SERIALIZED_CHARS) {
|
|
3524
|
-
const fallback = buildMaskedCandidate(fallbackLimits);
|
|
3525
|
-
if (fallback !== undefined && hasMeaningfulFullValue(fallback)) {
|
|
3526
|
-
candidate = fallback;
|
|
3527
|
-
truncatedForStorage = true;
|
|
3528
|
-
}
|
|
3529
|
-
}
|
|
3530
3511
|
const valueId = (0, crypto_1.randomUUID)();
|
|
3531
3512
|
const projectedKind = candidate && typeof candidate === 'object'
|
|
3532
3513
|
? (candidate.__kind || candidate.__type)
|
|
@@ -3535,13 +3516,13 @@ function createCapturedValueEntry(params) {
|
|
|
3535
3516
|
id: valueId,
|
|
3536
3517
|
target: params.target,
|
|
3537
3518
|
value: candidate,
|
|
3538
|
-
truncatedForStorage,
|
|
3519
|
+
truncatedForStorage: false,
|
|
3539
3520
|
projectedKind: typeof projectedKind === 'string' ? projectedKind : undefined,
|
|
3540
3521
|
...(params.metadata ?? {}),
|
|
3541
3522
|
};
|
|
3542
3523
|
return {
|
|
3543
3524
|
captureRef: {
|
|
3544
|
-
status:
|
|
3525
|
+
status: 'stored',
|
|
3545
3526
|
valueId,
|
|
3546
3527
|
projectedKind: entry.projectedKind,
|
|
3547
3528
|
},
|
|
@@ -3557,12 +3538,6 @@ async function createCapturedValueEntryAsync(params) {
|
|
|
3557
3538
|
maxItems: TRACE_FULL_VALUE_MAX_ITEMS,
|
|
3558
3539
|
maxString: TRACE_FULL_VALUE_MAX_STRING,
|
|
3559
3540
|
};
|
|
3560
|
-
const fallbackLimits = {
|
|
3561
|
-
maxDepth: TRACE_FULL_VALUE_FALLBACK_DEPTH,
|
|
3562
|
-
maxKeys: TRACE_FULL_VALUE_FALLBACK_KEYS,
|
|
3563
|
-
maxItems: TRACE_FULL_VALUE_FALLBACK_ITEMS,
|
|
3564
|
-
maxString: TRACE_FULL_VALUE_FALLBACK_STRING,
|
|
3565
|
-
};
|
|
3566
3541
|
const buildMaskedCandidate = async (limits) => {
|
|
3567
3542
|
const projected = params.target === 'request.headers'
|
|
3568
3543
|
? sanitizeHeaders(params.rawValue, params.capture.captureHeaders)
|
|
@@ -3580,14 +3555,6 @@ async function createCapturedValueEntryAsync(params) {
|
|
|
3580
3555
|
if (!candidateSerialized || candidateSerialized === previewSerialized) {
|
|
3581
3556
|
return undefined;
|
|
3582
3557
|
}
|
|
3583
|
-
let truncatedForStorage = false;
|
|
3584
|
-
if (candidateSerialized.length > TRACE_FULL_VALUE_MAX_SERIALIZED_CHARS) {
|
|
3585
|
-
const fallback = await buildMaskedCandidate(fallbackLimits);
|
|
3586
|
-
if (fallback !== undefined && hasMeaningfulFullValue(fallback)) {
|
|
3587
|
-
candidate = fallback;
|
|
3588
|
-
truncatedForStorage = true;
|
|
3589
|
-
}
|
|
3590
|
-
}
|
|
3591
3558
|
const valueId = (0, crypto_1.randomUUID)();
|
|
3592
3559
|
const projectedKind = candidate && typeof candidate === 'object'
|
|
3593
3560
|
? (candidate.__kind || candidate.__type)
|
|
@@ -3596,83 +3563,19 @@ async function createCapturedValueEntryAsync(params) {
|
|
|
3596
3563
|
id: valueId,
|
|
3597
3564
|
target: params.target,
|
|
3598
3565
|
value: candidate,
|
|
3599
|
-
truncatedForStorage,
|
|
3566
|
+
truncatedForStorage: false,
|
|
3600
3567
|
projectedKind: typeof projectedKind === 'string' ? projectedKind : undefined,
|
|
3601
3568
|
...(params.metadata ?? {}),
|
|
3602
3569
|
};
|
|
3603
3570
|
return {
|
|
3604
3571
|
captureRef: {
|
|
3605
|
-
status:
|
|
3572
|
+
status: 'stored',
|
|
3606
3573
|
valueId,
|
|
3607
3574
|
projectedKind: entry.projectedKind,
|
|
3608
3575
|
},
|
|
3609
3576
|
entry,
|
|
3610
3577
|
};
|
|
3611
3578
|
}
|
|
3612
|
-
function maybeCaptureFullTraceValue(params) {
|
|
3613
|
-
const result = createCapturedValueEntry({
|
|
3614
|
-
target: params.target,
|
|
3615
|
-
rawValue: params.rawValue,
|
|
3616
|
-
previewValue: params.previewValue,
|
|
3617
|
-
capture: params.capture,
|
|
3618
|
-
metadata: {
|
|
3619
|
-
fn: params.event.fn,
|
|
3620
|
-
file: params.event.file,
|
|
3621
|
-
line: params.event.line ?? null,
|
|
3622
|
-
spanId: params.event.spanId ?? null,
|
|
3623
|
-
parentSpanId: params.event.parentSpanId ?? null,
|
|
3624
|
-
},
|
|
3625
|
-
});
|
|
3626
|
-
if (!result)
|
|
3627
|
-
return undefined;
|
|
3628
|
-
if (result.entry) {
|
|
3629
|
-
const existing = params.event[TRACE_FULL_VALUE_ENTRY_SYMBOL];
|
|
3630
|
-
if (Array.isArray(existing)) {
|
|
3631
|
-
existing.push(result.entry);
|
|
3632
|
-
}
|
|
3633
|
-
else {
|
|
3634
|
-
Object.defineProperty(params.event, TRACE_FULL_VALUE_ENTRY_SYMBOL, {
|
|
3635
|
-
value: [result.entry],
|
|
3636
|
-
enumerable: false,
|
|
3637
|
-
configurable: true,
|
|
3638
|
-
writable: true,
|
|
3639
|
-
});
|
|
3640
|
-
}
|
|
3641
|
-
}
|
|
3642
|
-
return result.captureRef;
|
|
3643
|
-
}
|
|
3644
|
-
async function maybeCaptureFullTraceValueAsync(params) {
|
|
3645
|
-
const result = await createCapturedValueEntryAsync({
|
|
3646
|
-
target: params.target,
|
|
3647
|
-
rawValue: params.rawValue,
|
|
3648
|
-
previewValue: params.previewValue,
|
|
3649
|
-
capture: params.capture,
|
|
3650
|
-
metadata: {
|
|
3651
|
-
fn: params.event.fn,
|
|
3652
|
-
file: params.event.file,
|
|
3653
|
-
line: params.event.line ?? null,
|
|
3654
|
-
spanId: params.event.spanId ?? null,
|
|
3655
|
-
parentSpanId: params.event.parentSpanId ?? null,
|
|
3656
|
-
},
|
|
3657
|
-
});
|
|
3658
|
-
if (!result)
|
|
3659
|
-
return undefined;
|
|
3660
|
-
if (result.entry) {
|
|
3661
|
-
const existing = params.event[TRACE_FULL_VALUE_ENTRY_SYMBOL];
|
|
3662
|
-
if (Array.isArray(existing)) {
|
|
3663
|
-
existing.push(result.entry);
|
|
3664
|
-
}
|
|
3665
|
-
else {
|
|
3666
|
-
Object.defineProperty(params.event, TRACE_FULL_VALUE_ENTRY_SYMBOL, {
|
|
3667
|
-
value: [result.entry],
|
|
3668
|
-
enumerable: false,
|
|
3669
|
-
configurable: true,
|
|
3670
|
-
writable: true,
|
|
3671
|
-
});
|
|
3672
|
-
}
|
|
3673
|
-
}
|
|
3674
|
-
return result.captureRef;
|
|
3675
|
-
}
|
|
3676
3579
|
function maybeCaptureRequestValue(params, sink) {
|
|
3677
3580
|
const result = createCapturedValueEntry(params);
|
|
3678
3581
|
if (!result)
|
|
@@ -3792,6 +3695,7 @@ function reproMiddleware(cfg) {
|
|
|
3792
3695
|
let idleTimer = null;
|
|
3793
3696
|
let hardStopTimer = null;
|
|
3794
3697
|
let flushPayload = null;
|
|
3698
|
+
let requestCaptureScheduled = false;
|
|
3795
3699
|
let sessionDrainWait = null;
|
|
3796
3700
|
const activeSpans = new Set();
|
|
3797
3701
|
let anonymousSpanDepth = 0;
|
|
@@ -3881,6 +3785,179 @@ function reproMiddleware(cfg) {
|
|
|
3881
3785
|
}
|
|
3882
3786
|
scheduleIdleFlush();
|
|
3883
3787
|
};
|
|
3788
|
+
const chooseRequestEndpoint = () => {
|
|
3789
|
+
const pendingEvents = preparePendingTraceEventsForFlush(events.slice());
|
|
3790
|
+
const baseEvents = balanceTraceEvents(pendingEvents.slice());
|
|
3791
|
+
const orderedEvents = TRACE_ORDER_MODE === 'tree'
|
|
3792
|
+
? reorderTraceEvents(baseEvents)
|
|
3793
|
+
: sortTraceEventsChronologically(baseEvents);
|
|
3794
|
+
const summary = summarizeEndpointFromEvents(orderedEvents);
|
|
3795
|
+
return {
|
|
3796
|
+
chosenEndpoint: summary.endpointTrace
|
|
3797
|
+
?? summary.preferredAppTrace
|
|
3798
|
+
?? summary.firstAppTrace
|
|
3799
|
+
?? endpointTrace
|
|
3800
|
+
?? preferredAppTrace
|
|
3801
|
+
?? firstAppTrace
|
|
3802
|
+
?? { fn: null, file: null, line: null, functionType: null },
|
|
3803
|
+
hasTraceEvents: orderedEvents.length > 0,
|
|
3804
|
+
};
|
|
3805
|
+
};
|
|
3806
|
+
const buildRequestCapturePayloadAsync = async (chosenEndpoint, hasTraceEvents) => {
|
|
3807
|
+
const endpointTraceCtx = (() => {
|
|
3808
|
+
if (!chosenEndpoint?.fn && !chosenEndpoint?.file)
|
|
3809
|
+
return null;
|
|
3810
|
+
return {
|
|
3811
|
+
type: 'enter',
|
|
3812
|
+
eventType: 'enter',
|
|
3813
|
+
fn: chosenEndpoint.fn ?? undefined,
|
|
3814
|
+
wrapperClass: inferWrapperClassFromFn(chosenEndpoint.fn),
|
|
3815
|
+
file: chosenEndpoint.file ?? null,
|
|
3816
|
+
line: chosenEndpoint.line ?? null,
|
|
3817
|
+
functionType: chosenEndpoint.functionType ?? null,
|
|
3818
|
+
library: inferLibraryNameFromFile(chosenEndpoint.file),
|
|
3819
|
+
};
|
|
3820
|
+
})();
|
|
3821
|
+
const activePrivacy = resolvePrivacy();
|
|
3822
|
+
const requestBodyRaw = req.body;
|
|
3823
|
+
const requestBodyMaterialization = limitRawInlinePrivacyValue('request.body', requestBodyRaw)
|
|
3824
|
+
?? await materializeInlinePrivacyValueAsync('request.body', sanitizeRequestSnapshot(requestBodyRaw), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
3825
|
+
const requestBody = requestBodyMaterialization.value;
|
|
3826
|
+
const requestParams = await applyPrivacyThenMaskAsync('request.params', sanitizeRequestSnapshot(req.params), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
3827
|
+
const requestQuery = await applyPrivacyThenMaskAsync('request.query', sanitizeRequestSnapshot(req.query), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
3828
|
+
const maskedHeaders = await applyPrivacyThenMaskAsync('request.headers', requestHeaders, cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
3829
|
+
const responseBodyMaterialization = capturedBody === undefined
|
|
3830
|
+
? { value: undefined }
|
|
3831
|
+
: limitRawInlinePrivacyValue('response.body', capturedBody)
|
|
3832
|
+
?? await materializeInlinePrivacyValueAsync('response.body', sanitizeRequestSnapshot(capturedBody), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
3833
|
+
const responseBody = responseBodyMaterialization.value;
|
|
3834
|
+
const requestValueEntries = [];
|
|
3835
|
+
const bodyValueCapture = requestBodyMaterialization.skipped
|
|
3836
|
+
? undefined
|
|
3837
|
+
: await maybeCaptureRequestValueAsync({
|
|
3838
|
+
target: 'request.body',
|
|
3839
|
+
rawValue: req.body,
|
|
3840
|
+
previewValue: requestBody,
|
|
3841
|
+
capture: {
|
|
3842
|
+
runtimeConfig: cfg,
|
|
3843
|
+
captureHeaders: cfg.captureHeaders,
|
|
3844
|
+
maskReq,
|
|
3845
|
+
trace: endpointTraceCtx,
|
|
3846
|
+
masking,
|
|
3847
|
+
privacy: activePrivacy,
|
|
3848
|
+
},
|
|
3849
|
+
}, requestValueEntries);
|
|
3850
|
+
const paramsValueCapture = await maybeCaptureRequestValueAsync({
|
|
3851
|
+
target: 'request.params',
|
|
3852
|
+
rawValue: req.params,
|
|
3853
|
+
previewValue: requestParams,
|
|
3854
|
+
capture: {
|
|
3855
|
+
runtimeConfig: cfg,
|
|
3856
|
+
captureHeaders: cfg.captureHeaders,
|
|
3857
|
+
maskReq,
|
|
3858
|
+
trace: endpointTraceCtx,
|
|
3859
|
+
masking,
|
|
3860
|
+
privacy: activePrivacy,
|
|
3861
|
+
},
|
|
3862
|
+
}, requestValueEntries);
|
|
3863
|
+
const queryValueCapture = await maybeCaptureRequestValueAsync({
|
|
3864
|
+
target: 'request.query',
|
|
3865
|
+
rawValue: req.query,
|
|
3866
|
+
previewValue: requestQuery,
|
|
3867
|
+
capture: {
|
|
3868
|
+
runtimeConfig: cfg,
|
|
3869
|
+
captureHeaders: cfg.captureHeaders,
|
|
3870
|
+
maskReq,
|
|
3871
|
+
trace: endpointTraceCtx,
|
|
3872
|
+
masking,
|
|
3873
|
+
privacy: activePrivacy,
|
|
3874
|
+
},
|
|
3875
|
+
}, requestValueEntries);
|
|
3876
|
+
const headersValueCapture = await maybeCaptureRequestValueAsync({
|
|
3877
|
+
target: 'request.headers',
|
|
3878
|
+
rawValue: req.headers,
|
|
3879
|
+
previewValue: maskedHeaders,
|
|
3880
|
+
capture: {
|
|
3881
|
+
runtimeConfig: cfg,
|
|
3882
|
+
captureHeaders: cfg.captureHeaders,
|
|
3883
|
+
maskReq,
|
|
3884
|
+
trace: endpointTraceCtx,
|
|
3885
|
+
masking,
|
|
3886
|
+
privacy: activePrivacy,
|
|
3887
|
+
},
|
|
3888
|
+
}, requestValueEntries);
|
|
3889
|
+
const respBodyValueCapture = responseBodyMaterialization.skipped
|
|
3890
|
+
? undefined
|
|
3891
|
+
: await maybeCaptureRequestValueAsync({
|
|
3892
|
+
target: 'response.body',
|
|
3893
|
+
rawValue: capturedBody,
|
|
3894
|
+
previewValue: responseBody,
|
|
3895
|
+
capture: {
|
|
3896
|
+
runtimeConfig: cfg,
|
|
3897
|
+
captureHeaders: cfg.captureHeaders,
|
|
3898
|
+
maskReq,
|
|
3899
|
+
trace: endpointTraceCtx,
|
|
3900
|
+
masking,
|
|
3901
|
+
privacy: activePrivacy,
|
|
3902
|
+
},
|
|
3903
|
+
}, requestValueEntries);
|
|
3904
|
+
const requestPayload = {
|
|
3905
|
+
rid,
|
|
3906
|
+
method: req.method,
|
|
3907
|
+
url,
|
|
3908
|
+
path,
|
|
3909
|
+
status: res.statusCode,
|
|
3910
|
+
durMs: Date.now() - t0,
|
|
3911
|
+
headers: maskedHeaders,
|
|
3912
|
+
key,
|
|
3913
|
+
respBody: responseBody,
|
|
3914
|
+
trace: hasTraceEvents ? undefined : [],
|
|
3915
|
+
};
|
|
3916
|
+
if (requestBody !== undefined)
|
|
3917
|
+
requestPayload.body = requestBody;
|
|
3918
|
+
if (bodyValueCapture)
|
|
3919
|
+
requestPayload.bodyValueCapture = bodyValueCapture;
|
|
3920
|
+
if (requestParams !== undefined)
|
|
3921
|
+
requestPayload.params = requestParams;
|
|
3922
|
+
if (paramsValueCapture)
|
|
3923
|
+
requestPayload.paramsValueCapture = paramsValueCapture;
|
|
3924
|
+
if (requestQuery !== undefined)
|
|
3925
|
+
requestPayload.query = requestQuery;
|
|
3926
|
+
if (queryValueCapture)
|
|
3927
|
+
requestPayload.queryValueCapture = queryValueCapture;
|
|
3928
|
+
if (headersValueCapture)
|
|
3929
|
+
requestPayload.headersValueCapture = headersValueCapture;
|
|
3930
|
+
if (respBodyValueCapture)
|
|
3931
|
+
requestPayload.respBodyValueCapture = respBodyValueCapture;
|
|
3932
|
+
if (requestBodyMaterialization.skipped) {
|
|
3933
|
+
requestPayload.bodyMaterialization = requestBodyMaterialization.skipped;
|
|
3934
|
+
}
|
|
3935
|
+
if (responseBodyMaterialization.skipped) {
|
|
3936
|
+
requestPayload.respBodyMaterialization = responseBodyMaterialization.skipped;
|
|
3937
|
+
}
|
|
3938
|
+
requestPayload.entryPoint = chosenEndpoint;
|
|
3939
|
+
return { requestPayload, requestValueEntries };
|
|
3940
|
+
};
|
|
3941
|
+
const emitRequestCaptureAsync = async () => {
|
|
3942
|
+
if (requestCaptureScheduled)
|
|
3943
|
+
return;
|
|
3944
|
+
requestCaptureScheduled = true;
|
|
3945
|
+
try {
|
|
3946
|
+
const { chosenEndpoint, hasTraceEvents } = chooseRequestEndpoint();
|
|
3947
|
+
const { requestPayload, requestValueEntries } = await buildRequestCapturePayloadAsync(chosenEndpoint, hasTraceEvents);
|
|
3948
|
+
post(cfg, sid, {
|
|
3949
|
+
entries: [{
|
|
3950
|
+
actionId: aid,
|
|
3951
|
+
request: requestPayload,
|
|
3952
|
+
requestValues: requestValueEntries.length ? requestValueEntries : undefined,
|
|
3953
|
+
t: requestEpochMs,
|
|
3954
|
+
}]
|
|
3955
|
+
});
|
|
3956
|
+
}
|
|
3957
|
+
catch {
|
|
3958
|
+
// never break user code
|
|
3959
|
+
}
|
|
3960
|
+
};
|
|
3884
3961
|
try {
|
|
3885
3962
|
if (__TRACER__?.tracer?.on) {
|
|
3886
3963
|
const getTid = __TRACER__?.getCurrentTraceId;
|
|
@@ -3933,7 +4010,8 @@ function reproMiddleware(cfg) {
|
|
|
3933
4010
|
if (finished) {
|
|
3934
4011
|
scheduleIdleFlush();
|
|
3935
4012
|
}
|
|
3936
|
-
|
|
4013
|
+
const hasErrorPayload = hasMeaningfulRawTraceError(ev.error);
|
|
4014
|
+
if (ev.args !== undefined || ev.returnValue !== undefined || hasErrorPayload) {
|
|
3937
4015
|
evt.__reproPending = {
|
|
3938
4016
|
...(ev.args !== undefined
|
|
3939
4017
|
? {
|
|
@@ -3945,7 +4023,7 @@ function reproMiddleware(cfg) {
|
|
|
3945
4023
|
returnValueRaw: ev.returnValue,
|
|
3946
4024
|
}
|
|
3947
4025
|
: {}),
|
|
3948
|
-
...(
|
|
4026
|
+
...(hasErrorPayload
|
|
3949
4027
|
? {
|
|
3950
4028
|
errorRaw: ev.error,
|
|
3951
4029
|
}
|
|
@@ -3972,6 +4050,7 @@ function reproMiddleware(cfg) {
|
|
|
3972
4050
|
: Buffer.from(chunks.map(String).join(''));
|
|
3973
4051
|
capturedBody = coerceBodyToStorable(buf, res.getHeader?.('content-type'));
|
|
3974
4052
|
}
|
|
4053
|
+
void emitRequestCaptureAsync();
|
|
3975
4054
|
if (!flushPayload) {
|
|
3976
4055
|
flushPayload = async () => {
|
|
3977
4056
|
try {
|
|
@@ -3986,150 +4065,7 @@ function reproMiddleware(cfg) {
|
|
|
3986
4065
|
const orderedEvents = TRACE_ORDER_MODE === 'tree'
|
|
3987
4066
|
? reorderTraceEvents(baseEvents)
|
|
3988
4067
|
: sortTraceEventsChronologically(baseEvents);
|
|
3989
|
-
const summary = summarizeEndpointFromEvents(orderedEvents);
|
|
3990
|
-
const chosenEndpoint = summary.endpointTrace
|
|
3991
|
-
?? summary.preferredAppTrace
|
|
3992
|
-
?? summary.firstAppTrace
|
|
3993
|
-
?? endpointTrace
|
|
3994
|
-
?? preferredAppTrace
|
|
3995
|
-
?? firstAppTrace
|
|
3996
|
-
?? { fn: null, file: null, line: null, functionType: null };
|
|
3997
4068
|
const traceBatches = chunkArray(orderedEvents, TRACE_BATCH_SIZE);
|
|
3998
|
-
const endpointTraceCtx = (() => {
|
|
3999
|
-
if (!chosenEndpoint?.fn && !chosenEndpoint?.file)
|
|
4000
|
-
return null;
|
|
4001
|
-
return {
|
|
4002
|
-
type: 'enter',
|
|
4003
|
-
eventType: 'enter',
|
|
4004
|
-
fn: chosenEndpoint.fn ?? undefined,
|
|
4005
|
-
wrapperClass: inferWrapperClassFromFn(chosenEndpoint.fn),
|
|
4006
|
-
file: chosenEndpoint.file ?? null,
|
|
4007
|
-
line: chosenEndpoint.line ?? null,
|
|
4008
|
-
functionType: chosenEndpoint.functionType ?? null,
|
|
4009
|
-
library: inferLibraryNameFromFile(chosenEndpoint.file),
|
|
4010
|
-
};
|
|
4011
|
-
})();
|
|
4012
|
-
const activePrivacy = resolvePrivacy();
|
|
4013
|
-
const requestBodyMaterialization = await materializeInlinePrivacyValueAsync('request.body', sanitizeRequestSnapshot(req.body), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4014
|
-
const requestBody = requestBodyMaterialization.value;
|
|
4015
|
-
const requestParams = await applyPrivacyThenMaskAsync('request.params', sanitizeRequestSnapshot(req.params), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4016
|
-
const requestQuery = await applyPrivacyThenMaskAsync('request.query', sanitizeRequestSnapshot(req.query), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4017
|
-
const maskedHeaders = await applyPrivacyThenMaskAsync('request.headers', requestHeaders, cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4018
|
-
const responseBodyMaterialization = await materializeInlinePrivacyValueAsync('response.body', capturedBody === undefined ? undefined : sanitizeRequestSnapshot(capturedBody), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4019
|
-
const responseBody = responseBodyMaterialization.value;
|
|
4020
|
-
const requestValueEntries = [];
|
|
4021
|
-
const bodyValueCapture = requestBodyMaterialization.skipped
|
|
4022
|
-
? undefined
|
|
4023
|
-
: await maybeCaptureRequestValueAsync({
|
|
4024
|
-
target: 'request.body',
|
|
4025
|
-
rawValue: req.body,
|
|
4026
|
-
previewValue: requestBody,
|
|
4027
|
-
capture: {
|
|
4028
|
-
runtimeConfig: cfg,
|
|
4029
|
-
captureHeaders: cfg.captureHeaders,
|
|
4030
|
-
maskReq,
|
|
4031
|
-
trace: endpointTraceCtx,
|
|
4032
|
-
masking,
|
|
4033
|
-
privacy: activePrivacy,
|
|
4034
|
-
},
|
|
4035
|
-
}, requestValueEntries);
|
|
4036
|
-
const paramsValueCapture = await maybeCaptureRequestValueAsync({
|
|
4037
|
-
target: 'request.params',
|
|
4038
|
-
rawValue: req.params,
|
|
4039
|
-
previewValue: requestParams,
|
|
4040
|
-
capture: {
|
|
4041
|
-
runtimeConfig: cfg,
|
|
4042
|
-
captureHeaders: cfg.captureHeaders,
|
|
4043
|
-
maskReq,
|
|
4044
|
-
trace: endpointTraceCtx,
|
|
4045
|
-
masking,
|
|
4046
|
-
privacy: activePrivacy,
|
|
4047
|
-
},
|
|
4048
|
-
}, requestValueEntries);
|
|
4049
|
-
const queryValueCapture = await maybeCaptureRequestValueAsync({
|
|
4050
|
-
target: 'request.query',
|
|
4051
|
-
rawValue: req.query,
|
|
4052
|
-
previewValue: requestQuery,
|
|
4053
|
-
capture: {
|
|
4054
|
-
runtimeConfig: cfg,
|
|
4055
|
-
captureHeaders: cfg.captureHeaders,
|
|
4056
|
-
maskReq,
|
|
4057
|
-
trace: endpointTraceCtx,
|
|
4058
|
-
masking,
|
|
4059
|
-
privacy: activePrivacy,
|
|
4060
|
-
},
|
|
4061
|
-
}, requestValueEntries);
|
|
4062
|
-
const headersValueCapture = await maybeCaptureRequestValueAsync({
|
|
4063
|
-
target: 'request.headers',
|
|
4064
|
-
rawValue: req.headers,
|
|
4065
|
-
previewValue: maskedHeaders,
|
|
4066
|
-
capture: {
|
|
4067
|
-
runtimeConfig: cfg,
|
|
4068
|
-
captureHeaders: cfg.captureHeaders,
|
|
4069
|
-
maskReq,
|
|
4070
|
-
trace: endpointTraceCtx,
|
|
4071
|
-
masking,
|
|
4072
|
-
privacy: activePrivacy,
|
|
4073
|
-
},
|
|
4074
|
-
}, requestValueEntries);
|
|
4075
|
-
const respBodyValueCapture = responseBodyMaterialization.skipped
|
|
4076
|
-
? undefined
|
|
4077
|
-
: await maybeCaptureRequestValueAsync({
|
|
4078
|
-
target: 'response.body',
|
|
4079
|
-
rawValue: capturedBody,
|
|
4080
|
-
previewValue: responseBody,
|
|
4081
|
-
capture: {
|
|
4082
|
-
runtimeConfig: cfg,
|
|
4083
|
-
captureHeaders: cfg.captureHeaders,
|
|
4084
|
-
maskReq,
|
|
4085
|
-
trace: endpointTraceCtx,
|
|
4086
|
-
masking,
|
|
4087
|
-
privacy: activePrivacy,
|
|
4088
|
-
},
|
|
4089
|
-
}, requestValueEntries);
|
|
4090
|
-
const requestPayload = {
|
|
4091
|
-
rid,
|
|
4092
|
-
method: req.method,
|
|
4093
|
-
url,
|
|
4094
|
-
path,
|
|
4095
|
-
status: res.statusCode,
|
|
4096
|
-
durMs: Date.now() - t0,
|
|
4097
|
-
headers: maskedHeaders,
|
|
4098
|
-
key,
|
|
4099
|
-
respBody: responseBody,
|
|
4100
|
-
trace: traceBatches.length ? undefined : [],
|
|
4101
|
-
};
|
|
4102
|
-
if (requestBody !== undefined)
|
|
4103
|
-
requestPayload.body = requestBody;
|
|
4104
|
-
if (bodyValueCapture)
|
|
4105
|
-
requestPayload.bodyValueCapture = bodyValueCapture;
|
|
4106
|
-
if (requestParams !== undefined)
|
|
4107
|
-
requestPayload.params = requestParams;
|
|
4108
|
-
if (paramsValueCapture)
|
|
4109
|
-
requestPayload.paramsValueCapture = paramsValueCapture;
|
|
4110
|
-
if (requestQuery !== undefined)
|
|
4111
|
-
requestPayload.query = requestQuery;
|
|
4112
|
-
if (queryValueCapture)
|
|
4113
|
-
requestPayload.queryValueCapture = queryValueCapture;
|
|
4114
|
-
if (headersValueCapture)
|
|
4115
|
-
requestPayload.headersValueCapture = headersValueCapture;
|
|
4116
|
-
if (respBodyValueCapture)
|
|
4117
|
-
requestPayload.respBodyValueCapture = respBodyValueCapture;
|
|
4118
|
-
if (requestBodyMaterialization.skipped) {
|
|
4119
|
-
requestPayload.bodyMaterialization = requestBodyMaterialization.skipped;
|
|
4120
|
-
}
|
|
4121
|
-
if (responseBodyMaterialization.skipped) {
|
|
4122
|
-
requestPayload.respBodyMaterialization = responseBodyMaterialization.skipped;
|
|
4123
|
-
}
|
|
4124
|
-
requestPayload.entryPoint = chosenEndpoint;
|
|
4125
|
-
post(cfg, sid, {
|
|
4126
|
-
entries: [{
|
|
4127
|
-
actionId: aid,
|
|
4128
|
-
request: requestPayload,
|
|
4129
|
-
requestValues: requestValueEntries.length ? requestValueEntries : undefined,
|
|
4130
|
-
t: requestEpochMs,
|
|
4131
|
-
}]
|
|
4132
|
-
});
|
|
4133
4069
|
if (traceBatches.length) {
|
|
4134
4070
|
for (let i = 0; i < traceBatches.length; i++) {
|
|
4135
4071
|
const batch = traceBatches[i];
|
|
@@ -4567,7 +4503,11 @@ function sanitizeResultForMeta(value, options = {}) {
|
|
|
4567
4503
|
if (typeof value === 'function')
|
|
4568
4504
|
return undefined;
|
|
4569
4505
|
try {
|
|
4570
|
-
return sanitizeTraceValue(value, 0, new WeakMap(),
|
|
4506
|
+
return sanitizeTraceValue(value, 0, new WeakMap(), {
|
|
4507
|
+
preserveLongStrings: true,
|
|
4508
|
+
disableTruncation: true,
|
|
4509
|
+
...options,
|
|
4510
|
+
});
|
|
4571
4511
|
}
|
|
4572
4512
|
catch {
|
|
4573
4513
|
const fallback = safeJson(value);
|
|
@@ -4653,7 +4593,7 @@ async function emitDbQueryAsync(cfg, sid, aid, payload) {
|
|
|
4653
4593
|
const afterPreview = afterMaterialization.value;
|
|
4654
4594
|
const resultMetaMaterialization = await materializeInlinePrivacyValueAsync('db.resultMeta', resultMetaSource ?? undefined, cfg, maskReq, null, null, privacy, dbContext);
|
|
4655
4595
|
const resultMetaPreviewRaw = resultMetaMaterialization.value;
|
|
4656
|
-
const resultMetaPreview =
|
|
4596
|
+
const resultMetaPreview = sanitizeMaterializedTraceValue(resultMetaPreviewRaw);
|
|
4657
4597
|
const errorMaterialization = await materializeInlinePrivacyValueAsync('db.error', payload.error ?? undefined, cfg, maskReq, null, null, privacy, dbContext);
|
|
4658
4598
|
const errorPreview = errorMaterialization.value;
|
|
4659
4599
|
const capture = {
|
|
@@ -5049,23 +4989,6 @@ function normalizeKafkaHeadersForPayload(headers) {
|
|
|
5049
4989
|
}
|
|
5050
4990
|
return out;
|
|
5051
4991
|
}
|
|
5052
|
-
function previewKafkaValue(value, maxLength = 120) {
|
|
5053
|
-
if (value === null || value === undefined)
|
|
5054
|
-
return null;
|
|
5055
|
-
let text;
|
|
5056
|
-
if (typeof value === 'string') {
|
|
5057
|
-
text = value;
|
|
5058
|
-
}
|
|
5059
|
-
else if (Buffer.isBuffer(value)) {
|
|
5060
|
-
text = value.toString('utf8');
|
|
5061
|
-
}
|
|
5062
|
-
else {
|
|
5063
|
-
return null;
|
|
5064
|
-
}
|
|
5065
|
-
if (text.length <= maxLength)
|
|
5066
|
-
return text;
|
|
5067
|
-
return `${text.slice(0, Math.max(0, maxLength - 3))}...`;
|
|
5068
|
-
}
|
|
5069
4992
|
function kafkaValueSize(value) {
|
|
5070
4993
|
if (value === null || value === undefined)
|
|
5071
4994
|
return null;
|
|
@@ -5073,8 +4996,93 @@ function kafkaValueSize(value) {
|
|
|
5073
4996
|
return Buffer.byteLength(value, 'utf8');
|
|
5074
4997
|
if (Buffer.isBuffer(value))
|
|
5075
4998
|
return value.length;
|
|
4999
|
+
if (value instanceof Uint8Array)
|
|
5000
|
+
return value.byteLength;
|
|
5076
5001
|
return null;
|
|
5077
5002
|
}
|
|
5003
|
+
function decodeKafkaValue(value) {
|
|
5004
|
+
if (value === null || value === undefined)
|
|
5005
|
+
return null;
|
|
5006
|
+
if (typeof value === 'string')
|
|
5007
|
+
return value;
|
|
5008
|
+
if (Buffer.isBuffer(value))
|
|
5009
|
+
return value.toString('utf8');
|
|
5010
|
+
if (value instanceof Uint8Array)
|
|
5011
|
+
return Buffer.from(value).toString('utf8');
|
|
5012
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
5013
|
+
return value;
|
|
5014
|
+
return sanitizeResultForMeta(value);
|
|
5015
|
+
}
|
|
5016
|
+
function parseKafkaJsonString(value) {
|
|
5017
|
+
const trimmed = value.trim();
|
|
5018
|
+
if (!trimmed || !'{['.includes(trimmed[0])) {
|
|
5019
|
+
return { parsed: false, value };
|
|
5020
|
+
}
|
|
5021
|
+
try {
|
|
5022
|
+
return { parsed: true, value: JSON.parse(value) };
|
|
5023
|
+
}
|
|
5024
|
+
catch {
|
|
5025
|
+
return { parsed: false, value };
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
5028
|
+
function decodeKafkaMessageValue(value) {
|
|
5029
|
+
const decoded = decodeKafkaValue(value);
|
|
5030
|
+
if (typeof decoded !== 'string') {
|
|
5031
|
+
return {
|
|
5032
|
+
value: decoded,
|
|
5033
|
+
valueEncoding: decoded === null ? null : typeof decoded,
|
|
5034
|
+
};
|
|
5035
|
+
}
|
|
5036
|
+
const parsed = parseKafkaJsonString(decoded);
|
|
5037
|
+
if (parsed.parsed) {
|
|
5038
|
+
return {
|
|
5039
|
+
value: parsed.value,
|
|
5040
|
+
rawValue: decoded,
|
|
5041
|
+
valueEncoding: 'json',
|
|
5042
|
+
};
|
|
5043
|
+
}
|
|
5044
|
+
return {
|
|
5045
|
+
value: decoded,
|
|
5046
|
+
valueEncoding: 'utf8',
|
|
5047
|
+
};
|
|
5048
|
+
}
|
|
5049
|
+
function buildKafkaMessagePayload(message) {
|
|
5050
|
+
const msgObj = message && typeof message === 'object' ? message : { value: message };
|
|
5051
|
+
const decoded = decodeKafkaMessageValue(msgObj.value);
|
|
5052
|
+
const payload = {
|
|
5053
|
+
key: decodeKafkaValue(msgObj.key),
|
|
5054
|
+
value: decoded.value,
|
|
5055
|
+
valueEncoding: decoded.valueEncoding,
|
|
5056
|
+
valueBytes: kafkaValueSize(msgObj.value),
|
|
5057
|
+
headers: normalizeKafkaHeadersForPayload(msgObj.headers),
|
|
5058
|
+
};
|
|
5059
|
+
if (decoded.rawValue !== undefined) {
|
|
5060
|
+
payload.rawValue = decoded.rawValue;
|
|
5061
|
+
}
|
|
5062
|
+
if (msgObj.partition !== undefined) {
|
|
5063
|
+
payload.partition = msgObj.partition;
|
|
5064
|
+
}
|
|
5065
|
+
if (msgObj.timestamp !== undefined) {
|
|
5066
|
+
payload.timestamp = msgObj.timestamp;
|
|
5067
|
+
}
|
|
5068
|
+
if (msgObj.offset !== undefined) {
|
|
5069
|
+
payload.offset = msgObj.offset;
|
|
5070
|
+
}
|
|
5071
|
+
return payload;
|
|
5072
|
+
}
|
|
5073
|
+
function cloneKafkaTelemetryValue(value) {
|
|
5074
|
+
if (value === undefined || value === null)
|
|
5075
|
+
return value;
|
|
5076
|
+
try {
|
|
5077
|
+
return JSON.parse(JSON.stringify(value));
|
|
5078
|
+
}
|
|
5079
|
+
catch {
|
|
5080
|
+
return value;
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
async function materializeKafkaRequestBody(cfg, maskReq, body) {
|
|
5084
|
+
return materializeInlinePrivacyValueAsync('request.body', sanitizeTraceValueForPrivacy(body), cfg, maskReq, null, normalizeMaskingConfig(cfg.masking), getRuntimePrivacyState(cfg).policy ?? null);
|
|
5085
|
+
}
|
|
5078
5086
|
function summarizeKafkaError(error) {
|
|
5079
5087
|
const message = typeof error?.message === 'string'
|
|
5080
5088
|
? error.message
|
|
@@ -5150,6 +5158,7 @@ function recordKafkaTraceEvent(raw, sink, cfg, maskReq) {
|
|
|
5150
5158
|
};
|
|
5151
5159
|
if (shouldDropTraceEvent(candidate))
|
|
5152
5160
|
return;
|
|
5161
|
+
const omitJsonBuiltinValues = shouldOmitJsonBuiltinTraceValues(candidate);
|
|
5153
5162
|
const evt = {
|
|
5154
5163
|
t: alignTimestamp(typeof raw.t === 'number' ? raw.t : Date.now()),
|
|
5155
5164
|
type: raw.type,
|
|
@@ -5163,14 +5172,14 @@ function recordKafkaTraceEvent(raw, sink, cfg, maskReq) {
|
|
|
5163
5172
|
};
|
|
5164
5173
|
const privacy = getRuntimePrivacyState(cfg).policy ?? null;
|
|
5165
5174
|
const masking = normalizeMaskingConfig(cfg.masking);
|
|
5166
|
-
if (raw.args !== undefined) {
|
|
5167
|
-
evt.args =
|
|
5175
|
+
if (!omitJsonBuiltinValues && raw.args !== undefined) {
|
|
5176
|
+
evt.args = sanitizeMaterializedTraceValue(materializeTracePrivacyValue('trace.args', sanitizeTraceArgsForPrivacy(raw.args), cfg, maskReq, candidate, masking, privacy));
|
|
5168
5177
|
}
|
|
5169
|
-
if (raw.returnValue !== undefined) {
|
|
5170
|
-
evt.returnValue =
|
|
5178
|
+
if (!omitJsonBuiltinValues && raw.returnValue !== undefined) {
|
|
5179
|
+
evt.returnValue = sanitizeMaterializedTraceValue(materializeTracePrivacyValue('trace.returnValue', sanitizeTraceValueForPrivacy(raw.returnValue), cfg, maskReq, candidate, masking, privacy));
|
|
5171
5180
|
}
|
|
5172
|
-
if (raw.error
|
|
5173
|
-
evt.error =
|
|
5181
|
+
if (hasMeaningfulRawTraceError(raw.error)) {
|
|
5182
|
+
evt.error = sanitizeMaterializedTraceValue(materializeTracePrivacyValue('trace.error', sanitizeTraceValueForPrivacy(raw.error), cfg, maskReq, candidate, masking, privacy));
|
|
5174
5183
|
}
|
|
5175
5184
|
if (raw.threw !== undefined)
|
|
5176
5185
|
evt.threw = raw.threw === true;
|
|
@@ -5197,6 +5206,7 @@ function buildPendingKafkaTraceEvent(raw) {
|
|
|
5197
5206
|
};
|
|
5198
5207
|
if (shouldDropTraceEvent(candidate))
|
|
5199
5208
|
return null;
|
|
5209
|
+
const omitJsonBuiltinValues = shouldOmitJsonBuiltinTraceValues(candidate);
|
|
5200
5210
|
const evt = {
|
|
5201
5211
|
t: alignTimestamp(typeof raw.t === 'number' ? raw.t : Date.now()),
|
|
5202
5212
|
type: raw.type,
|
|
@@ -5211,19 +5221,20 @@ function buildPendingKafkaTraceEvent(raw) {
|
|
|
5211
5221
|
if (typeof raw.sourceFile === 'string' && raw.sourceFile) {
|
|
5212
5222
|
evt.__reproSourceFile = String(raw.sourceFile);
|
|
5213
5223
|
}
|
|
5214
|
-
|
|
5224
|
+
const hasErrorPayload = hasMeaningfulRawTraceError(raw.error);
|
|
5225
|
+
if ((!omitJsonBuiltinValues && (raw.args !== undefined || raw.returnValue !== undefined)) || hasErrorPayload) {
|
|
5215
5226
|
evt.__reproPending = {
|
|
5216
|
-
...(raw.args !== undefined
|
|
5227
|
+
...(!omitJsonBuiltinValues && raw.args !== undefined
|
|
5217
5228
|
? {
|
|
5218
5229
|
argsRaw: normalizeRawTraceArgs(raw.args),
|
|
5219
5230
|
}
|
|
5220
5231
|
: {}),
|
|
5221
|
-
...(raw.returnValue !== undefined
|
|
5232
|
+
...(!omitJsonBuiltinValues && raw.returnValue !== undefined
|
|
5222
5233
|
? {
|
|
5223
5234
|
returnValueRaw: raw.returnValue,
|
|
5224
5235
|
}
|
|
5225
5236
|
: {}),
|
|
5226
|
-
...(
|
|
5237
|
+
...(hasErrorPayload
|
|
5227
5238
|
? {
|
|
5228
5239
|
errorRaw: raw.error,
|
|
5229
5240
|
}
|
|
@@ -5351,14 +5362,26 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
5351
5362
|
finally {
|
|
5352
5363
|
if (!sid)
|
|
5353
5364
|
return;
|
|
5354
|
-
const previewKeys = propagatedMessages
|
|
5355
|
-
.slice(0, 10)
|
|
5356
|
-
.map((message) => previewKafkaValue(message?.key))
|
|
5357
|
-
.filter((value) => value !== null);
|
|
5358
5365
|
const totalValueBytes = propagatedMessages.reduce((sum, message) => {
|
|
5359
5366
|
const size = kafkaValueSize(message?.value);
|
|
5360
5367
|
return sum + (size ?? 0);
|
|
5361
5368
|
}, 0);
|
|
5369
|
+
const requestKey = `KAFKA_PUBLISH ${topic}`;
|
|
5370
|
+
const maskReq = {
|
|
5371
|
+
method: 'KAFKA_PUBLISH',
|
|
5372
|
+
path: `kafka://${topic}`,
|
|
5373
|
+
key: requestKey,
|
|
5374
|
+
};
|
|
5375
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5376
|
+
transport: 'kafka',
|
|
5377
|
+
topic,
|
|
5378
|
+
messageCount: propagatedMessages.length,
|
|
5379
|
+
totalValueBytes,
|
|
5380
|
+
messages: propagatedMessages.map((message) => buildKafkaMessagePayload(message)),
|
|
5381
|
+
traceId: span?.traceId ?? null,
|
|
5382
|
+
spanId: span?.spanId ?? null,
|
|
5383
|
+
parentSpanId: span?.parentSpanId ?? null,
|
|
5384
|
+
});
|
|
5362
5385
|
const requestPayload = {
|
|
5363
5386
|
rid: publishRid,
|
|
5364
5387
|
method: 'KAFKA_PUBLISH',
|
|
@@ -5366,22 +5389,14 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
5366
5389
|
path: `kafka://${topic}`,
|
|
5367
5390
|
status: threw ? 500 : 200,
|
|
5368
5391
|
durMs: Date.now() - t0,
|
|
5369
|
-
key:
|
|
5392
|
+
key: requestKey,
|
|
5370
5393
|
headers: {
|
|
5371
5394
|
transport: 'kafka',
|
|
5372
5395
|
topic,
|
|
5373
5396
|
messageCount: propagatedMessages.length,
|
|
5374
5397
|
},
|
|
5375
|
-
body:
|
|
5376
|
-
|
|
5377
|
-
topic,
|
|
5378
|
-
messageCount: propagatedMessages.length,
|
|
5379
|
-
totalValueBytes,
|
|
5380
|
-
keyPreview: previewKeys,
|
|
5381
|
-
traceId: span?.traceId ?? null,
|
|
5382
|
-
spanId: span?.spanId ?? null,
|
|
5383
|
-
parentSpanId: span?.parentSpanId ?? null,
|
|
5384
|
-
},
|
|
5398
|
+
body: bodyMaterialization.value,
|
|
5399
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5385
5400
|
respBody: threw
|
|
5386
5401
|
? { error: summarizeKafkaError(error) }
|
|
5387
5402
|
: summarizeKafkaProducerResult(result),
|
|
@@ -5466,29 +5481,51 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
5466
5481
|
const count = Array.isArray(entry.messages) ? entry.messages.length : 0;
|
|
5467
5482
|
return sum + count;
|
|
5468
5483
|
}, 0);
|
|
5484
|
+
const totalValueBytes = patchedTopicMessages.reduce((sum, entry) => {
|
|
5485
|
+
const messages = Array.isArray(entry.messages) ? entry.messages : [];
|
|
5486
|
+
return sum + messages.reduce((messageSum, message) => {
|
|
5487
|
+
const size = kafkaValueSize(message?.value);
|
|
5488
|
+
return messageSum + (size ?? 0);
|
|
5489
|
+
}, 0);
|
|
5490
|
+
}, 0);
|
|
5491
|
+
const requestKey = uniqueTopics.length === 1
|
|
5492
|
+
? `KAFKA_PUBLISH_BATCH ${uniqueTopics[0]}`
|
|
5493
|
+
: 'KAFKA_PUBLISH_BATCH';
|
|
5494
|
+
const requestPath = uniqueTopics.length === 1 ? `kafka://${uniqueTopics[0]}` : 'kafka://batch';
|
|
5495
|
+
const maskReq = {
|
|
5496
|
+
method: 'KAFKA_PUBLISH_BATCH',
|
|
5497
|
+
path: requestPath,
|
|
5498
|
+
key: requestKey,
|
|
5499
|
+
};
|
|
5500
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5501
|
+
transport: 'kafka',
|
|
5502
|
+
topics: uniqueTopics,
|
|
5503
|
+
topicMessages: patchedTopicMessages.map((entry) => ({
|
|
5504
|
+
topic: sanitizeKafkaTopic(entry.topic),
|
|
5505
|
+
messages: (Array.isArray(entry.messages) ? entry.messages : [])
|
|
5506
|
+
.map((message) => buildKafkaMessagePayload(message)),
|
|
5507
|
+
})),
|
|
5508
|
+
messageCount,
|
|
5509
|
+
totalValueBytes,
|
|
5510
|
+
traceId: span?.traceId ?? null,
|
|
5511
|
+
spanId: span?.spanId ?? null,
|
|
5512
|
+
parentSpanId: span?.parentSpanId ?? null,
|
|
5513
|
+
});
|
|
5469
5514
|
const requestPayload = {
|
|
5470
5515
|
rid: publishRid,
|
|
5471
5516
|
method: 'KAFKA_PUBLISH_BATCH',
|
|
5472
|
-
url:
|
|
5473
|
-
path:
|
|
5517
|
+
url: requestPath,
|
|
5518
|
+
path: requestPath,
|
|
5474
5519
|
status: threw ? 500 : 200,
|
|
5475
5520
|
durMs: Date.now() - t0,
|
|
5476
|
-
key:
|
|
5477
|
-
? `KAFKA_PUBLISH_BATCH ${uniqueTopics[0]}`
|
|
5478
|
-
: 'KAFKA_PUBLISH_BATCH',
|
|
5521
|
+
key: requestKey,
|
|
5479
5522
|
headers: {
|
|
5480
5523
|
transport: 'kafka',
|
|
5481
5524
|
topicCount: uniqueTopics.length,
|
|
5482
5525
|
messageCount,
|
|
5483
5526
|
},
|
|
5484
|
-
body:
|
|
5485
|
-
|
|
5486
|
-
topics: uniqueTopics,
|
|
5487
|
-
messageCount,
|
|
5488
|
-
traceId: span?.traceId ?? null,
|
|
5489
|
-
spanId: span?.spanId ?? null,
|
|
5490
|
-
parentSpanId: span?.parentSpanId ?? null,
|
|
5491
|
-
},
|
|
5527
|
+
body: bodyMaterialization.value,
|
|
5528
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5492
5529
|
respBody: threw
|
|
5493
5530
|
? { error: summarizeKafkaError(error) }
|
|
5494
5531
|
: summarizeKafkaProducerResult(result),
|
|
@@ -5574,6 +5611,24 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
|
|
|
5574
5611
|
finally {
|
|
5575
5612
|
if (!sid)
|
|
5576
5613
|
return;
|
|
5614
|
+
const messagePayload = buildKafkaMessagePayload(message);
|
|
5615
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5616
|
+
transport: 'kafka',
|
|
5617
|
+
topic,
|
|
5618
|
+
partition,
|
|
5619
|
+
offset: message?.offset ?? null,
|
|
5620
|
+
timestamp: message?.timestamp ?? null,
|
|
5621
|
+
groupId: consumer?.__repro_group_id ?? null,
|
|
5622
|
+
parentRequestRid: runtime.requestRid,
|
|
5623
|
+
parentTraceId: runtime.traceId,
|
|
5624
|
+
parentSpanId: runtime.parentSpanId,
|
|
5625
|
+
messageKey: messagePayload.key,
|
|
5626
|
+
value: cloneKafkaTelemetryValue(messagePayload.value),
|
|
5627
|
+
rawValue: messagePayload.rawValue,
|
|
5628
|
+
valueEncoding: messagePayload.valueEncoding,
|
|
5629
|
+
valueBytes: messagePayload.valueBytes,
|
|
5630
|
+
message: messagePayload,
|
|
5631
|
+
});
|
|
5577
5632
|
const requestPayload = {
|
|
5578
5633
|
rid: consumeRid,
|
|
5579
5634
|
method: 'KAFKA_CONSUME',
|
|
@@ -5583,19 +5638,8 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
|
|
|
5583
5638
|
durMs: Date.now() - t0,
|
|
5584
5639
|
key: `KAFKA_CONSUME ${topic}`,
|
|
5585
5640
|
headers: normalizeKafkaHeadersForPayload(message?.headers),
|
|
5586
|
-
body:
|
|
5587
|
-
|
|
5588
|
-
topic,
|
|
5589
|
-
partition,
|
|
5590
|
-
offset: message?.offset ?? null,
|
|
5591
|
-
timestamp: message?.timestamp ?? null,
|
|
5592
|
-
groupId: consumer?.__repro_group_id ?? null,
|
|
5593
|
-
parentRequestRid: runtime.requestRid,
|
|
5594
|
-
parentTraceId: runtime.traceId,
|
|
5595
|
-
parentSpanId: runtime.parentSpanId,
|
|
5596
|
-
messageKey: previewKafkaValue(message?.key),
|
|
5597
|
-
valueBytes: kafkaValueSize(message?.value),
|
|
5598
|
-
},
|
|
5641
|
+
body: bodyMaterialization.value,
|
|
5642
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5599
5643
|
respBody: threw ? { error: summarizeKafkaError(error) } : undefined,
|
|
5600
5644
|
};
|
|
5601
5645
|
post(cfg, sid, {
|
|
@@ -5680,6 +5724,20 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
|
|
|
5680
5724
|
return;
|
|
5681
5725
|
const firstOffset = messages.length ? messages[0]?.offset ?? null : null;
|
|
5682
5726
|
const lastOffset = messages.length ? messages[messages.length - 1]?.offset ?? null : null;
|
|
5727
|
+
const firstMessagePayload = firstMessage ? buildKafkaMessagePayload(firstMessage) : null;
|
|
5728
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5729
|
+
transport: 'kafka',
|
|
5730
|
+
topic,
|
|
5731
|
+
groupId: consumer?.__repro_group_id ?? null,
|
|
5732
|
+
messageCount: messages.length,
|
|
5733
|
+
firstOffset,
|
|
5734
|
+
lastOffset,
|
|
5735
|
+
parentRequestRid: runtime.requestRid,
|
|
5736
|
+
parentTraceId: runtime.traceId,
|
|
5737
|
+
parentSpanId: runtime.parentSpanId,
|
|
5738
|
+
firstMessageKey: firstMessagePayload?.key ?? null,
|
|
5739
|
+
messages: messages.map((message) => buildKafkaMessagePayload(message)),
|
|
5740
|
+
});
|
|
5683
5741
|
const requestPayload = {
|
|
5684
5742
|
rid: consumeRid,
|
|
5685
5743
|
method: 'KAFKA_CONSUME_BATCH',
|
|
@@ -5689,18 +5747,8 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
|
|
|
5689
5747
|
durMs: Date.now() - t0,
|
|
5690
5748
|
key: `KAFKA_CONSUME_BATCH ${topic}`,
|
|
5691
5749
|
headers: firstMessage ? normalizeKafkaHeadersForPayload(firstMessage.headers) : {},
|
|
5692
|
-
body:
|
|
5693
|
-
|
|
5694
|
-
topic,
|
|
5695
|
-
groupId: consumer?.__repro_group_id ?? null,
|
|
5696
|
-
messageCount: messages.length,
|
|
5697
|
-
firstOffset,
|
|
5698
|
-
lastOffset,
|
|
5699
|
-
parentRequestRid: runtime.requestRid,
|
|
5700
|
-
parentTraceId: runtime.traceId,
|
|
5701
|
-
parentSpanId: runtime.parentSpanId,
|
|
5702
|
-
firstMessageKey: firstMessage ? previewKafkaValue(firstMessage.key) : null,
|
|
5703
|
-
},
|
|
5750
|
+
body: bodyMaterialization.value,
|
|
5751
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5704
5752
|
respBody: threw ? { error: summarizeKafkaError(error) } : undefined,
|
|
5705
5753
|
};
|
|
5706
5754
|
post(cfg, sid, {
|
|
@@ -6531,5 +6579,7 @@ exports.__reproTestHooks = {
|
|
|
6531
6579
|
getRuntimePrivacyState(cfg).policy = policy;
|
|
6532
6580
|
},
|
|
6533
6581
|
recordKafkaTraceEventAsyncForTest: recordKafkaTraceEventAsync,
|
|
6582
|
+
materializeInlinePrivacyValueAsyncForTest: materializeInlinePrivacyValueAsync,
|
|
6583
|
+
patchKafkaProducerInstanceForTest: patchKafkaProducerInstance,
|
|
6534
6584
|
wrapKafkaEachMessageHandlerForTest: wrapKafkaEachMessageHandler,
|
|
6535
6585
|
};
|