@reproapp/node-sdk 0.0.4 → 0.0.6
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 +462 -439
- package/package.json +2 -2
- package/src/index.ts +539 -488
- 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/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)
|
|
@@ -3933,7 +3836,8 @@ function reproMiddleware(cfg) {
|
|
|
3933
3836
|
if (finished) {
|
|
3934
3837
|
scheduleIdleFlush();
|
|
3935
3838
|
}
|
|
3936
|
-
|
|
3839
|
+
const hasErrorPayload = hasMeaningfulRawTraceError(ev.error);
|
|
3840
|
+
if (ev.args !== undefined || ev.returnValue !== undefined || hasErrorPayload) {
|
|
3937
3841
|
evt.__reproPending = {
|
|
3938
3842
|
...(ev.args !== undefined
|
|
3939
3843
|
? {
|
|
@@ -3945,7 +3849,7 @@ function reproMiddleware(cfg) {
|
|
|
3945
3849
|
returnValueRaw: ev.returnValue,
|
|
3946
3850
|
}
|
|
3947
3851
|
: {}),
|
|
3948
|
-
...(
|
|
3852
|
+
...(hasErrorPayload
|
|
3949
3853
|
? {
|
|
3950
3854
|
errorRaw: ev.error,
|
|
3951
3855
|
}
|
|
@@ -4010,12 +3914,17 @@ function reproMiddleware(cfg) {
|
|
|
4010
3914
|
};
|
|
4011
3915
|
})();
|
|
4012
3916
|
const activePrivacy = resolvePrivacy();
|
|
4013
|
-
const
|
|
3917
|
+
const requestBodyRaw = req.body;
|
|
3918
|
+
const requestBodyMaterialization = limitRawInlinePrivacyValue('request.body', requestBodyRaw)
|
|
3919
|
+
?? await materializeInlinePrivacyValueAsync('request.body', sanitizeRequestSnapshot(requestBodyRaw), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4014
3920
|
const requestBody = requestBodyMaterialization.value;
|
|
4015
3921
|
const requestParams = await applyPrivacyThenMaskAsync('request.params', sanitizeRequestSnapshot(req.params), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4016
3922
|
const requestQuery = await applyPrivacyThenMaskAsync('request.query', sanitizeRequestSnapshot(req.query), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4017
3923
|
const maskedHeaders = await applyPrivacyThenMaskAsync('request.headers', requestHeaders, cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4018
|
-
const responseBodyMaterialization =
|
|
3924
|
+
const responseBodyMaterialization = capturedBody === undefined
|
|
3925
|
+
? { value: undefined }
|
|
3926
|
+
: limitRawInlinePrivacyValue('response.body', capturedBody)
|
|
3927
|
+
?? await materializeInlinePrivacyValueAsync('response.body', sanitizeRequestSnapshot(capturedBody), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
|
|
4019
3928
|
const responseBody = responseBodyMaterialization.value;
|
|
4020
3929
|
const requestValueEntries = [];
|
|
4021
3930
|
const bodyValueCapture = requestBodyMaterialization.skipped
|
|
@@ -4567,7 +4476,11 @@ function sanitizeResultForMeta(value, options = {}) {
|
|
|
4567
4476
|
if (typeof value === 'function')
|
|
4568
4477
|
return undefined;
|
|
4569
4478
|
try {
|
|
4570
|
-
return sanitizeTraceValue(value, 0, new WeakMap(),
|
|
4479
|
+
return sanitizeTraceValue(value, 0, new WeakMap(), {
|
|
4480
|
+
preserveLongStrings: true,
|
|
4481
|
+
disableTruncation: true,
|
|
4482
|
+
...options,
|
|
4483
|
+
});
|
|
4571
4484
|
}
|
|
4572
4485
|
catch {
|
|
4573
4486
|
const fallback = safeJson(value);
|
|
@@ -4653,7 +4566,7 @@ async function emitDbQueryAsync(cfg, sid, aid, payload) {
|
|
|
4653
4566
|
const afterPreview = afterMaterialization.value;
|
|
4654
4567
|
const resultMetaMaterialization = await materializeInlinePrivacyValueAsync('db.resultMeta', resultMetaSource ?? undefined, cfg, maskReq, null, null, privacy, dbContext);
|
|
4655
4568
|
const resultMetaPreviewRaw = resultMetaMaterialization.value;
|
|
4656
|
-
const resultMetaPreview =
|
|
4569
|
+
const resultMetaPreview = sanitizeMaterializedTraceValue(resultMetaPreviewRaw);
|
|
4657
4570
|
const errorMaterialization = await materializeInlinePrivacyValueAsync('db.error', payload.error ?? undefined, cfg, maskReq, null, null, privacy, dbContext);
|
|
4658
4571
|
const errorPreview = errorMaterialization.value;
|
|
4659
4572
|
const capture = {
|
|
@@ -5049,23 +4962,6 @@ function normalizeKafkaHeadersForPayload(headers) {
|
|
|
5049
4962
|
}
|
|
5050
4963
|
return out;
|
|
5051
4964
|
}
|
|
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
4965
|
function kafkaValueSize(value) {
|
|
5070
4966
|
if (value === null || value === undefined)
|
|
5071
4967
|
return null;
|
|
@@ -5073,8 +4969,93 @@ function kafkaValueSize(value) {
|
|
|
5073
4969
|
return Buffer.byteLength(value, 'utf8');
|
|
5074
4970
|
if (Buffer.isBuffer(value))
|
|
5075
4971
|
return value.length;
|
|
4972
|
+
if (value instanceof Uint8Array)
|
|
4973
|
+
return value.byteLength;
|
|
5076
4974
|
return null;
|
|
5077
4975
|
}
|
|
4976
|
+
function decodeKafkaValue(value) {
|
|
4977
|
+
if (value === null || value === undefined)
|
|
4978
|
+
return null;
|
|
4979
|
+
if (typeof value === 'string')
|
|
4980
|
+
return value;
|
|
4981
|
+
if (Buffer.isBuffer(value))
|
|
4982
|
+
return value.toString('utf8');
|
|
4983
|
+
if (value instanceof Uint8Array)
|
|
4984
|
+
return Buffer.from(value).toString('utf8');
|
|
4985
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
4986
|
+
return value;
|
|
4987
|
+
return sanitizeResultForMeta(value);
|
|
4988
|
+
}
|
|
4989
|
+
function parseKafkaJsonString(value) {
|
|
4990
|
+
const trimmed = value.trim();
|
|
4991
|
+
if (!trimmed || !'{['.includes(trimmed[0])) {
|
|
4992
|
+
return { parsed: false, value };
|
|
4993
|
+
}
|
|
4994
|
+
try {
|
|
4995
|
+
return { parsed: true, value: JSON.parse(value) };
|
|
4996
|
+
}
|
|
4997
|
+
catch {
|
|
4998
|
+
return { parsed: false, value };
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
function decodeKafkaMessageValue(value) {
|
|
5002
|
+
const decoded = decodeKafkaValue(value);
|
|
5003
|
+
if (typeof decoded !== 'string') {
|
|
5004
|
+
return {
|
|
5005
|
+
value: decoded,
|
|
5006
|
+
valueEncoding: decoded === null ? null : typeof decoded,
|
|
5007
|
+
};
|
|
5008
|
+
}
|
|
5009
|
+
const parsed = parseKafkaJsonString(decoded);
|
|
5010
|
+
if (parsed.parsed) {
|
|
5011
|
+
return {
|
|
5012
|
+
value: parsed.value,
|
|
5013
|
+
rawValue: decoded,
|
|
5014
|
+
valueEncoding: 'json',
|
|
5015
|
+
};
|
|
5016
|
+
}
|
|
5017
|
+
return {
|
|
5018
|
+
value: decoded,
|
|
5019
|
+
valueEncoding: 'utf8',
|
|
5020
|
+
};
|
|
5021
|
+
}
|
|
5022
|
+
function buildKafkaMessagePayload(message) {
|
|
5023
|
+
const msgObj = message && typeof message === 'object' ? message : { value: message };
|
|
5024
|
+
const decoded = decodeKafkaMessageValue(msgObj.value);
|
|
5025
|
+
const payload = {
|
|
5026
|
+
key: decodeKafkaValue(msgObj.key),
|
|
5027
|
+
value: decoded.value,
|
|
5028
|
+
valueEncoding: decoded.valueEncoding,
|
|
5029
|
+
valueBytes: kafkaValueSize(msgObj.value),
|
|
5030
|
+
headers: normalizeKafkaHeadersForPayload(msgObj.headers),
|
|
5031
|
+
};
|
|
5032
|
+
if (decoded.rawValue !== undefined) {
|
|
5033
|
+
payload.rawValue = decoded.rawValue;
|
|
5034
|
+
}
|
|
5035
|
+
if (msgObj.partition !== undefined) {
|
|
5036
|
+
payload.partition = msgObj.partition;
|
|
5037
|
+
}
|
|
5038
|
+
if (msgObj.timestamp !== undefined) {
|
|
5039
|
+
payload.timestamp = msgObj.timestamp;
|
|
5040
|
+
}
|
|
5041
|
+
if (msgObj.offset !== undefined) {
|
|
5042
|
+
payload.offset = msgObj.offset;
|
|
5043
|
+
}
|
|
5044
|
+
return payload;
|
|
5045
|
+
}
|
|
5046
|
+
function cloneKafkaTelemetryValue(value) {
|
|
5047
|
+
if (value === undefined || value === null)
|
|
5048
|
+
return value;
|
|
5049
|
+
try {
|
|
5050
|
+
return JSON.parse(JSON.stringify(value));
|
|
5051
|
+
}
|
|
5052
|
+
catch {
|
|
5053
|
+
return value;
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
async function materializeKafkaRequestBody(cfg, maskReq, body) {
|
|
5057
|
+
return materializeInlinePrivacyValueAsync('request.body', sanitizeTraceValueForPrivacy(body), cfg, maskReq, null, normalizeMaskingConfig(cfg.masking), getRuntimePrivacyState(cfg).policy ?? null);
|
|
5058
|
+
}
|
|
5078
5059
|
function summarizeKafkaError(error) {
|
|
5079
5060
|
const message = typeof error?.message === 'string'
|
|
5080
5061
|
? error.message
|
|
@@ -5150,6 +5131,7 @@ function recordKafkaTraceEvent(raw, sink, cfg, maskReq) {
|
|
|
5150
5131
|
};
|
|
5151
5132
|
if (shouldDropTraceEvent(candidate))
|
|
5152
5133
|
return;
|
|
5134
|
+
const omitJsonBuiltinValues = shouldOmitJsonBuiltinTraceValues(candidate);
|
|
5153
5135
|
const evt = {
|
|
5154
5136
|
t: alignTimestamp(typeof raw.t === 'number' ? raw.t : Date.now()),
|
|
5155
5137
|
type: raw.type,
|
|
@@ -5163,14 +5145,14 @@ function recordKafkaTraceEvent(raw, sink, cfg, maskReq) {
|
|
|
5163
5145
|
};
|
|
5164
5146
|
const privacy = getRuntimePrivacyState(cfg).policy ?? null;
|
|
5165
5147
|
const masking = normalizeMaskingConfig(cfg.masking);
|
|
5166
|
-
if (raw.args !== undefined) {
|
|
5167
|
-
evt.args =
|
|
5148
|
+
if (!omitJsonBuiltinValues && raw.args !== undefined) {
|
|
5149
|
+
evt.args = sanitizeMaterializedTraceValue(materializeTracePrivacyValue('trace.args', sanitizeTraceArgsForPrivacy(raw.args), cfg, maskReq, candidate, masking, privacy));
|
|
5168
5150
|
}
|
|
5169
|
-
if (raw.returnValue !== undefined) {
|
|
5170
|
-
evt.returnValue =
|
|
5151
|
+
if (!omitJsonBuiltinValues && raw.returnValue !== undefined) {
|
|
5152
|
+
evt.returnValue = sanitizeMaterializedTraceValue(materializeTracePrivacyValue('trace.returnValue', sanitizeTraceValueForPrivacy(raw.returnValue), cfg, maskReq, candidate, masking, privacy));
|
|
5171
5153
|
}
|
|
5172
|
-
if (raw.error
|
|
5173
|
-
evt.error =
|
|
5154
|
+
if (hasMeaningfulRawTraceError(raw.error)) {
|
|
5155
|
+
evt.error = sanitizeMaterializedTraceValue(materializeTracePrivacyValue('trace.error', sanitizeTraceValueForPrivacy(raw.error), cfg, maskReq, candidate, masking, privacy));
|
|
5174
5156
|
}
|
|
5175
5157
|
if (raw.threw !== undefined)
|
|
5176
5158
|
evt.threw = raw.threw === true;
|
|
@@ -5197,6 +5179,7 @@ function buildPendingKafkaTraceEvent(raw) {
|
|
|
5197
5179
|
};
|
|
5198
5180
|
if (shouldDropTraceEvent(candidate))
|
|
5199
5181
|
return null;
|
|
5182
|
+
const omitJsonBuiltinValues = shouldOmitJsonBuiltinTraceValues(candidate);
|
|
5200
5183
|
const evt = {
|
|
5201
5184
|
t: alignTimestamp(typeof raw.t === 'number' ? raw.t : Date.now()),
|
|
5202
5185
|
type: raw.type,
|
|
@@ -5211,19 +5194,20 @@ function buildPendingKafkaTraceEvent(raw) {
|
|
|
5211
5194
|
if (typeof raw.sourceFile === 'string' && raw.sourceFile) {
|
|
5212
5195
|
evt.__reproSourceFile = String(raw.sourceFile);
|
|
5213
5196
|
}
|
|
5214
|
-
|
|
5197
|
+
const hasErrorPayload = hasMeaningfulRawTraceError(raw.error);
|
|
5198
|
+
if ((!omitJsonBuiltinValues && (raw.args !== undefined || raw.returnValue !== undefined)) || hasErrorPayload) {
|
|
5215
5199
|
evt.__reproPending = {
|
|
5216
|
-
...(raw.args !== undefined
|
|
5200
|
+
...(!omitJsonBuiltinValues && raw.args !== undefined
|
|
5217
5201
|
? {
|
|
5218
5202
|
argsRaw: normalizeRawTraceArgs(raw.args),
|
|
5219
5203
|
}
|
|
5220
5204
|
: {}),
|
|
5221
|
-
...(raw.returnValue !== undefined
|
|
5205
|
+
...(!omitJsonBuiltinValues && raw.returnValue !== undefined
|
|
5222
5206
|
? {
|
|
5223
5207
|
returnValueRaw: raw.returnValue,
|
|
5224
5208
|
}
|
|
5225
5209
|
: {}),
|
|
5226
|
-
...(
|
|
5210
|
+
...(hasErrorPayload
|
|
5227
5211
|
? {
|
|
5228
5212
|
errorRaw: raw.error,
|
|
5229
5213
|
}
|
|
@@ -5351,14 +5335,26 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
5351
5335
|
finally {
|
|
5352
5336
|
if (!sid)
|
|
5353
5337
|
return;
|
|
5354
|
-
const previewKeys = propagatedMessages
|
|
5355
|
-
.slice(0, 10)
|
|
5356
|
-
.map((message) => previewKafkaValue(message?.key))
|
|
5357
|
-
.filter((value) => value !== null);
|
|
5358
5338
|
const totalValueBytes = propagatedMessages.reduce((sum, message) => {
|
|
5359
5339
|
const size = kafkaValueSize(message?.value);
|
|
5360
5340
|
return sum + (size ?? 0);
|
|
5361
5341
|
}, 0);
|
|
5342
|
+
const requestKey = `KAFKA_PUBLISH ${topic}`;
|
|
5343
|
+
const maskReq = {
|
|
5344
|
+
method: 'KAFKA_PUBLISH',
|
|
5345
|
+
path: `kafka://${topic}`,
|
|
5346
|
+
key: requestKey,
|
|
5347
|
+
};
|
|
5348
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5349
|
+
transport: 'kafka',
|
|
5350
|
+
topic,
|
|
5351
|
+
messageCount: propagatedMessages.length,
|
|
5352
|
+
totalValueBytes,
|
|
5353
|
+
messages: propagatedMessages.map((message) => buildKafkaMessagePayload(message)),
|
|
5354
|
+
traceId: span?.traceId ?? null,
|
|
5355
|
+
spanId: span?.spanId ?? null,
|
|
5356
|
+
parentSpanId: span?.parentSpanId ?? null,
|
|
5357
|
+
});
|
|
5362
5358
|
const requestPayload = {
|
|
5363
5359
|
rid: publishRid,
|
|
5364
5360
|
method: 'KAFKA_PUBLISH',
|
|
@@ -5366,22 +5362,14 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
5366
5362
|
path: `kafka://${topic}`,
|
|
5367
5363
|
status: threw ? 500 : 200,
|
|
5368
5364
|
durMs: Date.now() - t0,
|
|
5369
|
-
key:
|
|
5365
|
+
key: requestKey,
|
|
5370
5366
|
headers: {
|
|
5371
5367
|
transport: 'kafka',
|
|
5372
5368
|
topic,
|
|
5373
5369
|
messageCount: propagatedMessages.length,
|
|
5374
5370
|
},
|
|
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
|
-
},
|
|
5371
|
+
body: bodyMaterialization.value,
|
|
5372
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5385
5373
|
respBody: threw
|
|
5386
5374
|
? { error: summarizeKafkaError(error) }
|
|
5387
5375
|
: summarizeKafkaProducerResult(result),
|
|
@@ -5466,29 +5454,51 @@ function patchKafkaProducerInstance(producer, cfg) {
|
|
|
5466
5454
|
const count = Array.isArray(entry.messages) ? entry.messages.length : 0;
|
|
5467
5455
|
return sum + count;
|
|
5468
5456
|
}, 0);
|
|
5457
|
+
const totalValueBytes = patchedTopicMessages.reduce((sum, entry) => {
|
|
5458
|
+
const messages = Array.isArray(entry.messages) ? entry.messages : [];
|
|
5459
|
+
return sum + messages.reduce((messageSum, message) => {
|
|
5460
|
+
const size = kafkaValueSize(message?.value);
|
|
5461
|
+
return messageSum + (size ?? 0);
|
|
5462
|
+
}, 0);
|
|
5463
|
+
}, 0);
|
|
5464
|
+
const requestKey = uniqueTopics.length === 1
|
|
5465
|
+
? `KAFKA_PUBLISH_BATCH ${uniqueTopics[0]}`
|
|
5466
|
+
: 'KAFKA_PUBLISH_BATCH';
|
|
5467
|
+
const requestPath = uniqueTopics.length === 1 ? `kafka://${uniqueTopics[0]}` : 'kafka://batch';
|
|
5468
|
+
const maskReq = {
|
|
5469
|
+
method: 'KAFKA_PUBLISH_BATCH',
|
|
5470
|
+
path: requestPath,
|
|
5471
|
+
key: requestKey,
|
|
5472
|
+
};
|
|
5473
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5474
|
+
transport: 'kafka',
|
|
5475
|
+
topics: uniqueTopics,
|
|
5476
|
+
topicMessages: patchedTopicMessages.map((entry) => ({
|
|
5477
|
+
topic: sanitizeKafkaTopic(entry.topic),
|
|
5478
|
+
messages: (Array.isArray(entry.messages) ? entry.messages : [])
|
|
5479
|
+
.map((message) => buildKafkaMessagePayload(message)),
|
|
5480
|
+
})),
|
|
5481
|
+
messageCount,
|
|
5482
|
+
totalValueBytes,
|
|
5483
|
+
traceId: span?.traceId ?? null,
|
|
5484
|
+
spanId: span?.spanId ?? null,
|
|
5485
|
+
parentSpanId: span?.parentSpanId ?? null,
|
|
5486
|
+
});
|
|
5469
5487
|
const requestPayload = {
|
|
5470
5488
|
rid: publishRid,
|
|
5471
5489
|
method: 'KAFKA_PUBLISH_BATCH',
|
|
5472
|
-
url:
|
|
5473
|
-
path:
|
|
5490
|
+
url: requestPath,
|
|
5491
|
+
path: requestPath,
|
|
5474
5492
|
status: threw ? 500 : 200,
|
|
5475
5493
|
durMs: Date.now() - t0,
|
|
5476
|
-
key:
|
|
5477
|
-
? `KAFKA_PUBLISH_BATCH ${uniqueTopics[0]}`
|
|
5478
|
-
: 'KAFKA_PUBLISH_BATCH',
|
|
5494
|
+
key: requestKey,
|
|
5479
5495
|
headers: {
|
|
5480
5496
|
transport: 'kafka',
|
|
5481
5497
|
topicCount: uniqueTopics.length,
|
|
5482
5498
|
messageCount,
|
|
5483
5499
|
},
|
|
5484
|
-
body:
|
|
5485
|
-
|
|
5486
|
-
topics: uniqueTopics,
|
|
5487
|
-
messageCount,
|
|
5488
|
-
traceId: span?.traceId ?? null,
|
|
5489
|
-
spanId: span?.spanId ?? null,
|
|
5490
|
-
parentSpanId: span?.parentSpanId ?? null,
|
|
5491
|
-
},
|
|
5500
|
+
body: bodyMaterialization.value,
|
|
5501
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5492
5502
|
respBody: threw
|
|
5493
5503
|
? { error: summarizeKafkaError(error) }
|
|
5494
5504
|
: summarizeKafkaProducerResult(result),
|
|
@@ -5574,6 +5584,24 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
|
|
|
5574
5584
|
finally {
|
|
5575
5585
|
if (!sid)
|
|
5576
5586
|
return;
|
|
5587
|
+
const messagePayload = buildKafkaMessagePayload(message);
|
|
5588
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5589
|
+
transport: 'kafka',
|
|
5590
|
+
topic,
|
|
5591
|
+
partition,
|
|
5592
|
+
offset: message?.offset ?? null,
|
|
5593
|
+
timestamp: message?.timestamp ?? null,
|
|
5594
|
+
groupId: consumer?.__repro_group_id ?? null,
|
|
5595
|
+
parentRequestRid: runtime.requestRid,
|
|
5596
|
+
parentTraceId: runtime.traceId,
|
|
5597
|
+
parentSpanId: runtime.parentSpanId,
|
|
5598
|
+
messageKey: messagePayload.key,
|
|
5599
|
+
value: cloneKafkaTelemetryValue(messagePayload.value),
|
|
5600
|
+
rawValue: messagePayload.rawValue,
|
|
5601
|
+
valueEncoding: messagePayload.valueEncoding,
|
|
5602
|
+
valueBytes: messagePayload.valueBytes,
|
|
5603
|
+
message: messagePayload,
|
|
5604
|
+
});
|
|
5577
5605
|
const requestPayload = {
|
|
5578
5606
|
rid: consumeRid,
|
|
5579
5607
|
method: 'KAFKA_CONSUME',
|
|
@@ -5583,19 +5611,8 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
|
|
|
5583
5611
|
durMs: Date.now() - t0,
|
|
5584
5612
|
key: `KAFKA_CONSUME ${topic}`,
|
|
5585
5613
|
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
|
-
},
|
|
5614
|
+
body: bodyMaterialization.value,
|
|
5615
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5599
5616
|
respBody: threw ? { error: summarizeKafkaError(error) } : undefined,
|
|
5600
5617
|
};
|
|
5601
5618
|
post(cfg, sid, {
|
|
@@ -5680,6 +5697,20 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
|
|
|
5680
5697
|
return;
|
|
5681
5698
|
const firstOffset = messages.length ? messages[0]?.offset ?? null : null;
|
|
5682
5699
|
const lastOffset = messages.length ? messages[messages.length - 1]?.offset ?? null : null;
|
|
5700
|
+
const firstMessagePayload = firstMessage ? buildKafkaMessagePayload(firstMessage) : null;
|
|
5701
|
+
const bodyMaterialization = await materializeKafkaRequestBody(cfg, maskReq, {
|
|
5702
|
+
transport: 'kafka',
|
|
5703
|
+
topic,
|
|
5704
|
+
groupId: consumer?.__repro_group_id ?? null,
|
|
5705
|
+
messageCount: messages.length,
|
|
5706
|
+
firstOffset,
|
|
5707
|
+
lastOffset,
|
|
5708
|
+
parentRequestRid: runtime.requestRid,
|
|
5709
|
+
parentTraceId: runtime.traceId,
|
|
5710
|
+
parentSpanId: runtime.parentSpanId,
|
|
5711
|
+
firstMessageKey: firstMessagePayload?.key ?? null,
|
|
5712
|
+
messages: messages.map((message) => buildKafkaMessagePayload(message)),
|
|
5713
|
+
});
|
|
5683
5714
|
const requestPayload = {
|
|
5684
5715
|
rid: consumeRid,
|
|
5685
5716
|
method: 'KAFKA_CONSUME_BATCH',
|
|
@@ -5689,18 +5720,8 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
|
|
|
5689
5720
|
durMs: Date.now() - t0,
|
|
5690
5721
|
key: `KAFKA_CONSUME_BATCH ${topic}`,
|
|
5691
5722
|
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
|
-
},
|
|
5723
|
+
body: bodyMaterialization.value,
|
|
5724
|
+
bodyMaterialization: bodyMaterialization.skipped,
|
|
5704
5725
|
respBody: threw ? { error: summarizeKafkaError(error) } : undefined,
|
|
5705
5726
|
};
|
|
5706
5727
|
post(cfg, sid, {
|
|
@@ -6531,5 +6552,7 @@ exports.__reproTestHooks = {
|
|
|
6531
6552
|
getRuntimePrivacyState(cfg).policy = policy;
|
|
6532
6553
|
},
|
|
6533
6554
|
recordKafkaTraceEventAsyncForTest: recordKafkaTraceEventAsync,
|
|
6555
|
+
materializeInlinePrivacyValueAsyncForTest: materializeInlinePrivacyValueAsync,
|
|
6556
|
+
patchKafkaProducerInstanceForTest: patchKafkaProducerInstance,
|
|
6534
6557
|
wrapKafkaEachMessageHandlerForTest: wrapKafkaEachMessageHandler,
|
|
6535
6558
|
};
|