@reproapp/node-sdk 0.0.21 → 0.0.23
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.js +106 -46
- package/package.json +2 -2
- package/src/index.ts +134 -73
- package/test/circular-capture.test.js +1 -0
- package/test/client-performance-regression.test.js +189 -0
- package/test/disable-subtree.test.js +1 -0
- package/test/express-trace-http-args.test.js +2 -0
- package/test/kafka-runtime-privacy-policy.test.js +10 -7
- package/test/request-flush-timing.test.js +1 -0
- package/test/trace-batch-size.test.js +16 -0
package/dist/index.js
CHANGED
|
@@ -843,7 +843,7 @@ const SDK_BACKGROUND_IDLE_DELAY_MS = (() => {
|
|
|
843
843
|
const env = Number(process.env.REPRO_SDK_BACKGROUND_IDLE_DELAY_MS);
|
|
844
844
|
if (Number.isFinite(env) && env >= 0)
|
|
845
845
|
return env;
|
|
846
|
-
return
|
|
846
|
+
return 5000;
|
|
847
847
|
})();
|
|
848
848
|
const SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = (() => {
|
|
849
849
|
const env = Number(process.env.REPRO_SDK_BACKGROUND_BUSY_IDLE_DELAY_MS);
|
|
@@ -852,10 +852,17 @@ const SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = (() => {
|
|
|
852
852
|
return 1000;
|
|
853
853
|
})();
|
|
854
854
|
const SDK_BACKGROUND_MAX_DEFER_MS = (() => {
|
|
855
|
-
const
|
|
855
|
+
const raw = String(process.env.REPRO_SDK_BACKGROUND_MAX_DEFER_MS ?? '').trim().toLowerCase();
|
|
856
|
+
if (!raw) {
|
|
857
|
+
return Number.POSITIVE_INFINITY;
|
|
858
|
+
}
|
|
859
|
+
if (raw === 'off' || raw === 'never' || raw === 'infinite' || raw === 'infinity' || raw === '-1') {
|
|
860
|
+
return Number.POSITIVE_INFINITY;
|
|
861
|
+
}
|
|
862
|
+
const env = Number(raw);
|
|
856
863
|
if (Number.isFinite(env) && env >= 0)
|
|
857
864
|
return Math.trunc(env);
|
|
858
|
-
return
|
|
865
|
+
return Number.POSITIVE_INFINITY;
|
|
859
866
|
})();
|
|
860
867
|
const SDK_BACKGROUND_WORK_TIMEOUT_MS = (() => {
|
|
861
868
|
const env = Number(process.env.REPRO_SDK_BACKGROUND_WORK_TIMEOUT_MS);
|
|
@@ -915,7 +922,9 @@ function noteClientActivity(now = Date.now()) {
|
|
|
915
922
|
}
|
|
916
923
|
function getSdkBackgroundDelayMs(now = Date.now()) {
|
|
917
924
|
if (hasActiveClientRequests()) {
|
|
918
|
-
if (oldestActiveClientRequestAt !== null &&
|
|
925
|
+
if (oldestActiveClientRequestAt !== null &&
|
|
926
|
+
Number.isFinite(SDK_BACKGROUND_MAX_DEFER_MS) &&
|
|
927
|
+
SDK_BACKGROUND_MAX_DEFER_MS >= 0) {
|
|
919
928
|
const activeForMs = now - oldestActiveClientRequestAt;
|
|
920
929
|
if (activeForMs >= SDK_BACKGROUND_MAX_DEFER_MS)
|
|
921
930
|
return 0;
|
|
@@ -1703,6 +1712,18 @@ const TRACE_BATCH_MAX_SERIALIZED_BYTES = (() => {
|
|
|
1703
1712
|
return Math.trunc(env);
|
|
1704
1713
|
return 512 * 1024;
|
|
1705
1714
|
})();
|
|
1715
|
+
const TRACE_MAX_EVENTS_PER_REQUEST = (() => {
|
|
1716
|
+
const env = Number(process.env.REPRO_TRACE_MAX_EVENTS_PER_REQUEST);
|
|
1717
|
+
if (Number.isFinite(env) && env > 0)
|
|
1718
|
+
return Math.trunc(env);
|
|
1719
|
+
return 1000;
|
|
1720
|
+
})();
|
|
1721
|
+
const TRACE_MAX_BATCHES_PER_REQUEST = (() => {
|
|
1722
|
+
const env = Number(process.env.REPRO_TRACE_MAX_BATCHES_PER_REQUEST);
|
|
1723
|
+
if (Number.isFinite(env) && env > 0)
|
|
1724
|
+
return Math.trunc(env);
|
|
1725
|
+
return 8;
|
|
1726
|
+
})();
|
|
1706
1727
|
const TRACE_FLUSH_DELAY_MS = 20;
|
|
1707
1728
|
// Choose how to order trace events in payloads.
|
|
1708
1729
|
// - "chronological" (default): preserve event arrival order (no reshuffle).
|
|
@@ -2259,54 +2280,69 @@ async function materializePendingTraceEvents(events, params) {
|
|
|
2259
2280
|
parentSpanId: evt.parentSpanId ?? null,
|
|
2260
2281
|
};
|
|
2261
2282
|
if (!omitJsonBuiltinValues && pending.argsRaw !== undefined) {
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
const argsValueCapture = await maybeCaptureTraceValueAsync({
|
|
2265
|
-
target: 'trace.args',
|
|
2266
|
-
rawValue: pending.argsRaw,
|
|
2267
|
-
previewValue: evt.args,
|
|
2268
|
-
capture: captureContext,
|
|
2269
|
-
metadata: traceValueMetadata,
|
|
2270
|
-
});
|
|
2271
|
-
if (argsValueCapture?.entry) {
|
|
2272
|
-
attachTraceValueEntry(evt, argsValueCapture.entry);
|
|
2283
|
+
if (!__FULL_VALUE_CAPTURE_ENABLED && traceInlineValueExceedsLimit(pending.argsRaw)) {
|
|
2284
|
+
evt.args = makeOmittedValue('inline-size-limit');
|
|
2273
2285
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2286
|
+
else {
|
|
2287
|
+
const argsMaterialized = await materializeTracePrivacyValueAsync('trace.args', sanitizeTraceArgsForPrivacy(pending.argsRaw), params.cfg, params.maskReq, candidate, params.masking, activePrivacy);
|
|
2288
|
+
evt.args = limitMaterializedTraceInlineValue(argsMaterialized);
|
|
2289
|
+
const argsValueCapture = await maybeCaptureTraceValueAsync({
|
|
2290
|
+
target: 'trace.args',
|
|
2291
|
+
rawValue: pending.argsRaw,
|
|
2292
|
+
previewValue: evt.args,
|
|
2293
|
+
capture: captureContext,
|
|
2294
|
+
metadata: traceValueMetadata,
|
|
2295
|
+
});
|
|
2296
|
+
if (argsValueCapture?.entry) {
|
|
2297
|
+
attachTraceValueEntry(evt, argsValueCapture.entry);
|
|
2298
|
+
}
|
|
2299
|
+
if (argsValueCapture?.captureRef) {
|
|
2300
|
+
evt.argsValueCapture = argsValueCapture.captureRef;
|
|
2301
|
+
}
|
|
2276
2302
|
}
|
|
2277
2303
|
}
|
|
2278
2304
|
if (!omitJsonBuiltinValues && pending.returnValueRaw !== undefined) {
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
const returnValueCapture = await maybeCaptureTraceValueAsync({
|
|
2282
|
-
target: 'trace.returnValue',
|
|
2283
|
-
rawValue: pending.returnValueRaw,
|
|
2284
|
-
previewValue: evt.returnValue,
|
|
2285
|
-
capture: captureContext,
|
|
2286
|
-
metadata: traceValueMetadata,
|
|
2287
|
-
});
|
|
2288
|
-
if (returnValueCapture?.entry) {
|
|
2289
|
-
attachTraceValueEntry(evt, returnValueCapture.entry);
|
|
2305
|
+
if (!__FULL_VALUE_CAPTURE_ENABLED && traceInlineValueExceedsLimit(pending.returnValueRaw)) {
|
|
2306
|
+
evt.returnValue = makeOmittedValue('inline-size-limit');
|
|
2290
2307
|
}
|
|
2291
|
-
|
|
2292
|
-
|
|
2308
|
+
else {
|
|
2309
|
+
const returnValueMaterialized = await materializeTracePrivacyValueAsync('trace.returnValue', sanitizeTraceValueForPrivacy(pending.returnValueRaw), params.cfg, params.maskReq, candidate, params.masking, activePrivacy);
|
|
2310
|
+
evt.returnValue = limitMaterializedTraceInlineValue(returnValueMaterialized);
|
|
2311
|
+
const returnValueCapture = await maybeCaptureTraceValueAsync({
|
|
2312
|
+
target: 'trace.returnValue',
|
|
2313
|
+
rawValue: pending.returnValueRaw,
|
|
2314
|
+
previewValue: evt.returnValue,
|
|
2315
|
+
capture: captureContext,
|
|
2316
|
+
metadata: traceValueMetadata,
|
|
2317
|
+
});
|
|
2318
|
+
if (returnValueCapture?.entry) {
|
|
2319
|
+
attachTraceValueEntry(evt, returnValueCapture.entry);
|
|
2320
|
+
}
|
|
2321
|
+
if (returnValueCapture?.captureRef) {
|
|
2322
|
+
evt.returnValueCapture = returnValueCapture.captureRef;
|
|
2323
|
+
}
|
|
2293
2324
|
}
|
|
2294
2325
|
}
|
|
2295
2326
|
if (pending.errorRaw !== undefined) {
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
const errorValueCapture = await maybeCaptureTraceValueAsync({
|
|
2299
|
-
target: 'trace.error',
|
|
2300
|
-
rawValue: pending.errorRaw,
|
|
2301
|
-
previewValue: evt.error,
|
|
2302
|
-
capture: captureContext,
|
|
2303
|
-
metadata: traceValueMetadata,
|
|
2304
|
-
});
|
|
2305
|
-
if (errorValueCapture?.entry) {
|
|
2306
|
-
attachTraceValueEntry(evt, errorValueCapture.entry);
|
|
2327
|
+
if (!__FULL_VALUE_CAPTURE_ENABLED && traceInlineValueExceedsLimit(pending.errorRaw)) {
|
|
2328
|
+
evt.error = makeOmittedValue('inline-size-limit');
|
|
2307
2329
|
}
|
|
2308
|
-
|
|
2309
|
-
|
|
2330
|
+
else {
|
|
2331
|
+
const errorMaterialized = await materializeTracePrivacyValueAsync('trace.error', sanitizeTraceValueForPrivacy(pending.errorRaw), params.cfg, params.maskReq, candidate, params.masking, activePrivacy);
|
|
2332
|
+
evt.error = limitMaterializedTraceInlineValue(errorMaterialized);
|
|
2333
|
+
const errorValueCapture = await maybeCaptureTraceValueAsync({
|
|
2334
|
+
target: 'trace.error',
|
|
2335
|
+
rawValue: pending.errorRaw,
|
|
2336
|
+
previewValue: evt.error,
|
|
2337
|
+
capture: captureContext,
|
|
2338
|
+
metadata: traceValueMetadata,
|
|
2339
|
+
});
|
|
2340
|
+
if (errorValueCapture?.entry) {
|
|
2341
|
+
attachTraceValueEntry(evt, errorValueCapture.entry);
|
|
2342
|
+
}
|
|
2343
|
+
if (errorValueCapture?.captureRef) {
|
|
2344
|
+
evt.errorValueCapture = errorValueCapture.captureRef;
|
|
2345
|
+
}
|
|
2310
2346
|
}
|
|
2311
2347
|
}
|
|
2312
2348
|
}
|
|
@@ -2808,7 +2844,22 @@ function traceInlineValueExceedsLimit(value) {
|
|
|
2808
2844
|
return boundedSerializedTraceValueLength(value, TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS).exceeded;
|
|
2809
2845
|
}
|
|
2810
2846
|
function limitInlinePrivacyValue(target, value) {
|
|
2811
|
-
|
|
2847
|
+
if (value === undefined) {
|
|
2848
|
+
return { value };
|
|
2849
|
+
}
|
|
2850
|
+
const serialized = boundedSerializedTraceValueLength(value, TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS);
|
|
2851
|
+
if (serialized.exceeded) {
|
|
2852
|
+
return {
|
|
2853
|
+
value: undefined,
|
|
2854
|
+
skipped: {
|
|
2855
|
+
status: 'skipped',
|
|
2856
|
+
reason: 'inline-size-limit',
|
|
2857
|
+
target,
|
|
2858
|
+
serializedLength: Math.max(serialized.length, TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS + 1),
|
|
2859
|
+
limit: TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS,
|
|
2860
|
+
},
|
|
2861
|
+
};
|
|
2862
|
+
}
|
|
2812
2863
|
return { value };
|
|
2813
2864
|
}
|
|
2814
2865
|
function limitRawInlinePrivacyValue(target, value) {
|
|
@@ -3727,22 +3778,31 @@ function estimateTraceBatchSerializedBytes(batch, requestRid, actionId, batchInd
|
|
|
3727
3778
|
function chunkTraceEventsForTransport(events, requestRid, actionId) {
|
|
3728
3779
|
if (!Array.isArray(events) || events.length === 0)
|
|
3729
3780
|
return [];
|
|
3730
|
-
const
|
|
3781
|
+
const boundedEvents = events.slice(0, TRACE_MAX_EVENTS_PER_REQUEST);
|
|
3782
|
+
const countBatches = chunkArray(boundedEvents, TRACE_BATCH_SIZE);
|
|
3731
3783
|
const sizedBatches = [];
|
|
3732
3784
|
let current = [];
|
|
3733
3785
|
for (const event of countBatches.flat()) {
|
|
3786
|
+
if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
|
|
3787
|
+
break;
|
|
3788
|
+
}
|
|
3734
3789
|
const candidate = current.concat(event);
|
|
3735
3790
|
const batchIndex = sizedBatches.length;
|
|
3736
3791
|
const estimatedBytes = estimateTraceBatchSerializedBytes(candidate, requestRid, actionId, batchIndex);
|
|
3737
3792
|
if (current.length > 0 &&
|
|
3738
3793
|
estimatedBytes > TRACE_BATCH_MAX_SERIALIZED_BYTES) {
|
|
3739
3794
|
sizedBatches.push(current);
|
|
3795
|
+
if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
|
|
3796
|
+
current = [];
|
|
3797
|
+
break;
|
|
3798
|
+
}
|
|
3740
3799
|
current = [event];
|
|
3741
3800
|
continue;
|
|
3742
3801
|
}
|
|
3743
3802
|
current = candidate;
|
|
3744
3803
|
}
|
|
3745
|
-
if (current.length > 0
|
|
3804
|
+
if (current.length > 0 &&
|
|
3805
|
+
sizedBatches.length < TRACE_MAX_BATCHES_PER_REQUEST) {
|
|
3746
3806
|
sizedBatches.push(current);
|
|
3747
3807
|
}
|
|
3748
3808
|
return sizedBatches;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reproapp/node-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"description": "Repro Nest SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"build": "tsc -p tsconfig.json",
|
|
13
13
|
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
|
|
14
14
|
"prepublishOnly": "npm run build",
|
|
15
|
-
"test": "npm run build && node test/unawaited.test.js && node test/integration-unawaited.js && node test/request-flush-timing.test.js && node test/request-capture-background.test.js && node test/request-manifest-priority.test.js && node test/runtime-no-double-invoke.test.js && node test/express-trace-http-args.test.js && node test/trace-batch-size.test.js && node test/sdk-background-priority.test.js && node test/ingest-queue-retention.test.js && node test/ingest-timeout.test.js && node -r ./tracer/register test/promise-map.test.js && node test/disable-subtree.test.js && node test/circular-capture.test.js && node test/wrap-plugin-arrow-args.test.js && node test/wrap-plugin-super-call.test.js && node test/function-arg-identity.test.js && node test/privacy-runtime-policy.test.js && node test/runtime-privacy-materialization.test.js && node test/kafka-runtime-privacy-policy.test.js",
|
|
15
|
+
"test": "npm run build && node test/unawaited.test.js && node test/integration-unawaited.js && node test/request-flush-timing.test.js && node test/request-capture-background.test.js && node test/client-performance-regression.test.js && node test/request-manifest-priority.test.js && node test/runtime-no-double-invoke.test.js && node test/express-trace-http-args.test.js && node test/trace-batch-size.test.js && node test/sdk-background-priority.test.js && node test/ingest-queue-retention.test.js && node test/ingest-timeout.test.js && node -r ./tracer/register test/promise-map.test.js && node test/disable-subtree.test.js && node test/circular-capture.test.js && node test/wrap-plugin-arrow-args.test.js && node test/wrap-plugin-super-call.test.js && node test/function-arg-identity.test.js && node test/privacy-runtime-policy.test.js && node test/runtime-privacy-materialization.test.js && node test/kafka-runtime-privacy-policy.test.js",
|
|
16
16
|
"test:containers": "npm run build && node test/runtime-no-double-invoke.testcontainers.test.js && node test/wrap-plugin-super-call.testcontainers.test.js && node test/function-arg-identity.testcontainers.test.js"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -1239,7 +1239,7 @@ function nextRequestId(base: number | string): string {
|
|
|
1239
1239
|
const SDK_BACKGROUND_IDLE_DELAY_MS = (() => {
|
|
1240
1240
|
const env = Number(process.env.REPRO_SDK_BACKGROUND_IDLE_DELAY_MS);
|
|
1241
1241
|
if (Number.isFinite(env) && env >= 0) return env;
|
|
1242
|
-
return
|
|
1242
|
+
return 5000;
|
|
1243
1243
|
})();
|
|
1244
1244
|
|
|
1245
1245
|
const SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = (() => {
|
|
@@ -1249,9 +1249,16 @@ const SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = (() => {
|
|
|
1249
1249
|
})();
|
|
1250
1250
|
|
|
1251
1251
|
const SDK_BACKGROUND_MAX_DEFER_MS = (() => {
|
|
1252
|
-
const
|
|
1252
|
+
const raw = String(process.env.REPRO_SDK_BACKGROUND_MAX_DEFER_MS ?? '').trim().toLowerCase();
|
|
1253
|
+
if (!raw) {
|
|
1254
|
+
return Number.POSITIVE_INFINITY;
|
|
1255
|
+
}
|
|
1256
|
+
if (raw === 'off' || raw === 'never' || raw === 'infinite' || raw === 'infinity' || raw === '-1') {
|
|
1257
|
+
return Number.POSITIVE_INFINITY;
|
|
1258
|
+
}
|
|
1259
|
+
const env = Number(raw);
|
|
1253
1260
|
if (Number.isFinite(env) && env >= 0) return Math.trunc(env);
|
|
1254
|
-
return
|
|
1261
|
+
return Number.POSITIVE_INFINITY;
|
|
1255
1262
|
})();
|
|
1256
1263
|
|
|
1257
1264
|
const SDK_BACKGROUND_WORK_TIMEOUT_MS = (() => {
|
|
@@ -1319,7 +1326,11 @@ function noteClientActivity(now = Date.now()): void {
|
|
|
1319
1326
|
|
|
1320
1327
|
function getSdkBackgroundDelayMs(now = Date.now()): number {
|
|
1321
1328
|
if (hasActiveClientRequests()) {
|
|
1322
|
-
if (
|
|
1329
|
+
if (
|
|
1330
|
+
oldestActiveClientRequestAt !== null &&
|
|
1331
|
+
Number.isFinite(SDK_BACKGROUND_MAX_DEFER_MS) &&
|
|
1332
|
+
SDK_BACKGROUND_MAX_DEFER_MS >= 0
|
|
1333
|
+
) {
|
|
1323
1334
|
const activeForMs = now - oldestActiveClientRequestAt;
|
|
1324
1335
|
if (activeForMs >= SDK_BACKGROUND_MAX_DEFER_MS) return 0;
|
|
1325
1336
|
return Math.min(SDK_BACKGROUND_IDLE_DELAY_MS, Math.max(0, SDK_BACKGROUND_MAX_DEFER_MS - activeForMs));
|
|
@@ -2105,6 +2116,16 @@ const TRACE_BATCH_MAX_SERIALIZED_BYTES = (() => {
|
|
|
2105
2116
|
if (Number.isFinite(env) && env > 0) return Math.trunc(env);
|
|
2106
2117
|
return 512 * 1024;
|
|
2107
2118
|
})();
|
|
2119
|
+
const TRACE_MAX_EVENTS_PER_REQUEST = (() => {
|
|
2120
|
+
const env = Number(process.env.REPRO_TRACE_MAX_EVENTS_PER_REQUEST);
|
|
2121
|
+
if (Number.isFinite(env) && env > 0) return Math.trunc(env);
|
|
2122
|
+
return 1000;
|
|
2123
|
+
})();
|
|
2124
|
+
const TRACE_MAX_BATCHES_PER_REQUEST = (() => {
|
|
2125
|
+
const env = Number(process.env.REPRO_TRACE_MAX_BATCHES_PER_REQUEST);
|
|
2126
|
+
if (Number.isFinite(env) && env > 0) return Math.trunc(env);
|
|
2127
|
+
return 8;
|
|
2128
|
+
})();
|
|
2108
2129
|
const TRACE_FLUSH_DELAY_MS = 20;
|
|
2109
2130
|
// Choose how to order trace events in payloads.
|
|
2110
2131
|
// - "chronological" (default): preserve event arrival order (no reshuffle).
|
|
@@ -2704,78 +2725,90 @@ async function materializePendingTraceEvents(
|
|
|
2704
2725
|
};
|
|
2705
2726
|
|
|
2706
2727
|
if (!omitJsonBuiltinValues && pending.argsRaw !== undefined) {
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2728
|
+
if (!__FULL_VALUE_CAPTURE_ENABLED && traceInlineValueExceedsLimit(pending.argsRaw)) {
|
|
2729
|
+
evt.args = makeOmittedValue('inline-size-limit');
|
|
2730
|
+
} else {
|
|
2731
|
+
const argsMaterialized = await materializeTracePrivacyValueAsync(
|
|
2732
|
+
'trace.args',
|
|
2733
|
+
sanitizeTraceArgsForPrivacy(pending.argsRaw),
|
|
2734
|
+
params.cfg,
|
|
2735
|
+
params.maskReq,
|
|
2736
|
+
candidate,
|
|
2737
|
+
params.masking,
|
|
2738
|
+
activePrivacy,
|
|
2739
|
+
);
|
|
2740
|
+
evt.args = limitMaterializedTraceInlineValue(argsMaterialized);
|
|
2741
|
+
const argsValueCapture = await maybeCaptureTraceValueAsync({
|
|
2742
|
+
target: 'trace.args',
|
|
2743
|
+
rawValue: pending.argsRaw,
|
|
2744
|
+
previewValue: evt.args,
|
|
2745
|
+
capture: captureContext,
|
|
2746
|
+
metadata: traceValueMetadata,
|
|
2747
|
+
});
|
|
2748
|
+
if (argsValueCapture?.entry) {
|
|
2749
|
+
attachTraceValueEntry(evt, argsValueCapture.entry);
|
|
2750
|
+
}
|
|
2751
|
+
if (argsValueCapture?.captureRef) {
|
|
2752
|
+
evt.argsValueCapture = argsValueCapture.captureRef;
|
|
2753
|
+
}
|
|
2729
2754
|
}
|
|
2730
2755
|
}
|
|
2731
2756
|
if (!omitJsonBuiltinValues && pending.returnValueRaw !== undefined) {
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2757
|
+
if (!__FULL_VALUE_CAPTURE_ENABLED && traceInlineValueExceedsLimit(pending.returnValueRaw)) {
|
|
2758
|
+
evt.returnValue = makeOmittedValue('inline-size-limit');
|
|
2759
|
+
} else {
|
|
2760
|
+
const returnValueMaterialized = await materializeTracePrivacyValueAsync(
|
|
2761
|
+
'trace.returnValue',
|
|
2762
|
+
sanitizeTraceValueForPrivacy(pending.returnValueRaw),
|
|
2763
|
+
params.cfg,
|
|
2764
|
+
params.maskReq,
|
|
2765
|
+
candidate,
|
|
2766
|
+
params.masking,
|
|
2767
|
+
activePrivacy,
|
|
2768
|
+
);
|
|
2769
|
+
evt.returnValue = limitMaterializedTraceInlineValue(returnValueMaterialized);
|
|
2770
|
+
const returnValueCapture = await maybeCaptureTraceValueAsync({
|
|
2771
|
+
target: 'trace.returnValue',
|
|
2772
|
+
rawValue: pending.returnValueRaw,
|
|
2773
|
+
previewValue: evt.returnValue,
|
|
2774
|
+
capture: captureContext,
|
|
2775
|
+
metadata: traceValueMetadata,
|
|
2776
|
+
});
|
|
2777
|
+
if (returnValueCapture?.entry) {
|
|
2778
|
+
attachTraceValueEntry(evt, returnValueCapture.entry);
|
|
2779
|
+
}
|
|
2780
|
+
if (returnValueCapture?.captureRef) {
|
|
2781
|
+
evt.returnValueCapture = returnValueCapture.captureRef;
|
|
2782
|
+
}
|
|
2754
2783
|
}
|
|
2755
2784
|
}
|
|
2756
2785
|
if (pending.errorRaw !== undefined) {
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2786
|
+
if (!__FULL_VALUE_CAPTURE_ENABLED && traceInlineValueExceedsLimit(pending.errorRaw)) {
|
|
2787
|
+
evt.error = makeOmittedValue('inline-size-limit');
|
|
2788
|
+
} else {
|
|
2789
|
+
const errorMaterialized = await materializeTracePrivacyValueAsync(
|
|
2790
|
+
'trace.error',
|
|
2791
|
+
sanitizeTraceValueForPrivacy(pending.errorRaw),
|
|
2792
|
+
params.cfg,
|
|
2793
|
+
params.maskReq,
|
|
2794
|
+
candidate,
|
|
2795
|
+
params.masking,
|
|
2796
|
+
activePrivacy,
|
|
2797
|
+
);
|
|
2798
|
+
evt.error = limitMaterializedTraceInlineValue(errorMaterialized);
|
|
2799
|
+
const errorValueCapture = await maybeCaptureTraceValueAsync({
|
|
2800
|
+
target: 'trace.error',
|
|
2801
|
+
rawValue: pending.errorRaw,
|
|
2802
|
+
previewValue: evt.error,
|
|
2803
|
+
capture: captureContext,
|
|
2804
|
+
metadata: traceValueMetadata,
|
|
2805
|
+
});
|
|
2806
|
+
if (errorValueCapture?.entry) {
|
|
2807
|
+
attachTraceValueEntry(evt, errorValueCapture.entry);
|
|
2808
|
+
}
|
|
2809
|
+
if (errorValueCapture?.captureRef) {
|
|
2810
|
+
evt.errorValueCapture = errorValueCapture.captureRef;
|
|
2811
|
+
}
|
|
2779
2812
|
}
|
|
2780
2813
|
}
|
|
2781
2814
|
}
|
|
@@ -3405,7 +3438,24 @@ function limitInlinePrivacyValue(
|
|
|
3405
3438
|
target: RuntimePrivacySurface,
|
|
3406
3439
|
value: any,
|
|
3407
3440
|
): InlinePrivacyMaterializationResult {
|
|
3408
|
-
|
|
3441
|
+
if (value === undefined) {
|
|
3442
|
+
return { value };
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
const serialized = boundedSerializedTraceValueLength(value, TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS);
|
|
3446
|
+
if (serialized.exceeded) {
|
|
3447
|
+
return {
|
|
3448
|
+
value: undefined,
|
|
3449
|
+
skipped: {
|
|
3450
|
+
status: 'skipped',
|
|
3451
|
+
reason: 'inline-size-limit',
|
|
3452
|
+
target,
|
|
3453
|
+
serializedLength: Math.max(serialized.length, TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS + 1),
|
|
3454
|
+
limit: TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS,
|
|
3455
|
+
},
|
|
3456
|
+
};
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3409
3459
|
return { value };
|
|
3410
3460
|
}
|
|
3411
3461
|
|
|
@@ -4459,11 +4509,15 @@ function chunkTraceEventsForTransport(
|
|
|
4459
4509
|
): TraceEventRecord[][] {
|
|
4460
4510
|
if (!Array.isArray(events) || events.length === 0) return [];
|
|
4461
4511
|
|
|
4462
|
-
const
|
|
4512
|
+
const boundedEvents = events.slice(0, TRACE_MAX_EVENTS_PER_REQUEST);
|
|
4513
|
+
const countBatches = chunkArray(boundedEvents, TRACE_BATCH_SIZE);
|
|
4463
4514
|
const sizedBatches: TraceEventRecord[][] = [];
|
|
4464
4515
|
let current: TraceEventRecord[] = [];
|
|
4465
4516
|
|
|
4466
4517
|
for (const event of countBatches.flat()) {
|
|
4518
|
+
if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
|
|
4519
|
+
break;
|
|
4520
|
+
}
|
|
4467
4521
|
const candidate = current.concat(event);
|
|
4468
4522
|
const batchIndex = sizedBatches.length;
|
|
4469
4523
|
const estimatedBytes = estimateTraceBatchSerializedBytes(
|
|
@@ -4478,6 +4532,10 @@ function chunkTraceEventsForTransport(
|
|
|
4478
4532
|
estimatedBytes > TRACE_BATCH_MAX_SERIALIZED_BYTES
|
|
4479
4533
|
) {
|
|
4480
4534
|
sizedBatches.push(current);
|
|
4535
|
+
if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
|
|
4536
|
+
current = [];
|
|
4537
|
+
break;
|
|
4538
|
+
}
|
|
4481
4539
|
current = [event];
|
|
4482
4540
|
continue;
|
|
4483
4541
|
}
|
|
@@ -4485,7 +4543,10 @@ function chunkTraceEventsForTransport(
|
|
|
4485
4543
|
current = candidate;
|
|
4486
4544
|
}
|
|
4487
4545
|
|
|
4488
|
-
if (
|
|
4546
|
+
if (
|
|
4547
|
+
current.length > 0 &&
|
|
4548
|
+
sizedBatches.length < TRACE_MAX_BATCHES_PER_REQUEST
|
|
4549
|
+
) {
|
|
4489
4550
|
sizedBatches.push(current);
|
|
4490
4551
|
}
|
|
4491
4552
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
process.env.TRACE_LINGER_AFTER_FINISH_MS = '0';
|
|
2
2
|
process.env.TRACE_IDLE_FLUSH_MS = '25';
|
|
3
3
|
process.env.SESSION_DRAIN_TIMEOUT_MS = '0';
|
|
4
|
+
process.env.REPRO_SDK_BACKGROUND_IDLE_DELAY_MS = '25';
|
|
4
5
|
|
|
5
6
|
const assert = require('assert');
|
|
6
7
|
const { EventEmitter } = require('events');
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
delete process.env.REPRO_SDK_BACKGROUND_MAX_DEFER_MS;
|
|
2
|
+
process.env.REPRO_SDK_BACKGROUND_IDLE_DELAY_MS = '25';
|
|
3
|
+
process.env.REPRO_SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = '0';
|
|
4
|
+
process.env.REPRO_SDK_TRACE_INLINE_VALUE_MAX_SERIALIZED_CHARS = '2048';
|
|
5
|
+
process.env.TRACE_IDLE_FLUSH_MS = '10';
|
|
6
|
+
process.env.TRACE_LINGER_AFTER_FINISH_MS = '0';
|
|
7
|
+
|
|
8
|
+
const assert = require('node:assert/strict');
|
|
9
|
+
const { EventEmitter } = require('node:events');
|
|
10
|
+
const { initReproTracing, reproMiddleware, __reproTestHooks } = require('../dist');
|
|
11
|
+
const { flushIngestQueue } = require('../dist/ingest/client');
|
|
12
|
+
|
|
13
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
|
+
|
|
15
|
+
async function waitFor(predicate, timeoutMs = 2500) {
|
|
16
|
+
const deadline = Date.now() + timeoutMs;
|
|
17
|
+
while (Date.now() < deadline) {
|
|
18
|
+
if (predicate()) return;
|
|
19
|
+
await sleep(20);
|
|
20
|
+
}
|
|
21
|
+
assert(predicate(), 'timed out waiting for expected condition');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function makeReqRes(sessionId, actionId, path = '/captured') {
|
|
25
|
+
const req = new EventEmitter();
|
|
26
|
+
req.method = 'GET';
|
|
27
|
+
req.url = path;
|
|
28
|
+
req.headers = sessionId && actionId
|
|
29
|
+
? {
|
|
30
|
+
'x-bug-session-id': sessionId,
|
|
31
|
+
'x-bug-action-id': actionId,
|
|
32
|
+
'x-bug-request-start': String(Date.now()),
|
|
33
|
+
}
|
|
34
|
+
: {};
|
|
35
|
+
req.body = undefined;
|
|
36
|
+
req.params = {};
|
|
37
|
+
req.query = {};
|
|
38
|
+
|
|
39
|
+
const res = new EventEmitter();
|
|
40
|
+
res.statusCode = 200;
|
|
41
|
+
res.getHeader = () => 'application/json';
|
|
42
|
+
res.setHeader = () => {};
|
|
43
|
+
res.json = function (body) { this.body = body; this.emit('finish'); return body; };
|
|
44
|
+
res.send = function (body) { this.body = body; this.emit('finish'); return body; };
|
|
45
|
+
res.write = () => true;
|
|
46
|
+
res.end = () => { res.emit('finish'); return true; };
|
|
47
|
+
|
|
48
|
+
return { req, res };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function invokeMiddleware(middleware, req, res, handler) {
|
|
52
|
+
await new Promise((resolve, reject) => {
|
|
53
|
+
void middleware(req, res, async (err) => {
|
|
54
|
+
if (err) {
|
|
55
|
+
reject(err);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await handler();
|
|
60
|
+
resolve();
|
|
61
|
+
} catch (error) {
|
|
62
|
+
reject(error);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function flattenEvents(posts) {
|
|
69
|
+
return posts.flatMap((body) => Array.isArray(body?.events) ? body.events : []);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function eventsOf(posts, eventType) {
|
|
73
|
+
return flattenEvents(posts).filter((event) => event?.event_type === eventType);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function largePayload() {
|
|
77
|
+
return {
|
|
78
|
+
rows: Array.from({ length: 400 }, (_, index) => ({
|
|
79
|
+
index,
|
|
80
|
+
depot: `depot-${index}`,
|
|
81
|
+
description: `large response row ${index} `.repeat(4),
|
|
82
|
+
})),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function main() {
|
|
87
|
+
const capturedBodies = [];
|
|
88
|
+
const originalFetch = global.fetch;
|
|
89
|
+
global.fetch = async (_url, init = {}) => {
|
|
90
|
+
capturedBodies.push(JSON.parse(String(init.body || '{}')));
|
|
91
|
+
return {
|
|
92
|
+
ok: true,
|
|
93
|
+
status: 202,
|
|
94
|
+
json: async () => ({ ok: true }),
|
|
95
|
+
text: async () => '{"ok":true}',
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const cfg = {
|
|
101
|
+
tenantId: 'TENANT_test',
|
|
102
|
+
appId: 'APP_test',
|
|
103
|
+
appSecret: 'secret',
|
|
104
|
+
captureHeaders: false,
|
|
105
|
+
privacy: { environment: 'dev' },
|
|
106
|
+
ingestBase: 'http://127.0.0.1:65535',
|
|
107
|
+
};
|
|
108
|
+
const middleware = reproMiddleware(cfg);
|
|
109
|
+
|
|
110
|
+
__reproTestHooks.resetSdkBackgroundQueuesForTest();
|
|
111
|
+
const held = makeReqRes(null, null, '/held-open');
|
|
112
|
+
await invokeMiddleware(middleware, held.req, held.res, async () => {
|
|
113
|
+
// Keep one app endpoint open. Background capture from other requests must not run.
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const tagged = makeReqRes('S_perf_regression', 'A_perf_regression');
|
|
117
|
+
await invokeMiddleware(middleware, tagged.req, tagged.res, async () => {
|
|
118
|
+
tagged.res.json({ ok: true });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await sleep(2200);
|
|
122
|
+
assert.equal(
|
|
123
|
+
eventsOf(capturedBodies, 'backend_request').length,
|
|
124
|
+
0,
|
|
125
|
+
`background request capture ran while a client endpoint was still active: ${JSON.stringify(capturedBodies)}`,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
held.res.emit('finish');
|
|
129
|
+
await waitFor(() => eventsOf(capturedBodies, 'backend_request').length === 1);
|
|
130
|
+
|
|
131
|
+
capturedBodies.length = 0;
|
|
132
|
+
__reproTestHooks.resetSdkBackgroundQueuesForTest();
|
|
133
|
+
initReproTracing({ instrument: false, logFunctionCalls: false });
|
|
134
|
+
|
|
135
|
+
function largeTraceReturn() {
|
|
136
|
+
return largePayload();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const large = makeReqRes('S_perf_large_payload', 'A_perf_large_payload', '/large-payload');
|
|
140
|
+
await invokeMiddleware(middleware, large.req, large.res, async () => {
|
|
141
|
+
const traced = global.__repro_call(
|
|
142
|
+
largeTraceReturn,
|
|
143
|
+
null,
|
|
144
|
+
[],
|
|
145
|
+
'app',
|
|
146
|
+
1,
|
|
147
|
+
'largeTraceReturn',
|
|
148
|
+
false,
|
|
149
|
+
);
|
|
150
|
+
large.res.json(traced);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
await waitFor(() => eventsOf(capturedBodies, 'backend_request').length === 1);
|
|
154
|
+
await waitFor(() => eventsOf(capturedBodies, 'trace_batch').length >= 1);
|
|
155
|
+
|
|
156
|
+
const backendRequest = eventsOf(capturedBodies, 'backend_request')[0]?.payload?.request;
|
|
157
|
+
assert(backendRequest, JSON.stringify(capturedBodies));
|
|
158
|
+
assert.equal(backendRequest.respBody, undefined, JSON.stringify(backendRequest));
|
|
159
|
+
assert.equal(
|
|
160
|
+
backendRequest.respBodyMaterialization?.reason,
|
|
161
|
+
'inline-size-limit',
|
|
162
|
+
JSON.stringify(backendRequest),
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const traceEvents = eventsOf(capturedBodies, 'trace_batch')
|
|
166
|
+
.flatMap((event) => Array.isArray(event?.payload?.trace) ? event.payload.trace : []);
|
|
167
|
+
const largeReturnExit = traceEvents.find((event) =>
|
|
168
|
+
event?.fn === 'largeTraceReturn' &&
|
|
169
|
+
event?.type === 'exit' &&
|
|
170
|
+
event?.returnValue,
|
|
171
|
+
);
|
|
172
|
+
assert(largeReturnExit, JSON.stringify(traceEvents));
|
|
173
|
+
assert.deepEqual(
|
|
174
|
+
largeReturnExit.returnValue,
|
|
175
|
+
{ __kind: 'omitted', reason: 'inline-size-limit' },
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
console.log('client performance regression guards OK');
|
|
179
|
+
} finally {
|
|
180
|
+
await flushIngestQueue();
|
|
181
|
+
__reproTestHooks.resetSdkBackgroundQueuesForTest();
|
|
182
|
+
global.fetch = originalFetch;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
main().catch((error) => {
|
|
187
|
+
console.error(error);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
process.env.TRACE_LINGER_AFTER_FINISH_MS = '0';
|
|
3
3
|
process.env.TRACE_IDLE_FLUSH_MS = '25';
|
|
4
4
|
process.env.SESSION_DRAIN_TIMEOUT_MS = '0';
|
|
5
|
+
process.env.REPRO_SDK_BACKGROUND_IDLE_DELAY_MS = '25';
|
|
5
6
|
|
|
6
7
|
const assert = require('assert');
|
|
7
8
|
const { EventEmitter } = require('events');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const assert = require('assert');
|
|
2
2
|
process.env.REPRO_SDK_BACKGROUND_MAX_DEFER_MS = '50';
|
|
3
|
+
process.env.REPRO_SDK_BACKGROUND_IDLE_DELAY_MS = '25';
|
|
3
4
|
|
|
4
5
|
const { EventEmitter } = require('events');
|
|
5
6
|
const { normalizeRuntimePrivacyPolicy } = require('../dist/privacy');
|
|
@@ -306,7 +307,7 @@ async function testKafkaTraceFlushIsNotBlockedForeverByActiveHttpRequest() {
|
|
|
306
307
|
}
|
|
307
308
|
}
|
|
308
309
|
|
|
309
|
-
async function
|
|
310
|
+
async function testLargeHttpResponseBodyKeepsRequestMetadataWithoutInlineBody() {
|
|
310
311
|
const marker = 'OVERSIZED_HTTP_RESPONSE_MARKER';
|
|
311
312
|
const capturedBodies = [];
|
|
312
313
|
const originalFetch = global.fetch;
|
|
@@ -341,13 +342,15 @@ async function testLargeHttpResponseBodyIsCapturedWithoutDroppingRequest() {
|
|
|
341
342
|
await waitFor(() => capturedBodies.some((body) => {
|
|
342
343
|
const text = JSON.stringify(body);
|
|
343
344
|
return text.includes('"event_type":"backend_request"') &&
|
|
344
|
-
text.includes(
|
|
345
|
+
text.includes('"reason":"inline-size-limit"');
|
|
345
346
|
}));
|
|
346
347
|
const text = JSON.stringify(capturedBodies);
|
|
347
|
-
assert(text.includes(marker), text);
|
|
348
|
-
assert(
|
|
349
|
-
assert(
|
|
350
|
-
|
|
348
|
+
assert(!text.includes(marker), text);
|
|
349
|
+
assert(text.includes('respBodyMaterialization'), text);
|
|
350
|
+
assert(text.includes('"target":"response.body"'), text);
|
|
351
|
+
assert(!text.includes('__type":"json-string'), text);
|
|
352
|
+
assert(!text.includes('__truncatedKeys'), text);
|
|
353
|
+
assert(!text.includes('more chars'), text);
|
|
351
354
|
} finally {
|
|
352
355
|
await flushIngestQueue();
|
|
353
356
|
global.fetch = originalFetch;
|
|
@@ -743,7 +746,7 @@ async function main() {
|
|
|
743
746
|
await testKafkaConsumerTraceUsesConsumeTraceId();
|
|
744
747
|
await testKafkaProducerCapturesFullPublishedMessageValue();
|
|
745
748
|
await testKafkaTraceFlushIsNotBlockedForeverByActiveHttpRequest();
|
|
746
|
-
await
|
|
749
|
+
await testLargeHttpResponseBodyKeepsRequestMetadataWithoutInlineBody();
|
|
747
750
|
await testJsonBuiltinTracePayloadsAreOmitted();
|
|
748
751
|
await testLargeStringTraceValuesStayIngestibleAndCaptureFullValueOutOfBand();
|
|
749
752
|
await testLargeStructuredTraceValuesStayIngestibleAndCaptureFullValueOutOfBand();
|
|
@@ -37,6 +37,10 @@ function main() {
|
|
|
37
37
|
);
|
|
38
38
|
|
|
39
39
|
assert(batches.length > 1, `expected more than one batch, got ${batches.length}`);
|
|
40
|
+
assert(
|
|
41
|
+
batches.length <= 8,
|
|
42
|
+
`expected trace transport to cap batches per request, got ${batches.length}`,
|
|
43
|
+
);
|
|
40
44
|
|
|
41
45
|
batches.forEach((batch, index) => {
|
|
42
46
|
const size = __reproTestHooks.estimateTraceBatchSerializedBytesForTest(
|
|
@@ -51,6 +55,18 @@ function main() {
|
|
|
51
55
|
);
|
|
52
56
|
});
|
|
53
57
|
|
|
58
|
+
const manyEvents = Array.from({ length: 1500 }, (_, index) => makeEvent(index, 'tiny'));
|
|
59
|
+
const cappedBatches = __reproTestHooks.chunkTraceEventsForTransportForTest(
|
|
60
|
+
manyEvents,
|
|
61
|
+
'RID_test_trace_event_cap',
|
|
62
|
+
'A_test_trace_event_cap',
|
|
63
|
+
);
|
|
64
|
+
const cappedEventCount = cappedBatches.reduce((sum, batch) => sum + batch.length, 0);
|
|
65
|
+
assert(
|
|
66
|
+
cappedEventCount <= 1000,
|
|
67
|
+
`expected trace transport to cap events per request, got ${cappedEventCount}`,
|
|
68
|
+
);
|
|
69
|
+
|
|
54
70
|
// eslint-disable-next-line no-console
|
|
55
71
|
console.log('trace batch size chunking OK');
|
|
56
72
|
}
|