@reproapp/node-sdk 0.0.45 → 0.0.47
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 +11 -2
- package/dist/index.js +269 -126
- package/dist/ingest/client.js +11 -0
- package/dist/privacy.d.ts +1 -0
- package/dist/privacy.js +306 -7
- package/package.json +3 -3
- package/src/index.ts +396 -111
- package/src/ingest/client.ts +13 -0
- package/src/privacy.ts +409 -7
- package/test/ingest-high-priority-fairness.test.js +76 -0
- package/test/policy-capture-attestation.test.js +234 -0
- package/test/policy-session-completion.testcontainers.test.js +271 -0
- package/test/privacy-policy-index.test.js +194 -0
- package/test/sdk-background-timeout-isolation.test.js +39 -0
- package/test/trace-batch-size.test.js +4 -0
- package/test/trace-source-exclude.test.js +222 -0
- package/tracer/cjs-hook.js +56 -37
package/src/index.ts
CHANGED
|
@@ -341,6 +341,7 @@ export type TraceEventForFilter = {
|
|
|
341
341
|
fn?: string;
|
|
342
342
|
wrapperClass?: string | null;
|
|
343
343
|
file?: string | null;
|
|
344
|
+
sourceFile?: string | null;
|
|
344
345
|
line?: number | null;
|
|
345
346
|
depth?: number;
|
|
346
347
|
library?: string | null;
|
|
@@ -378,7 +379,11 @@ type PendingTraceEventRecord = TraceEventRecord & {
|
|
|
378
379
|
};
|
|
379
380
|
|
|
380
381
|
type TraceValueCaptureRef = {
|
|
381
|
-
status:
|
|
382
|
+
status:
|
|
383
|
+
| 'stored'
|
|
384
|
+
| 'truncated-for-storage'
|
|
385
|
+
| 'skipped-non-meaningful'
|
|
386
|
+
| 'failed-policy';
|
|
382
387
|
valueId?: string;
|
|
383
388
|
projectedKind?: string;
|
|
384
389
|
};
|
|
@@ -606,6 +611,7 @@ function refreshDisabledFunctionTraceRules() {
|
|
|
606
611
|
let disabledFunctionTraceRules: DisableFunctionTraceConfig[] = computeDisabledFunctionTraceRules();
|
|
607
612
|
let disabledFunctionTypePatterns: Array<string | number | RegExp> = [];
|
|
608
613
|
let disabledTraceFilePatterns: Array<string | number | RegExp> = [];
|
|
614
|
+
let excludedInstrumentationFilePatterns: Array<string | number | RegExp> = [];
|
|
609
615
|
let __TRACE_LOG_PREF: boolean | null = null;
|
|
610
616
|
let __FULL_VALUE_CAPTURE_ENABLED = true;
|
|
611
617
|
|
|
@@ -684,7 +690,7 @@ function matchesRule(rule: DisableFunctionTraceRule, event: TraceEventForFilter)
|
|
|
684
690
|
const wrapperPattern = rule.wrapper ?? rule.wrapperClass ?? rule.className ?? rule.owner;
|
|
685
691
|
if (!matchesPattern(event.wrapperClass, wrapperPattern)) return false;
|
|
686
692
|
|
|
687
|
-
if (!
|
|
693
|
+
if (!matchesTraceFile(event, rule.file)) return false;
|
|
688
694
|
if (!matchesPattern(event.line == null ? null : String(event.line), rule.line)) return false;
|
|
689
695
|
|
|
690
696
|
const libPattern = rule.lib ?? rule.library;
|
|
@@ -699,9 +705,29 @@ function matchesRule(rule: DisableFunctionTraceRule, event: TraceEventForFilter)
|
|
|
699
705
|
return true;
|
|
700
706
|
}
|
|
701
707
|
|
|
708
|
+
function matchesTraceFile(
|
|
709
|
+
event: Pick<TraceEventForFilter, 'file' | 'sourceFile'>,
|
|
710
|
+
pattern?: TraceRulePattern,
|
|
711
|
+
defaultWhenEmpty: boolean = true,
|
|
712
|
+
): boolean {
|
|
713
|
+
if (pattern === undefined || pattern === null) return defaultWhenEmpty;
|
|
714
|
+
const candidates = [event.file, event.sourceFile].filter(
|
|
715
|
+
(value): value is string => typeof value === 'string' && value.length > 0,
|
|
716
|
+
);
|
|
717
|
+
if (!candidates.length) {
|
|
718
|
+
return matchesPattern(null, pattern, defaultWhenEmpty);
|
|
719
|
+
}
|
|
720
|
+
return candidates.some((value) => matchesPattern(value, pattern, false));
|
|
721
|
+
}
|
|
722
|
+
|
|
702
723
|
function shouldDropTraceEvent(event: TraceEventForFilter): boolean {
|
|
703
724
|
if (disabledTraceFilePatterns.length) {
|
|
704
|
-
if (
|
|
725
|
+
if (matchesTraceFile(event, disabledTraceFilePatterns, false)) {
|
|
726
|
+
return true;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (excludedInstrumentationFilePatterns.length) {
|
|
730
|
+
if (matchesTraceFile(event, excludedInstrumentationFilePatterns, false)) {
|
|
705
731
|
return true;
|
|
706
732
|
}
|
|
707
733
|
}
|
|
@@ -948,6 +974,9 @@ export function initReproTracing(opts?: ReproTracingInitOptions) {
|
|
|
948
974
|
if (hasOwn(options, 'disableTraceFiles')) {
|
|
949
975
|
setDisabledTraceFiles(options.disableTraceFiles ?? null);
|
|
950
976
|
}
|
|
977
|
+
if (hasOwn(options, 'exclude')) {
|
|
978
|
+
excludedInstrumentationFilePatterns = normalizePatternArray(options.exclude);
|
|
979
|
+
}
|
|
951
980
|
if (hasOwn(options, 'logFunctionCalls') && typeof options.logFunctionCalls === 'boolean') {
|
|
952
981
|
setReproTraceLogsEnabled(options.logFunctionCalls);
|
|
953
982
|
}
|
|
@@ -971,7 +1000,17 @@ export function initReproTracing(opts?: ReproTracingInitOptions) {
|
|
|
971
1000
|
traceInterceptors: _traceInterceptors,
|
|
972
1001
|
...rest
|
|
973
1002
|
} = options;
|
|
974
|
-
const
|
|
1003
|
+
const defaults = defaultTracerInitOpts();
|
|
1004
|
+
const overrides = rest as TracerInitOpts;
|
|
1005
|
+
const initOpts = {
|
|
1006
|
+
...defaults,
|
|
1007
|
+
...overrides,
|
|
1008
|
+
include: overrides.include ?? defaults.include,
|
|
1009
|
+
exclude: [
|
|
1010
|
+
...(defaults.exclude ?? []),
|
|
1011
|
+
...(overrides.exclude ?? []),
|
|
1012
|
+
],
|
|
1013
|
+
};
|
|
975
1014
|
tracerPkg.init?.(initOpts);
|
|
976
1015
|
tracerPkg.patchHttp?.();
|
|
977
1016
|
applyTraceLogPreference(tracerPkg);
|
|
@@ -1094,6 +1133,7 @@ function traceEventCandidateFromRecord(event: PendingTraceEventRecord): TraceEve
|
|
|
1094
1133
|
fn: event.fn,
|
|
1095
1134
|
wrapperClass: inferWrapperClassFromFn(event.fn),
|
|
1096
1135
|
file: event.file ?? null,
|
|
1136
|
+
sourceFile: sourceFileForLibrary,
|
|
1097
1137
|
line: event.line ?? null,
|
|
1098
1138
|
depth: event.depth,
|
|
1099
1139
|
library: inferLibraryNameFromFile(sourceFileForLibrary ?? event.file),
|
|
@@ -1176,20 +1216,68 @@ type RequestCaptureScopeState = {
|
|
|
1176
1216
|
traceBatchCount: number;
|
|
1177
1217
|
dbChangeCount: number;
|
|
1178
1218
|
emailEventCount: number;
|
|
1219
|
+
captureFailures: Array<{
|
|
1220
|
+
stage: string;
|
|
1221
|
+
target: string;
|
|
1222
|
+
reason: string;
|
|
1223
|
+
}>;
|
|
1224
|
+
privacyMode: 'policy' | 'fallback' | 'raw';
|
|
1225
|
+
privacyPolicyFingerprint?: string;
|
|
1226
|
+
privacyStatementCount: number;
|
|
1179
1227
|
};
|
|
1180
1228
|
|
|
1181
1229
|
function createRequestCaptureScope(
|
|
1182
1230
|
requestRid: string,
|
|
1183
1231
|
transport: RequestCaptureScopeState['transport'],
|
|
1232
|
+
cfg?: ReproMiddlewareConfig,
|
|
1184
1233
|
): RequestCaptureScopeState {
|
|
1234
|
+
const privacy = cfg ? getRuntimePrivacyState(cfg).policy ?? null : null;
|
|
1235
|
+
const privacyMode =
|
|
1236
|
+
cfg && shouldCapturePrivacyRaw(cfg)
|
|
1237
|
+
? 'raw'
|
|
1238
|
+
: privacy
|
|
1239
|
+
? 'policy'
|
|
1240
|
+
: 'fallback';
|
|
1185
1241
|
return {
|
|
1186
1242
|
requestRid,
|
|
1187
1243
|
transport,
|
|
1188
|
-
|
|
1244
|
+
// Every scope represents one captured transport request. This is an
|
|
1245
|
+
// observed expectation, not a count of successful enqueue operations.
|
|
1246
|
+
backendRequestCount: 1,
|
|
1189
1247
|
traceBatchCount: 0,
|
|
1190
1248
|
dbChangeCount: 0,
|
|
1191
1249
|
emailEventCount: 0,
|
|
1250
|
+
captureFailures: [],
|
|
1251
|
+
privacyMode,
|
|
1252
|
+
privacyPolicyFingerprint: privacy?.fingerprint,
|
|
1253
|
+
privacyStatementCount: privacy?.statements.length ?? 0,
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
function recordRequestCaptureFailure(
|
|
1258
|
+
scope: RequestCaptureScopeState | null | undefined,
|
|
1259
|
+
stage: string,
|
|
1260
|
+
target: string,
|
|
1261
|
+
reason: string,
|
|
1262
|
+
): void {
|
|
1263
|
+
if (!scope) return;
|
|
1264
|
+
const normalized = {
|
|
1265
|
+
stage: String(stage || 'capture').slice(0, 80),
|
|
1266
|
+
target: String(target || 'unknown').slice(0, 120),
|
|
1267
|
+
reason: String(reason || 'capture_failed').slice(0, 120),
|
|
1192
1268
|
};
|
|
1269
|
+
if (
|
|
1270
|
+
scope.captureFailures.some((failure) =>
|
|
1271
|
+
failure.stage === normalized.stage &&
|
|
1272
|
+
failure.target === normalized.target &&
|
|
1273
|
+
failure.reason === normalized.reason,
|
|
1274
|
+
)
|
|
1275
|
+
) {
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
if (scope.captureFailures.length < 25) {
|
|
1279
|
+
scope.captureFailures.push(normalized);
|
|
1280
|
+
}
|
|
1193
1281
|
}
|
|
1194
1282
|
|
|
1195
1283
|
function buildRequestCaptureManifestPayload(
|
|
@@ -1219,6 +1307,20 @@ function buildRequestCaptureManifestPayload(
|
|
|
1219
1307
|
to: expectedTraceBatches - 1,
|
|
1220
1308
|
}
|
|
1221
1309
|
: undefined,
|
|
1310
|
+
privacy: {
|
|
1311
|
+
mode: scope.privacyMode,
|
|
1312
|
+
status:
|
|
1313
|
+
scope.captureFailures.length > 0
|
|
1314
|
+
? 'failed'
|
|
1315
|
+
: scope.privacyMode === 'raw'
|
|
1316
|
+
? 'bypassed'
|
|
1317
|
+
: 'applied',
|
|
1318
|
+
policyFingerprint: scope.privacyPolicyFingerprint,
|
|
1319
|
+
statementCount: scope.privacyStatementCount,
|
|
1320
|
+
},
|
|
1321
|
+
captureFailures: scope.captureFailures.length
|
|
1322
|
+
? scope.captureFailures.map((failure) => ({ ...failure }))
|
|
1323
|
+
: undefined,
|
|
1222
1324
|
closedAt,
|
|
1223
1325
|
};
|
|
1224
1326
|
}
|
|
@@ -1403,12 +1505,6 @@ const SDK_BACKGROUND_MAX_DEFER_MS = (() => {
|
|
|
1403
1505
|
return Number.POSITIVE_INFINITY;
|
|
1404
1506
|
})();
|
|
1405
1507
|
|
|
1406
|
-
const SDK_BACKGROUND_WORK_TIMEOUT_MS = (() => {
|
|
1407
|
-
const env = Number(process.env.REPRO_SDK_BACKGROUND_WORK_TIMEOUT_MS);
|
|
1408
|
-
if (Number.isFinite(env) && env >= 0) return Math.trunc(env);
|
|
1409
|
-
return 20000;
|
|
1410
|
-
})();
|
|
1411
|
-
|
|
1412
1508
|
const TRACE_MATERIALIZE_OFFTHREAD_ENABLED = (() => {
|
|
1413
1509
|
const env = String(process.env.REPRO_TRACE_MATERIALIZE_OFFTHREAD || '').trim().toLowerCase();
|
|
1414
1510
|
if (!env) return true;
|
|
@@ -1738,24 +1834,9 @@ function scheduleSdkBackgroundDrain(delayMs = 0): void {
|
|
|
1738
1834
|
}
|
|
1739
1835
|
|
|
1740
1836
|
async function runSdkBackgroundWork(work: () => Promise<void> | void): Promise<void> {
|
|
1741
|
-
|
|
1742
|
-
await work();
|
|
1743
|
-
return;
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
let timeout: NodeJS.Timeout | null = null;
|
|
1747
|
-
const workPromise = Promise.resolve()
|
|
1837
|
+
await Promise.resolve()
|
|
1748
1838
|
.then(work)
|
|
1749
1839
|
.catch(() => undefined);
|
|
1750
|
-
const timeoutPromise = new Promise<void>((resolve) => {
|
|
1751
|
-
timeout = setTimeout(resolve, SDK_BACKGROUND_WORK_TIMEOUT_MS);
|
|
1752
|
-
try { (timeout as any).unref?.(); } catch {}
|
|
1753
|
-
});
|
|
1754
|
-
|
|
1755
|
-
await Promise.race([workPromise, timeoutPromise]);
|
|
1756
|
-
if (timeout) {
|
|
1757
|
-
try { clearTimeout(timeout); } catch {}
|
|
1758
|
-
}
|
|
1759
1840
|
}
|
|
1760
1841
|
|
|
1761
1842
|
async function drainQueuedIngestBeforeBackgroundWork(): Promise<void> {
|
|
@@ -2747,7 +2828,7 @@ const TRACE_MAX_EVENTS_PER_REQUEST = (() => {
|
|
|
2747
2828
|
const TRACE_MAX_BATCHES_PER_REQUEST = (() => {
|
|
2748
2829
|
const env = Number(process.env.REPRO_TRACE_MAX_BATCHES_PER_REQUEST);
|
|
2749
2830
|
if (Number.isFinite(env) && env > 0) return Math.trunc(env);
|
|
2750
|
-
return
|
|
2831
|
+
return Math.ceil(TRACE_MAX_EVENTS_PER_REQUEST / TRACE_BATCH_SIZE);
|
|
2751
2832
|
})();
|
|
2752
2833
|
const TRACE_FLUSH_DELAY_MS = 20;
|
|
2753
2834
|
// Choose how to order trace events in payloads.
|
|
@@ -3321,6 +3402,7 @@ async function materializePendingTraceEvents(
|
|
|
3321
3402
|
maskReq: MaskRequestContext;
|
|
3322
3403
|
masking: NormalizedMaskingConfig | null;
|
|
3323
3404
|
resolvePrivacy: () => NormalizedRuntimePrivacyPolicy | null;
|
|
3405
|
+
captureScope?: RequestCaptureScopeState | null;
|
|
3324
3406
|
},
|
|
3325
3407
|
): Promise<TraceEventRecord[]> {
|
|
3326
3408
|
for (const evt of events) {
|
|
@@ -3367,7 +3449,7 @@ async function materializePendingTraceEvents(
|
|
|
3367
3449
|
previewValue: evt.args,
|
|
3368
3450
|
capture: captureContext,
|
|
3369
3451
|
metadata: traceValueMetadata,
|
|
3370
|
-
});
|
|
3452
|
+
}, params.captureScope);
|
|
3371
3453
|
if (argsValueCapture?.entry) {
|
|
3372
3454
|
attachTraceValueEntry(evt, argsValueCapture.entry);
|
|
3373
3455
|
}
|
|
@@ -3396,7 +3478,7 @@ async function materializePendingTraceEvents(
|
|
|
3396
3478
|
previewValue: evt.returnValue,
|
|
3397
3479
|
capture: captureContext,
|
|
3398
3480
|
metadata: traceValueMetadata,
|
|
3399
|
-
});
|
|
3481
|
+
}, params.captureScope);
|
|
3400
3482
|
if (returnValueCapture?.entry) {
|
|
3401
3483
|
attachTraceValueEntry(evt, returnValueCapture.entry);
|
|
3402
3484
|
}
|
|
@@ -3425,7 +3507,7 @@ async function materializePendingTraceEvents(
|
|
|
3425
3507
|
previewValue: evt.error,
|
|
3426
3508
|
capture: captureContext,
|
|
3427
3509
|
metadata: traceValueMetadata,
|
|
3428
|
-
});
|
|
3510
|
+
}, params.captureScope);
|
|
3429
3511
|
if (errorValueCapture?.entry) {
|
|
3430
3512
|
attachTraceValueEntry(evt, errorValueCapture.entry);
|
|
3431
3513
|
}
|
|
@@ -3443,7 +3525,20 @@ function stripPendingTraceValues(
|
|
|
3443
3525
|
reason: string,
|
|
3444
3526
|
): TraceEventRecord[] {
|
|
3445
3527
|
for (const evt of events) {
|
|
3446
|
-
|
|
3528
|
+
const pending = evt.__reproPending;
|
|
3529
|
+
if (!pending) continue;
|
|
3530
|
+
if (pending.argsRaw !== undefined) {
|
|
3531
|
+
evt.args = makeOmittedValue(reason);
|
|
3532
|
+
evt.argsValueCapture = { status: 'failed-policy' };
|
|
3533
|
+
}
|
|
3534
|
+
if (pending.returnValueRaw !== undefined) {
|
|
3535
|
+
evt.returnValue = makeOmittedValue(reason);
|
|
3536
|
+
evt.returnValueCapture = { status: 'failed-policy' };
|
|
3537
|
+
}
|
|
3538
|
+
if (pending.errorRaw !== undefined) {
|
|
3539
|
+
evt.error = makeOmittedValue(reason);
|
|
3540
|
+
evt.errorValueCapture = { status: 'failed-policy' };
|
|
3541
|
+
}
|
|
3447
3542
|
delete evt.__reproPending;
|
|
3448
3543
|
}
|
|
3449
3544
|
return events;
|
|
@@ -3460,6 +3555,7 @@ async function materializePendingTraceEventsAsync(
|
|
|
3460
3555
|
maskReq: MaskRequestContext;
|
|
3461
3556
|
masking: NormalizedMaskingConfig | null;
|
|
3462
3557
|
resolvePrivacy: () => NormalizedRuntimePrivacyPolicy | null;
|
|
3558
|
+
captureScope?: RequestCaptureScopeState | null;
|
|
3463
3559
|
},
|
|
3464
3560
|
): Promise<TraceEventRecord[]> {
|
|
3465
3561
|
if (!events.some((evt) => evt.__reproPending)) {
|
|
@@ -3474,6 +3570,12 @@ async function materializePendingTraceEventsAsync(
|
|
|
3474
3570
|
resolvePrivacy: () => privacy,
|
|
3475
3571
|
});
|
|
3476
3572
|
} catch {
|
|
3573
|
+
recordRequestCaptureFailure(
|
|
3574
|
+
params.captureScope ?? getCtx().captureScope,
|
|
3575
|
+
'privacy.trace',
|
|
3576
|
+
'trace.values',
|
|
3577
|
+
'main_thread_materialization_failed',
|
|
3578
|
+
);
|
|
3477
3579
|
return stripPendingTraceValues(events, 'main_thread_failed');
|
|
3478
3580
|
}
|
|
3479
3581
|
}
|
|
@@ -3492,16 +3594,24 @@ async function materializePendingTraceEventsAsync(
|
|
|
3492
3594
|
fullValueCaptureEnabled: __FULL_VALUE_CAPTURE_ENABLED,
|
|
3493
3595
|
});
|
|
3494
3596
|
} catch (err) {
|
|
3495
|
-
if (isTraceMaterializerTimeoutError(err)) {
|
|
3496
|
-
return stripPendingTraceValues(events, 'worker_timeout');
|
|
3497
|
-
}
|
|
3498
3597
|
try {
|
|
3499
3598
|
return await materializePendingTraceEvents(events, {
|
|
3500
3599
|
...params,
|
|
3501
3600
|
resolvePrivacy: () => privacy,
|
|
3502
3601
|
});
|
|
3503
3602
|
} catch {
|
|
3504
|
-
|
|
3603
|
+
recordRequestCaptureFailure(
|
|
3604
|
+
params.captureScope ?? getCtx().captureScope,
|
|
3605
|
+
'privacy.trace',
|
|
3606
|
+
'trace.values',
|
|
3607
|
+
isTraceMaterializerTimeoutError(err)
|
|
3608
|
+
? 'worker_timeout_fallback_failed'
|
|
3609
|
+
: 'worker_and_fallback_failed',
|
|
3610
|
+
);
|
|
3611
|
+
return stripPendingTraceValues(
|
|
3612
|
+
events,
|
|
3613
|
+
isTraceMaterializerTimeoutError(err) ? 'worker_timeout_fallback_failed' : 'worker_failed',
|
|
3614
|
+
);
|
|
3505
3615
|
}
|
|
3506
3616
|
}
|
|
3507
3617
|
}
|
|
@@ -4101,6 +4211,7 @@ function materializeInlinePrivacyValue(
|
|
|
4101
4211
|
masking: NormalizedMaskingConfig | null,
|
|
4102
4212
|
privacy: NormalizedRuntimePrivacyPolicy | null,
|
|
4103
4213
|
db?: RuntimePrivacyDbContext | null,
|
|
4214
|
+
captureScope?: RequestCaptureScopeState | null,
|
|
4104
4215
|
): InlinePrivacyMaterializationResult {
|
|
4105
4216
|
if (value === undefined) {
|
|
4106
4217
|
return { value };
|
|
@@ -4113,6 +4224,12 @@ function materializeInlinePrivacyValue(
|
|
|
4113
4224
|
const valueAfterPrivacy = applyPrivacyThenMask(target, value, cfg, req, trace, masking, privacy, db);
|
|
4114
4225
|
return { value: valueAfterPrivacy };
|
|
4115
4226
|
} catch {
|
|
4227
|
+
recordRequestCaptureFailure(
|
|
4228
|
+
captureScope ?? getCtx().captureScope,
|
|
4229
|
+
'privacy.inline',
|
|
4230
|
+
target,
|
|
4231
|
+
'privacy_transform_failed',
|
|
4232
|
+
);
|
|
4116
4233
|
return {
|
|
4117
4234
|
value: undefined,
|
|
4118
4235
|
skipped: {
|
|
@@ -4133,6 +4250,7 @@ async function materializeInlinePrivacyValueAsync(
|
|
|
4133
4250
|
masking: NormalizedMaskingConfig | null,
|
|
4134
4251
|
privacy: NormalizedRuntimePrivacyPolicy | null,
|
|
4135
4252
|
db?: RuntimePrivacyDbContext | null,
|
|
4253
|
+
captureScope?: RequestCaptureScopeState | null,
|
|
4136
4254
|
): Promise<InlinePrivacyMaterializationResult> {
|
|
4137
4255
|
if (value === undefined) {
|
|
4138
4256
|
return { value };
|
|
@@ -4145,6 +4263,12 @@ async function materializeInlinePrivacyValueAsync(
|
|
|
4145
4263
|
const valueAfterPrivacy = await applyPrivacyThenMaskAsync(target, value, cfg, req, trace, masking, privacy, db);
|
|
4146
4264
|
return { value: valueAfterPrivacy };
|
|
4147
4265
|
} catch {
|
|
4266
|
+
recordRequestCaptureFailure(
|
|
4267
|
+
captureScope ?? getCtx().captureScope,
|
|
4268
|
+
'privacy.inline',
|
|
4269
|
+
target,
|
|
4270
|
+
'privacy_transform_failed',
|
|
4271
|
+
);
|
|
4148
4272
|
return {
|
|
4149
4273
|
value: undefined,
|
|
4150
4274
|
skipped: {
|
|
@@ -5149,6 +5273,13 @@ function chunkTraceEventsForTransport(
|
|
|
5149
5273
|
if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
|
|
5150
5274
|
break;
|
|
5151
5275
|
}
|
|
5276
|
+
if (current.length >= TRACE_BATCH_SIZE) {
|
|
5277
|
+
sizedBatches.push(current);
|
|
5278
|
+
current = [];
|
|
5279
|
+
if (sizedBatches.length >= TRACE_MAX_BATCHES_PER_REQUEST) {
|
|
5280
|
+
break;
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5152
5283
|
const candidate = current.concat(event);
|
|
5153
5284
|
const batchIndex = sizedBatches.length;
|
|
5154
5285
|
const estimatedBytes = estimateTraceBatchSerializedBytes(
|
|
@@ -5380,8 +5511,20 @@ async function maybeCaptureRequestValueAsync(
|
|
|
5380
5511
|
capture: FullValueCaptureContext;
|
|
5381
5512
|
},
|
|
5382
5513
|
sink: TraceValueBatchEntry[],
|
|
5514
|
+
captureScope?: RequestCaptureScopeState | null,
|
|
5383
5515
|
): Promise<TraceValueCaptureRef | undefined> {
|
|
5384
|
-
|
|
5516
|
+
let result: Awaited<ReturnType<typeof createCapturedValueEntryAsync>>;
|
|
5517
|
+
try {
|
|
5518
|
+
result = await createCapturedValueEntryAsync(params);
|
|
5519
|
+
} catch {
|
|
5520
|
+
recordRequestCaptureFailure(
|
|
5521
|
+
captureScope ?? getCtx().captureScope,
|
|
5522
|
+
'privacy.full_value',
|
|
5523
|
+
params.target,
|
|
5524
|
+
'privacy_transform_failed',
|
|
5525
|
+
);
|
|
5526
|
+
return { status: 'failed-policy' };
|
|
5527
|
+
}
|
|
5385
5528
|
if (!result) return undefined;
|
|
5386
5529
|
if (result.entry) {
|
|
5387
5530
|
sink.push(result.entry);
|
|
@@ -5409,8 +5552,19 @@ async function maybeCaptureTraceValueAsync(
|
|
|
5409
5552
|
capture: FullValueCaptureContext;
|
|
5410
5553
|
metadata?: Partial<TraceValueBatchEntry>;
|
|
5411
5554
|
},
|
|
5555
|
+
captureScope?: RequestCaptureScopeState | null,
|
|
5412
5556
|
): Promise<{ captureRef: TraceValueCaptureRef; entry?: TraceValueBatchEntry } | undefined> {
|
|
5413
|
-
|
|
5557
|
+
try {
|
|
5558
|
+
return await createCapturedValueEntryAsync(params);
|
|
5559
|
+
} catch {
|
|
5560
|
+
recordRequestCaptureFailure(
|
|
5561
|
+
captureScope ?? getCtx().captureScope,
|
|
5562
|
+
'privacy.full_value',
|
|
5563
|
+
params.target,
|
|
5564
|
+
'privacy_transform_failed',
|
|
5565
|
+
);
|
|
5566
|
+
return { captureRef: { status: 'failed-policy' } };
|
|
5567
|
+
}
|
|
5414
5568
|
}
|
|
5415
5569
|
|
|
5416
5570
|
function maybeCaptureDbValue(
|
|
@@ -5438,8 +5592,20 @@ async function maybeCaptureDbValueAsync(
|
|
|
5438
5592
|
capture: FullValueCaptureContext;
|
|
5439
5593
|
},
|
|
5440
5594
|
sink: TraceValueBatchEntry[],
|
|
5595
|
+
captureScope?: RequestCaptureScopeState | null,
|
|
5441
5596
|
): Promise<TraceValueCaptureRef | undefined> {
|
|
5442
|
-
|
|
5597
|
+
let result: Awaited<ReturnType<typeof createCapturedValueEntryAsync>>;
|
|
5598
|
+
try {
|
|
5599
|
+
result = await createCapturedValueEntryAsync(params);
|
|
5600
|
+
} catch {
|
|
5601
|
+
recordRequestCaptureFailure(
|
|
5602
|
+
captureScope ?? getCtx().captureScope,
|
|
5603
|
+
'privacy.full_value',
|
|
5604
|
+
params.target,
|
|
5605
|
+
'privacy_transform_failed',
|
|
5606
|
+
);
|
|
5607
|
+
return { status: 'failed-policy' };
|
|
5608
|
+
}
|
|
5443
5609
|
if (!result) return undefined;
|
|
5444
5610
|
if (result.entry) {
|
|
5445
5611
|
sink.push(result.entry);
|
|
@@ -5475,15 +5641,27 @@ async function maybeCaptureDbValueFromCandidatesAsync(
|
|
|
5475
5641
|
capture: FullValueCaptureContext;
|
|
5476
5642
|
},
|
|
5477
5643
|
sink: TraceValueBatchEntry[],
|
|
5644
|
+
captureScope?: RequestCaptureScopeState | null,
|
|
5478
5645
|
): Promise<TraceValueCaptureRef | undefined> {
|
|
5479
5646
|
let skippedRef: TraceValueCaptureRef | undefined;
|
|
5480
5647
|
for (const rawValue of params.rawValues) {
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5648
|
+
let result: Awaited<ReturnType<typeof createCapturedValueEntryAsync>>;
|
|
5649
|
+
try {
|
|
5650
|
+
result = await createCapturedValueEntryAsync({
|
|
5651
|
+
target: params.target,
|
|
5652
|
+
rawValue,
|
|
5653
|
+
previewValue: params.previewValue,
|
|
5654
|
+
capture: params.capture,
|
|
5655
|
+
});
|
|
5656
|
+
} catch {
|
|
5657
|
+
recordRequestCaptureFailure(
|
|
5658
|
+
captureScope ?? getCtx().captureScope,
|
|
5659
|
+
'privacy.full_value',
|
|
5660
|
+
params.target,
|
|
5661
|
+
'privacy_transform_failed',
|
|
5662
|
+
);
|
|
5663
|
+
return { status: 'failed-policy' };
|
|
5664
|
+
}
|
|
5487
5665
|
if (!result) continue;
|
|
5488
5666
|
if (result.entry) {
|
|
5489
5667
|
sink.push(result.entry);
|
|
@@ -5791,7 +5969,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
5791
5969
|
|
|
5792
5970
|
const clockSkewMs = headerTs !== null ? headerTs - requestStartRaw : 0;
|
|
5793
5971
|
const rid = nextRequestId(requestEpochMs);
|
|
5794
|
-
const captureScope = createRequestCaptureScope(rid, 'http');
|
|
5972
|
+
const captureScope = createRequestCaptureScope(rid, 'http', captureCfg);
|
|
5795
5973
|
emitRequestCaptureStart(captureCfg, sid, aid, captureScope, requestEpochMs);
|
|
5796
5974
|
const t0 = requestStartRaw;
|
|
5797
5975
|
const url = (req as any).originalUrl || req.url || '/';
|
|
@@ -5993,9 +6171,11 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
5993
6171
|
endpointTraceCtx,
|
|
5994
6172
|
masking,
|
|
5995
6173
|
activePrivacy,
|
|
6174
|
+
undefined,
|
|
6175
|
+
captureScope,
|
|
5996
6176
|
);
|
|
5997
6177
|
const requestBody = requestBodyMaterialization.value;
|
|
5998
|
-
const
|
|
6178
|
+
const requestParamsMaterialization = await materializeInlinePrivacyValueAsync(
|
|
5999
6179
|
'request.params',
|
|
6000
6180
|
sanitizeRequestSnapshot((req as any).params),
|
|
6001
6181
|
captureCfg,
|
|
@@ -6003,8 +6183,11 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6003
6183
|
endpointTraceCtx,
|
|
6004
6184
|
masking,
|
|
6005
6185
|
activePrivacy,
|
|
6186
|
+
undefined,
|
|
6187
|
+
captureScope,
|
|
6006
6188
|
);
|
|
6007
|
-
const
|
|
6189
|
+
const requestParams = requestParamsMaterialization.value;
|
|
6190
|
+
const requestQueryMaterialization = await materializeInlinePrivacyValueAsync(
|
|
6008
6191
|
'request.query',
|
|
6009
6192
|
sanitizeRequestSnapshot((req as any).query),
|
|
6010
6193
|
captureCfg,
|
|
@@ -6012,8 +6195,11 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6012
6195
|
endpointTraceCtx,
|
|
6013
6196
|
masking,
|
|
6014
6197
|
activePrivacy,
|
|
6198
|
+
undefined,
|
|
6199
|
+
captureScope,
|
|
6015
6200
|
);
|
|
6016
|
-
const
|
|
6201
|
+
const requestQuery = requestQueryMaterialization.value;
|
|
6202
|
+
const requestHeadersMaterialization = await materializeInlinePrivacyValueAsync(
|
|
6017
6203
|
'request.headers',
|
|
6018
6204
|
requestHeaders,
|
|
6019
6205
|
captureCfg,
|
|
@@ -6021,7 +6207,10 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6021
6207
|
endpointTraceCtx,
|
|
6022
6208
|
masking,
|
|
6023
6209
|
activePrivacy,
|
|
6210
|
+
undefined,
|
|
6211
|
+
captureScope,
|
|
6024
6212
|
);
|
|
6213
|
+
const maskedHeaders = requestHeadersMaterialization.value;
|
|
6025
6214
|
const responseBodyMaterialization = capturedBody === undefined
|
|
6026
6215
|
? { value: undefined }
|
|
6027
6216
|
: limitRawInlinePrivacyValue('response.body', capturedBody)
|
|
@@ -6033,6 +6222,8 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6033
6222
|
endpointTraceCtx,
|
|
6034
6223
|
masking,
|
|
6035
6224
|
activePrivacy,
|
|
6225
|
+
undefined,
|
|
6226
|
+
captureScope,
|
|
6036
6227
|
);
|
|
6037
6228
|
const responseBody = responseBodyMaterialization.value;
|
|
6038
6229
|
const requestValueEntries: TraceValueBatchEntry[] = [];
|
|
@@ -6050,7 +6241,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6050
6241
|
masking,
|
|
6051
6242
|
privacy: activePrivacy,
|
|
6052
6243
|
},
|
|
6053
|
-
}, requestValueEntries);
|
|
6244
|
+
}, requestValueEntries, captureScope);
|
|
6054
6245
|
const paramsValueCapture = await maybeCaptureRequestValueAsync({
|
|
6055
6246
|
target: 'request.params',
|
|
6056
6247
|
rawValue: (req as any).params,
|
|
@@ -6063,7 +6254,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6063
6254
|
masking,
|
|
6064
6255
|
privacy: activePrivacy,
|
|
6065
6256
|
},
|
|
6066
|
-
}, requestValueEntries);
|
|
6257
|
+
}, requestValueEntries, captureScope);
|
|
6067
6258
|
const queryValueCapture = await maybeCaptureRequestValueAsync({
|
|
6068
6259
|
target: 'request.query',
|
|
6069
6260
|
rawValue: (req as any).query,
|
|
@@ -6076,7 +6267,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6076
6267
|
masking,
|
|
6077
6268
|
privacy: activePrivacy,
|
|
6078
6269
|
},
|
|
6079
|
-
}, requestValueEntries);
|
|
6270
|
+
}, requestValueEntries, captureScope);
|
|
6080
6271
|
const headersValueCapture = await maybeCaptureRequestValueAsync({
|
|
6081
6272
|
target: 'request.headers',
|
|
6082
6273
|
rawValue: req.headers,
|
|
@@ -6089,7 +6280,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6089
6280
|
masking,
|
|
6090
6281
|
privacy: activePrivacy,
|
|
6091
6282
|
},
|
|
6092
|
-
}, requestValueEntries);
|
|
6283
|
+
}, requestValueEntries, captureScope);
|
|
6093
6284
|
const respBodyValueCapture = capturedBody === undefined
|
|
6094
6285
|
? undefined
|
|
6095
6286
|
: await maybeCaptureRequestValueAsync({
|
|
@@ -6104,7 +6295,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6104
6295
|
masking,
|
|
6105
6296
|
privacy: activePrivacy,
|
|
6106
6297
|
},
|
|
6107
|
-
}, requestValueEntries);
|
|
6298
|
+
}, requestValueEntries, captureScope);
|
|
6108
6299
|
|
|
6109
6300
|
const responseDurationMs =
|
|
6110
6301
|
finishedAt !== null && Number.isFinite(finishedAt)
|
|
@@ -6165,9 +6356,43 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6165
6356
|
t: requestEpochMs,
|
|
6166
6357
|
}]
|
|
6167
6358
|
});
|
|
6168
|
-
captureScope.backendRequestCount += 1;
|
|
6169
6359
|
} catch {
|
|
6170
|
-
|
|
6360
|
+
recordRequestCaptureFailure(
|
|
6361
|
+
captureScope,
|
|
6362
|
+
'request.capture',
|
|
6363
|
+
'backend_request',
|
|
6364
|
+
'request_materialization_failed',
|
|
6365
|
+
);
|
|
6366
|
+
// Preserve non-sensitive request metadata so the manifest cannot
|
|
6367
|
+
// silently turn a failed policy capture into a zero-request scope.
|
|
6368
|
+
post(captureCfg, sid, {
|
|
6369
|
+
entries: [{
|
|
6370
|
+
actionId: aid,
|
|
6371
|
+
request: {
|
|
6372
|
+
rid,
|
|
6373
|
+
method: req.method,
|
|
6374
|
+
url,
|
|
6375
|
+
path,
|
|
6376
|
+
status: res.statusCode,
|
|
6377
|
+
durMs:
|
|
6378
|
+
finishedAt !== null && Number.isFinite(finishedAt)
|
|
6379
|
+
? Math.max(0, finishedAt - t0)
|
|
6380
|
+
: Date.now() - t0,
|
|
6381
|
+
key,
|
|
6382
|
+
bodyMaterialization: {
|
|
6383
|
+
status: 'skipped',
|
|
6384
|
+
reason: 'request_materialization_failed',
|
|
6385
|
+
target: 'request.body',
|
|
6386
|
+
},
|
|
6387
|
+
respBodyMaterialization: {
|
|
6388
|
+
status: 'skipped',
|
|
6389
|
+
reason: 'request_materialization_failed',
|
|
6390
|
+
target: 'response.body',
|
|
6391
|
+
},
|
|
6392
|
+
},
|
|
6393
|
+
t: requestEpochMs,
|
|
6394
|
+
}],
|
|
6395
|
+
});
|
|
6171
6396
|
}
|
|
6172
6397
|
};
|
|
6173
6398
|
|
|
@@ -6290,6 +6515,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6290
6515
|
maskReq,
|
|
6291
6516
|
masking,
|
|
6292
6517
|
resolvePrivacy,
|
|
6518
|
+
captureScope,
|
|
6293
6519
|
});
|
|
6294
6520
|
const baseEvents = balanceTraceEvents(materializedEvents.slice());
|
|
6295
6521
|
const orderedEvents = TRACE_ORDER_MODE === 'tree'
|
|
@@ -6308,12 +6534,21 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6308
6534
|
}
|
|
6309
6535
|
|
|
6310
6536
|
} catch {
|
|
6537
|
+
recordRequestCaptureFailure(
|
|
6538
|
+
captureScope,
|
|
6539
|
+
'trace.capture',
|
|
6540
|
+
'trace.batches',
|
|
6541
|
+
'trace_capture_failed',
|
|
6542
|
+
);
|
|
6311
6543
|
captureScope.traceBatchCount = 0;
|
|
6312
6544
|
traceBatches = [];
|
|
6313
|
-
} finally {
|
|
6314
|
-
emitRequestCaptureManifest(traceBatches.length);
|
|
6315
6545
|
}
|
|
6316
6546
|
|
|
6547
|
+
// Finalize policy/materialization status before publishing the
|
|
6548
|
+
// high-priority manifest. The manifest must lead its evidence
|
|
6549
|
+
// on the wire so a large trace queue cannot starve completion.
|
|
6550
|
+
emitRequestCaptureManifest(traceBatches.length);
|
|
6551
|
+
|
|
6317
6552
|
try {
|
|
6318
6553
|
for (let i = 0; i < traceBatches.length; i++) {
|
|
6319
6554
|
const batch = traceBatches[i];
|
|
@@ -6334,7 +6569,12 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
6334
6569
|
});
|
|
6335
6570
|
}
|
|
6336
6571
|
} catch {
|
|
6337
|
-
|
|
6572
|
+
recordRequestCaptureFailure(
|
|
6573
|
+
captureScope,
|
|
6574
|
+
'trace.enqueue',
|
|
6575
|
+
'trace.batches',
|
|
6576
|
+
'trace_enqueue_failed',
|
|
6577
|
+
);
|
|
6338
6578
|
}
|
|
6339
6579
|
};
|
|
6340
6580
|
}
|
|
@@ -6935,6 +7175,11 @@ function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
|
|
|
6935
7175
|
const ctx = getCtx() as Ctx;
|
|
6936
7176
|
const spanContext = payload?.spanContext ?? captureSpanContextFromTracer();
|
|
6937
7177
|
if (!shouldCaptureDbSpan(spanContext)) return;
|
|
7178
|
+
if (sid && ctx.captureScope) {
|
|
7179
|
+
// Count the observed database operation before asynchronous privacy
|
|
7180
|
+
// materialization. A later failure must remain visible to completeness.
|
|
7181
|
+
ctx.captureScope.dbChangeCount += 1;
|
|
7182
|
+
}
|
|
6938
7183
|
const runCtx: Ctx = {
|
|
6939
7184
|
sid: ctx.sid,
|
|
6940
7185
|
aid: ctx.aid,
|
|
@@ -6946,7 +7191,14 @@ function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
|
|
|
6946
7191
|
};
|
|
6947
7192
|
scheduleSdkBackgroundWork(async () => {
|
|
6948
7193
|
await als.run(runCtx, async () => {
|
|
6949
|
-
await emitDbQueryAsync(cfg, sid, aid, payload).catch(() =>
|
|
7194
|
+
await emitDbQueryAsync(cfg, sid, aid, payload).catch(() => {
|
|
7195
|
+
recordRequestCaptureFailure(
|
|
7196
|
+
runCtx.captureScope,
|
|
7197
|
+
'db.capture',
|
|
7198
|
+
'db.change',
|
|
7199
|
+
'db_capture_failed',
|
|
7200
|
+
);
|
|
7201
|
+
});
|
|
6950
7202
|
});
|
|
6951
7203
|
}, { priority: 'high' });
|
|
6952
7204
|
}
|
|
@@ -7061,8 +7313,13 @@ async function emitDbQueryAsync(cfg: any, sid?: string, aid?: string, payload?:
|
|
|
7061
7313
|
t: payload.t,
|
|
7062
7314
|
}]
|
|
7063
7315
|
});
|
|
7064
|
-
if (enqueued
|
|
7065
|
-
|
|
7316
|
+
if (!enqueued) {
|
|
7317
|
+
recordRequestCaptureFailure(
|
|
7318
|
+
ctx.captureScope,
|
|
7319
|
+
'db.enqueue',
|
|
7320
|
+
'db.change',
|
|
7321
|
+
'db_enqueue_failed',
|
|
7322
|
+
);
|
|
7066
7323
|
}
|
|
7067
7324
|
}
|
|
7068
7325
|
|
|
@@ -7498,6 +7755,7 @@ async function materializeKafkaRequestBody(
|
|
|
7498
7755
|
cfg: ReproMiddlewareConfig,
|
|
7499
7756
|
maskReq: MaskRequestContext,
|
|
7500
7757
|
body: Record<string, any>,
|
|
7758
|
+
captureScope?: RequestCaptureScopeState | null,
|
|
7501
7759
|
): Promise<InlinePrivacyMaterializationResult> {
|
|
7502
7760
|
return materializeInlinePrivacyValueAsync(
|
|
7503
7761
|
'request.body',
|
|
@@ -7507,6 +7765,8 @@ async function materializeKafkaRequestBody(
|
|
|
7507
7765
|
null,
|
|
7508
7766
|
normalizeMaskingConfig(cfg.masking),
|
|
7509
7767
|
getRuntimePrivacyState(cfg).policy ?? null,
|
|
7768
|
+
undefined,
|
|
7769
|
+
captureScope,
|
|
7510
7770
|
);
|
|
7511
7771
|
}
|
|
7512
7772
|
|
|
@@ -7595,6 +7855,7 @@ function recordKafkaTraceEvent(
|
|
|
7595
7855
|
fn: raw.fn,
|
|
7596
7856
|
wrapperClass: inferWrapperClassFromFn(raw.fn),
|
|
7597
7857
|
file: raw.file ?? null,
|
|
7858
|
+
sourceFile: sourceFileForLibrary,
|
|
7598
7859
|
line: typeof raw.line === 'number' ? raw.line : null,
|
|
7599
7860
|
depth: typeof raw.depth === 'number' ? raw.depth : undefined,
|
|
7600
7861
|
library: inferLibraryNameFromFile(sourceFileForLibrary ?? raw.file),
|
|
@@ -7727,6 +7988,7 @@ function buildPendingKafkaTraceEvent(raw: any): PendingTraceEventRecord | null {
|
|
|
7727
7988
|
fn: raw.fn,
|
|
7728
7989
|
wrapperClass: inferWrapperClassFromFn(raw.fn),
|
|
7729
7990
|
file: raw.file ?? null,
|
|
7991
|
+
sourceFile: sourceFileForLibrary,
|
|
7730
7992
|
line: typeof raw.line === 'number' ? raw.line : null,
|
|
7731
7993
|
depth: typeof raw.depth === 'number' ? raw.depth : undefined,
|
|
7732
7994
|
library: inferLibraryNameFromFile(sourceFileForLibrary ?? raw.file),
|
|
@@ -7844,22 +8106,31 @@ function scheduleKafkaTraceFlush(
|
|
|
7844
8106
|
const evt = buildPendingKafkaTraceEvent(rawTraceEvent);
|
|
7845
8107
|
if (evt) pendingEvents.push(evt);
|
|
7846
8108
|
}
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
8109
|
+
let entries: LegacyEntry[] = [];
|
|
8110
|
+
try {
|
|
8111
|
+
if (pendingEvents.length) {
|
|
8112
|
+
const masking = normalizeMaskingConfig(cfg.masking);
|
|
8113
|
+
const preparedEvents = preparePendingTraceEventsForFlush(pendingEvents);
|
|
8114
|
+
const materializedEvents = await materializePendingTraceEventsAsync(preparedEvents, {
|
|
8115
|
+
cfg,
|
|
8116
|
+
maskReq,
|
|
8117
|
+
masking,
|
|
8118
|
+
resolvePrivacy: () => getRuntimePrivacyState(cfg).policy ?? null,
|
|
8119
|
+
captureScope,
|
|
8120
|
+
});
|
|
8121
|
+
entries = buildKafkaTraceEntries(actionId, requestRid, materializedEvents);
|
|
8122
|
+
}
|
|
8123
|
+
} catch {
|
|
8124
|
+
recordRequestCaptureFailure(
|
|
8125
|
+
captureScope,
|
|
8126
|
+
'trace.capture',
|
|
8127
|
+
'trace.batches',
|
|
8128
|
+
'trace_capture_failed',
|
|
8129
|
+
);
|
|
8130
|
+
}
|
|
7857
8131
|
if (captureScope) {
|
|
7858
8132
|
captureScope.traceBatchCount = entries.length;
|
|
7859
8133
|
}
|
|
7860
|
-
if (entries.length) {
|
|
7861
|
-
post(cfg, sid, { entries });
|
|
7862
|
-
}
|
|
7863
8134
|
if (captureScope) {
|
|
7864
8135
|
post(cfg, sid, {
|
|
7865
8136
|
entries: [{
|
|
@@ -7871,7 +8142,10 @@ function scheduleKafkaTraceFlush(
|
|
|
7871
8142
|
),
|
|
7872
8143
|
t: alignedNow(),
|
|
7873
8144
|
}],
|
|
7874
|
-
});
|
|
8145
|
+
}, { priority: 'high' });
|
|
8146
|
+
}
|
|
8147
|
+
if (entries.length) {
|
|
8148
|
+
post(cfg, sid, { entries });
|
|
7875
8149
|
}
|
|
7876
8150
|
});
|
|
7877
8151
|
}, { priority: 'high' });
|
|
@@ -7890,7 +8164,7 @@ function patchKafkaProducerInstance(producer: any, cfg: KafkaJsPatchConfig) {
|
|
|
7890
8164
|
const aid = ctx.aid ?? fallback.aid ?? null;
|
|
7891
8165
|
const span = captureSpanContextFromTracer();
|
|
7892
8166
|
const publishRid = nextRequestId(alignedNow());
|
|
7893
|
-
const captureScope = createRequestCaptureScope(publishRid, 'kafka');
|
|
8167
|
+
const captureScope = createRequestCaptureScope(publishRid, 'kafka', cfg);
|
|
7894
8168
|
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
7895
8169
|
const payloadObj = payload && typeof payload === 'object' ? payload : {};
|
|
7896
8170
|
const topic = sanitizeKafkaTopic((payloadObj as any).topic);
|
|
@@ -7949,7 +8223,7 @@ function patchKafkaProducerInstance(producer: any, cfg: KafkaJsPatchConfig) {
|
|
|
7949
8223
|
traceId: span?.traceId ?? null,
|
|
7950
8224
|
spanId: span?.spanId ?? null,
|
|
7951
8225
|
parentSpanId: span?.parentSpanId ?? null,
|
|
7952
|
-
});
|
|
8226
|
+
}, captureScope);
|
|
7953
8227
|
|
|
7954
8228
|
const requestPayload: Record<string, any> = {
|
|
7955
8229
|
rid: publishRid,
|
|
@@ -7980,7 +8254,6 @@ function patchKafkaProducerInstance(producer: any, cfg: KafkaJsPatchConfig) {
|
|
|
7980
8254
|
},
|
|
7981
8255
|
],
|
|
7982
8256
|
});
|
|
7983
|
-
captureScope.backendRequestCount += 1;
|
|
7984
8257
|
post(cfg, sid, {
|
|
7985
8258
|
entries: [{
|
|
7986
8259
|
actionId: aid ?? null,
|
|
@@ -8005,7 +8278,7 @@ function patchKafkaProducerInstance(producer: any, cfg: KafkaJsPatchConfig) {
|
|
|
8005
8278
|
const aid = ctx.aid ?? fallback.aid ?? null;
|
|
8006
8279
|
const span = captureSpanContextFromTracer();
|
|
8007
8280
|
const publishRid = nextRequestId(alignedNow());
|
|
8008
|
-
const captureScope = createRequestCaptureScope(publishRid, 'kafka');
|
|
8281
|
+
const captureScope = createRequestCaptureScope(publishRid, 'kafka', cfg);
|
|
8009
8282
|
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
8010
8283
|
|
|
8011
8284
|
const payloadObj = payload && typeof payload === 'object' ? payload : {};
|
|
@@ -8099,7 +8372,7 @@ function patchKafkaProducerInstance(producer: any, cfg: KafkaJsPatchConfig) {
|
|
|
8099
8372
|
traceId: span?.traceId ?? null,
|
|
8100
8373
|
spanId: span?.spanId ?? null,
|
|
8101
8374
|
parentSpanId: span?.parentSpanId ?? null,
|
|
8102
|
-
});
|
|
8375
|
+
}, captureScope);
|
|
8103
8376
|
const requestPayload: Record<string, any> = {
|
|
8104
8377
|
rid: publishRid,
|
|
8105
8378
|
method: 'KAFKA_PUBLISH_BATCH',
|
|
@@ -8129,7 +8402,6 @@ function patchKafkaProducerInstance(producer: any, cfg: KafkaJsPatchConfig) {
|
|
|
8129
8402
|
},
|
|
8130
8403
|
],
|
|
8131
8404
|
});
|
|
8132
|
-
captureScope.backendRequestCount += 1;
|
|
8133
8405
|
post(cfg, sid, {
|
|
8134
8406
|
entries: [{
|
|
8135
8407
|
actionId: aid ?? null,
|
|
@@ -8156,7 +8428,7 @@ function wrapKafkaEachMessageHandler(eachMessage: any, cfg: KafkaJsPatchConfig,
|
|
|
8156
8428
|
const aid = runtime.aid;
|
|
8157
8429
|
const consumeRid = nextRequestId(`${topic}-${message?.offset ?? alignedNow()}`);
|
|
8158
8430
|
const traceId = consumeRid;
|
|
8159
|
-
const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
|
|
8431
|
+
const captureScope = createRequestCaptureScope(consumeRid, 'kafka', cfg);
|
|
8160
8432
|
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
8161
8433
|
const rawTraceEvents: any[] = [];
|
|
8162
8434
|
const maskReq: MaskRequestContext = {
|
|
@@ -8228,7 +8500,7 @@ function wrapKafkaEachMessageHandler(eachMessage: any, cfg: KafkaJsPatchConfig,
|
|
|
8228
8500
|
valueEncoding: messagePayload.valueEncoding,
|
|
8229
8501
|
valueBytes: messagePayload.valueBytes,
|
|
8230
8502
|
message: messagePayload,
|
|
8231
|
-
});
|
|
8503
|
+
}, captureScope);
|
|
8232
8504
|
const requestPayload: Record<string, any> = {
|
|
8233
8505
|
rid: consumeRid,
|
|
8234
8506
|
method: 'KAFKA_CONSUME',
|
|
@@ -8250,7 +8522,6 @@ function wrapKafkaEachMessageHandler(eachMessage: any, cfg: KafkaJsPatchConfig,
|
|
|
8250
8522
|
t: alignedNow(),
|
|
8251
8523
|
}],
|
|
8252
8524
|
});
|
|
8253
|
-
captureScope.backendRequestCount += 1;
|
|
8254
8525
|
scheduleKafkaTraceFlush(cfg, kafkaCtx, aid, consumeRid, rawTraceEvents, maskReq, captureScope);
|
|
8255
8526
|
}
|
|
8256
8527
|
};
|
|
@@ -8267,7 +8538,7 @@ function wrapKafkaEachBatchHandler(eachBatch: any, cfg: KafkaJsPatchConfig, cons
|
|
|
8267
8538
|
const aid = runtime.aid;
|
|
8268
8539
|
const consumeRid = nextRequestId(`${topic}-batch-${alignedNow()}`);
|
|
8269
8540
|
const traceId = consumeRid;
|
|
8270
|
-
const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
|
|
8541
|
+
const captureScope = createRequestCaptureScope(consumeRid, 'kafka', cfg);
|
|
8271
8542
|
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
8272
8543
|
const rawTraceEvents: any[] = [];
|
|
8273
8544
|
const maskReq: MaskRequestContext = {
|
|
@@ -8337,7 +8608,7 @@ function wrapKafkaEachBatchHandler(eachBatch: any, cfg: KafkaJsPatchConfig, cons
|
|
|
8337
8608
|
parentSpanId: runtime.parentSpanId,
|
|
8338
8609
|
firstMessageKey: firstMessagePayload?.key ?? null,
|
|
8339
8610
|
messages: messages.map((message: any) => buildKafkaMessagePayload(message)),
|
|
8340
|
-
});
|
|
8611
|
+
}, captureScope);
|
|
8341
8612
|
const requestPayload: Record<string, any> = {
|
|
8342
8613
|
rid: consumeRid,
|
|
8343
8614
|
method: 'KAFKA_CONSUME_BATCH',
|
|
@@ -8359,7 +8630,6 @@ function wrapKafkaEachBatchHandler(eachBatch: any, cfg: KafkaJsPatchConfig, cons
|
|
|
8359
8630
|
t: alignedNow(),
|
|
8360
8631
|
}],
|
|
8361
8632
|
});
|
|
8362
|
-
captureScope.backendRequestCount += 1;
|
|
8363
8633
|
scheduleKafkaTraceFlush(cfg, kafkaCtx, aid, consumeRid, rawTraceEvents, maskReq, captureScope);
|
|
8364
8634
|
}
|
|
8365
8635
|
};
|
|
@@ -8782,24 +9052,28 @@ function scheduleAmqpTraceFlush(
|
|
|
8782
9052
|
}
|
|
8783
9053
|
|
|
8784
9054
|
let entries: LegacyEntry[] = [];
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
post(cfg, sid, { entries });
|
|
9055
|
+
try {
|
|
9056
|
+
if (pendingEvents.length) {
|
|
9057
|
+
const masking = normalizeMaskingConfig(cfg.masking);
|
|
9058
|
+
const preparedEvents = preparePendingTraceEventsForFlush(pendingEvents);
|
|
9059
|
+
const materializedEvents = await materializePendingTraceEventsAsync(preparedEvents, {
|
|
9060
|
+
cfg,
|
|
9061
|
+
maskReq,
|
|
9062
|
+
masking,
|
|
9063
|
+
resolvePrivacy: () => getRuntimePrivacyState(cfg).policy ?? null,
|
|
9064
|
+
captureScope,
|
|
9065
|
+
});
|
|
9066
|
+
entries = buildAmqpTraceEntries(actionId, requestRid, materializedEvents);
|
|
8798
9067
|
}
|
|
8799
|
-
}
|
|
8800
|
-
|
|
9068
|
+
} catch {
|
|
9069
|
+
recordRequestCaptureFailure(
|
|
9070
|
+
captureScope,
|
|
9071
|
+
'trace.capture',
|
|
9072
|
+
'trace.batches',
|
|
9073
|
+
'trace_capture_failed',
|
|
9074
|
+
);
|
|
8801
9075
|
}
|
|
8802
|
-
|
|
9076
|
+
captureScope.traceBatchCount = entries.length;
|
|
8803
9077
|
post(cfg, sid, {
|
|
8804
9078
|
entries: [{
|
|
8805
9079
|
actionId: actionId ?? null,
|
|
@@ -8810,7 +9084,10 @@ function scheduleAmqpTraceFlush(
|
|
|
8810
9084
|
),
|
|
8811
9085
|
t: alignedNow(),
|
|
8812
9086
|
}],
|
|
8813
|
-
});
|
|
9087
|
+
}, { priority: 'high' });
|
|
9088
|
+
if (entries.length) {
|
|
9089
|
+
post(cfg, sid, { entries });
|
|
9090
|
+
}
|
|
8814
9091
|
});
|
|
8815
9092
|
}, { priority: 'high' });
|
|
8816
9093
|
}
|
|
@@ -8882,7 +9159,12 @@ function scheduleAmqpPublishCapture(params: {
|
|
|
8882
9159
|
};
|
|
8883
9160
|
|
|
8884
9161
|
scheduleSdkBackgroundWork(async () => {
|
|
8885
|
-
const bodyMaterialization = await materializeKafkaRequestBody(
|
|
9162
|
+
const bodyMaterialization = await materializeKafkaRequestBody(
|
|
9163
|
+
params.cfg,
|
|
9164
|
+
maskReq,
|
|
9165
|
+
body,
|
|
9166
|
+
params.captureScope,
|
|
9167
|
+
);
|
|
8886
9168
|
const requestPayload: Record<string, any> = {
|
|
8887
9169
|
rid: params.publishRid,
|
|
8888
9170
|
method: params.method,
|
|
@@ -8913,7 +9195,6 @@ function scheduleAmqpPublishCapture(params: {
|
|
|
8913
9195
|
t: alignedNow(),
|
|
8914
9196
|
}],
|
|
8915
9197
|
});
|
|
8916
|
-
params.captureScope.backendRequestCount += 1;
|
|
8917
9198
|
post(params.cfg, params.sid!, {
|
|
8918
9199
|
entries: [{
|
|
8919
9200
|
actionId: params.aid ?? null,
|
|
@@ -8975,7 +9256,7 @@ function patchAmqplibPublishMethod(
|
|
|
8975
9256
|
: `amqp://queue/${queue}`;
|
|
8976
9257
|
const key = `${method} ${methodName === 'publish' ? `${exchange || 'default'}/${routingKey}` : queue}`;
|
|
8977
9258
|
const content = methodName === 'publish' ? args[2] : args[1];
|
|
8978
|
-
const captureScope = createRequestCaptureScope(publishRid, 'amqp');
|
|
9259
|
+
const captureScope = createRequestCaptureScope(publishRid, 'amqp', cfg);
|
|
8979
9260
|
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
8980
9261
|
const t0 = Date.now();
|
|
8981
9262
|
let finished = false;
|
|
@@ -9065,7 +9346,7 @@ function wrapAmqplibConsumeHandler(onMessage: any, cfg: AmqplibPatchConfig, queu
|
|
|
9065
9346
|
const deliveryTag = message?.fields?.deliveryTag ?? alignedNow();
|
|
9066
9347
|
const consumeRid = nextRequestId(`${queueName}-${deliveryTag}`);
|
|
9067
9348
|
const traceId = consumeRid;
|
|
9068
|
-
const captureScope = createRequestCaptureScope(consumeRid, 'amqp');
|
|
9349
|
+
const captureScope = createRequestCaptureScope(consumeRid, 'amqp', cfg);
|
|
9069
9350
|
emitRequestCaptureStart(cfg, sid, aid, captureScope);
|
|
9070
9351
|
const rawTraceEvents: any[] = [];
|
|
9071
9352
|
const maskReq: MaskRequestContext = {
|
|
@@ -9150,7 +9431,12 @@ function wrapAmqplibConsumeHandler(onMessage: any, cfg: AmqplibPatchConfig, queu
|
|
|
9150
9431
|
};
|
|
9151
9432
|
|
|
9152
9433
|
scheduleSdkBackgroundWork(async () => {
|
|
9153
|
-
const bodyMaterialization = await materializeKafkaRequestBody(
|
|
9434
|
+
const bodyMaterialization = await materializeKafkaRequestBody(
|
|
9435
|
+
cfg,
|
|
9436
|
+
maskReq,
|
|
9437
|
+
body,
|
|
9438
|
+
captureScope,
|
|
9439
|
+
);
|
|
9154
9440
|
const requestPayload: Record<string, any> = {
|
|
9155
9441
|
rid: consumeRid,
|
|
9156
9442
|
method: 'AMQP_CONSUME',
|
|
@@ -9172,7 +9458,6 @@ function wrapAmqplibConsumeHandler(onMessage: any, cfg: AmqplibPatchConfig, queu
|
|
|
9172
9458
|
t: alignedNow(),
|
|
9173
9459
|
}],
|
|
9174
9460
|
});
|
|
9175
|
-
captureScope.backendRequestCount += 1;
|
|
9176
9461
|
scheduleAmqpTraceFlush(cfg, amqpCtx, aid, consumeRid, rawTraceEvents, maskReq, captureScope);
|
|
9177
9462
|
}, { priority: 'high' });
|
|
9178
9463
|
};
|