repro-nest 0.0.205 → 0.0.208
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 +5 -0
- package/dist/index.js +20 -1
- package/package.json +1 -1
- package/src/index.ts +24 -2
- package/tracer/runtime.js +46 -7
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,11 @@ type TracerApi = {
|
|
|
29
29
|
init?: (opts: any) => void;
|
|
30
30
|
tracer?: {
|
|
31
31
|
on: (fn: (ev: any) => void) => () => void;
|
|
32
|
+
getCurrentTraceContext?: () => {
|
|
33
|
+
traceId: any;
|
|
34
|
+
spanId: any;
|
|
35
|
+
depth?: number;
|
|
36
|
+
};
|
|
32
37
|
};
|
|
33
38
|
getCurrentTraceId?: () => string | null;
|
|
34
39
|
patchHttp?: () => void;
|
package/dist/index.js
CHANGED
|
@@ -439,6 +439,13 @@ function initReproTracing(opts) {
|
|
|
439
439
|
const initOpts = { ...defaultTracerInitOpts(), ...rest };
|
|
440
440
|
tracerPkg.init?.(initOpts);
|
|
441
441
|
tracerPkg.patchHttp?.();
|
|
442
|
+
// Ensure tracer exposes current trace context on the on-event API when available.
|
|
443
|
+
try {
|
|
444
|
+
if (!tracerPkg.tracer?.getCurrentTraceContext && tracerPkg.getCurrentTraceContext) {
|
|
445
|
+
tracerPkg.tracer.getCurrentTraceContext = tracerPkg.getCurrentTraceContext;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
catch { }
|
|
442
449
|
applyTraceLogPreference(tracerPkg);
|
|
443
450
|
__TRACER_READY = true;
|
|
444
451
|
patchAllKnownMongooseInstances();
|
|
@@ -800,7 +807,8 @@ const SESSION_DRAIN_TIMEOUT_MS = (() => {
|
|
|
800
807
|
if (Number.isFinite(env) && env >= 0)
|
|
801
808
|
return env;
|
|
802
809
|
// Bound wait for draining sessions to avoid lost flushes when a request hangs.
|
|
803
|
-
|
|
810
|
+
// Default to 1 minute; caller can override via env.
|
|
811
|
+
return 60000;
|
|
804
812
|
})();
|
|
805
813
|
function isThenable(value) {
|
|
806
814
|
return value != null && typeof value === 'object' && typeof value.then === 'function';
|
|
@@ -1327,6 +1335,9 @@ function reproMiddleware(cfg) {
|
|
|
1327
1335
|
if (ev.args !== undefined) {
|
|
1328
1336
|
evt.args = sanitizeTraceArgs(ev.args);
|
|
1329
1337
|
}
|
|
1338
|
+
if (ev.receiver !== undefined) {
|
|
1339
|
+
evt.receiver = sanitizeTraceValue(ev.receiver);
|
|
1340
|
+
}
|
|
1330
1341
|
if (ev.returnValue !== undefined) {
|
|
1331
1342
|
evt.returnValue = sanitizeTraceValue(ev.returnValue);
|
|
1332
1343
|
}
|
|
@@ -1888,6 +1899,12 @@ function dehydrateComplexValue(value) {
|
|
|
1888
1899
|
function emitDbQuery(cfg, sid, aid, payload) {
|
|
1889
1900
|
if (!sid)
|
|
1890
1901
|
return;
|
|
1902
|
+
let traceCtx = null;
|
|
1903
|
+
try {
|
|
1904
|
+
const getCtx = __TRACER__?.tracer?.getCurrentTraceContext;
|
|
1905
|
+
traceCtx = typeof getCtx === 'function' ? getCtx() : null;
|
|
1906
|
+
}
|
|
1907
|
+
catch { }
|
|
1891
1908
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
|
|
1892
1909
|
entries: [{
|
|
1893
1910
|
actionId: aid ?? null,
|
|
@@ -1897,6 +1914,8 @@ function emitDbQuery(cfg, sid, aid, payload) {
|
|
|
1897
1914
|
query: payload.query ?? undefined,
|
|
1898
1915
|
resultMeta: payload.resultMeta ?? undefined,
|
|
1899
1916
|
durMs: payload.durMs ?? undefined,
|
|
1917
|
+
traceId: traceCtx?.traceId ?? null,
|
|
1918
|
+
spanId: traceCtx?.spanId ?? null,
|
|
1900
1919
|
pk: null, before: null, after: null,
|
|
1901
1920
|
error: payload.error ?? undefined,
|
|
1902
1921
|
}],
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -174,7 +174,10 @@ function patchAllKnownMongooseInstances() {
|
|
|
174
174
|
// ====== tiny, safe tracer auto-init (no node_modules patches) ======
|
|
175
175
|
type TracerApi = {
|
|
176
176
|
init?: (opts: any) => void;
|
|
177
|
-
tracer?: {
|
|
177
|
+
tracer?: {
|
|
178
|
+
on: (fn: (ev: any) => void) => () => void;
|
|
179
|
+
getCurrentTraceContext?: () => { traceId: any; spanId: any; depth?: number };
|
|
180
|
+
};
|
|
178
181
|
getCurrentTraceId?: () => string | null;
|
|
179
182
|
patchHttp?: () => void; // optional in your tracer
|
|
180
183
|
setFunctionLogsEnabled?: (enabled: boolean) => void;
|
|
@@ -210,6 +213,7 @@ type TraceEventRecord = {
|
|
|
210
213
|
spanId?: string | number | null;
|
|
211
214
|
parentSpanId?: string | number | null;
|
|
212
215
|
args?: any;
|
|
216
|
+
receiver?: any;
|
|
213
217
|
returnValue?: any;
|
|
214
218
|
threw?: boolean;
|
|
215
219
|
error?: any;
|
|
@@ -622,6 +626,12 @@ export function initReproTracing(opts?: ReproTracingInitOptions) {
|
|
|
622
626
|
const initOpts = { ...defaultTracerInitOpts(), ...(rest as TracerInitOpts) };
|
|
623
627
|
tracerPkg.init?.(initOpts);
|
|
624
628
|
tracerPkg.patchHttp?.();
|
|
629
|
+
// Ensure tracer exposes current trace context on the on-event API when available.
|
|
630
|
+
try {
|
|
631
|
+
if (!tracerPkg.tracer?.getCurrentTraceContext && (tracerPkg as any).getCurrentTraceContext) {
|
|
632
|
+
(tracerPkg.tracer as any).getCurrentTraceContext = (tracerPkg as any).getCurrentTraceContext;
|
|
633
|
+
}
|
|
634
|
+
} catch {}
|
|
625
635
|
applyTraceLogPreference(tracerPkg);
|
|
626
636
|
__TRACER_READY = true;
|
|
627
637
|
patchAllKnownMongooseInstances();
|
|
@@ -1023,7 +1033,8 @@ const SESSION_DRAIN_TIMEOUT_MS = (() => {
|
|
|
1023
1033
|
const env = Number(process.env.SESSION_DRAIN_TIMEOUT_MS);
|
|
1024
1034
|
if (Number.isFinite(env) && env >= 0) return env;
|
|
1025
1035
|
// Bound wait for draining sessions to avoid lost flushes when a request hangs.
|
|
1026
|
-
|
|
1036
|
+
// Default to 1 minute; caller can override via env.
|
|
1037
|
+
return 60000;
|
|
1027
1038
|
})();
|
|
1028
1039
|
|
|
1029
1040
|
function isThenable(value: any): value is PromiseLike<any> {
|
|
@@ -1532,6 +1543,9 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1532
1543
|
if (ev.args !== undefined) {
|
|
1533
1544
|
evt.args = sanitizeTraceArgs(ev.args);
|
|
1534
1545
|
}
|
|
1546
|
+
if (ev.receiver !== undefined) {
|
|
1547
|
+
evt.receiver = sanitizeTraceValue(ev.receiver);
|
|
1548
|
+
}
|
|
1535
1549
|
if (ev.returnValue !== undefined) {
|
|
1536
1550
|
evt.returnValue = sanitizeTraceValue(ev.returnValue);
|
|
1537
1551
|
}
|
|
@@ -2100,6 +2114,12 @@ function dehydrateComplexValue(value: any) {
|
|
|
2100
2114
|
|
|
2101
2115
|
function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
|
|
2102
2116
|
if (!sid) return;
|
|
2117
|
+
let traceCtx: { traceId: any; spanId: any } | null = null;
|
|
2118
|
+
try {
|
|
2119
|
+
const getCtx = __TRACER__?.tracer?.getCurrentTraceContext;
|
|
2120
|
+
traceCtx = typeof getCtx === 'function' ? getCtx() : null;
|
|
2121
|
+
} catch {}
|
|
2122
|
+
|
|
2103
2123
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
|
|
2104
2124
|
entries: [{
|
|
2105
2125
|
actionId: aid ?? null,
|
|
@@ -2109,6 +2129,8 @@ function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
|
|
|
2109
2129
|
query: payload.query ?? undefined,
|
|
2110
2130
|
resultMeta: payload.resultMeta ?? undefined,
|
|
2111
2131
|
durMs: payload.durMs ?? undefined,
|
|
2132
|
+
traceId: traceCtx?.traceId ?? null,
|
|
2133
|
+
spanId: traceCtx?.spanId ?? null,
|
|
2112
2134
|
pk: null, before: null, after: null,
|
|
2113
2135
|
error: payload.error ?? undefined,
|
|
2114
2136
|
}],
|
package/tracer/runtime.js
CHANGED
|
@@ -100,6 +100,17 @@ function popSpan(ctx) {
|
|
|
100
100
|
const trace = {
|
|
101
101
|
on(fn){ listeners.add(fn); return () => listeners.delete(fn); },
|
|
102
102
|
withTrace(id, fn, depth = 0){ return als.run({ traceId: id, depth }, fn); },
|
|
103
|
+
getCurrentTraceContext(){
|
|
104
|
+
const store = als.getStore();
|
|
105
|
+
if (!store) return { traceId: null, spanId: null, depth: 0 };
|
|
106
|
+
const spanStack = Array.isArray(store.__repro_span_stack) ? store.__repro_span_stack : [];
|
|
107
|
+
const top = spanStack.length ? spanStack[spanStack.length - 1] : null;
|
|
108
|
+
return {
|
|
109
|
+
traceId: store.traceId || null,
|
|
110
|
+
spanId: top ? top.id ?? null : null,
|
|
111
|
+
depth: typeof store.depth === 'number' ? store.depth : (top?.depth ?? 0),
|
|
112
|
+
};
|
|
113
|
+
},
|
|
103
114
|
enter(fn, meta, detail){
|
|
104
115
|
const parentSpanIdOverride = meta && Object.prototype.hasOwnProperty.call(meta, 'parentSpanId')
|
|
105
116
|
? meta.parentSpanId
|
|
@@ -132,6 +143,7 @@ const trace = {
|
|
|
132
143
|
traceId: ctx.traceId,
|
|
133
144
|
depth: ctx.depth,
|
|
134
145
|
args: detail?.args,
|
|
146
|
+
receiver: detail?.receiver,
|
|
135
147
|
spanId: span.id,
|
|
136
148
|
parentSpanId: span.parentId
|
|
137
149
|
});
|
|
@@ -159,7 +171,8 @@ const trace = {
|
|
|
159
171
|
returnValue: detail?.returnValue,
|
|
160
172
|
error: detail?.error,
|
|
161
173
|
threw: detail?.threw === true,
|
|
162
|
-
unawaited: detail?.unawaited === true || frameUnawaited
|
|
174
|
+
unawaited: detail?.unawaited === true || frameUnawaited,
|
|
175
|
+
receiver: detail?.receiver
|
|
163
176
|
};
|
|
164
177
|
|
|
165
178
|
const promiseTaggedUnawaited = !!(baseDetail.returnValue && baseDetail.returnValue[SYM_UNAWAITED]);
|
|
@@ -179,6 +192,9 @@ const trace = {
|
|
|
179
192
|
unawaited: overrides.hasOwnProperty('unawaited')
|
|
180
193
|
? overrides.unawaited
|
|
181
194
|
: forceUnawaited,
|
|
195
|
+
receiver: overrides.hasOwnProperty('receiver')
|
|
196
|
+
? overrides.receiver
|
|
197
|
+
: baseDetail.receiver,
|
|
182
198
|
args: overrides.hasOwnProperty('args')
|
|
183
199
|
? overrides.args
|
|
184
200
|
: baseDetail.args
|
|
@@ -199,6 +215,7 @@ const trace = {
|
|
|
199
215
|
threw: finalDetail.threw === true,
|
|
200
216
|
error: finalDetail.error,
|
|
201
217
|
args: finalDetail.args,
|
|
218
|
+
receiver: finalDetail.receiver,
|
|
202
219
|
unawaited: finalDetail.unawaited === true
|
|
203
220
|
});
|
|
204
221
|
};
|
|
@@ -475,6 +492,24 @@ function forkAlsStoreForUnawaited(baseStore) {
|
|
|
475
492
|
return cloned;
|
|
476
493
|
}
|
|
477
494
|
|
|
495
|
+
// Only capture receiver/collection snapshots for common array iteration helpers to keep noise low.
|
|
496
|
+
const RECEIVER_METHOD_NAMES = new Set([
|
|
497
|
+
// Array iterators
|
|
498
|
+
'map', 'forEach', 'filter', 'find', 'findIndex', 'findLast', 'findLastIndex',
|
|
499
|
+
'some', 'every', 'reduce', 'reduceRight', 'flatMap', 'flat',
|
|
500
|
+
// Set / Map mutators
|
|
501
|
+
'add', 'delete', 'clear', 'set'
|
|
502
|
+
]);
|
|
503
|
+
|
|
504
|
+
function shouldCaptureReceiver(label, receiver) {
|
|
505
|
+
if (!label || receiver === null || receiver === undefined) return false;
|
|
506
|
+
const method = String(label).split('.').pop() || '';
|
|
507
|
+
if (!RECEIVER_METHOD_NAMES.has(method)) return false;
|
|
508
|
+
if (Array.isArray(receiver)) return true;
|
|
509
|
+
if (typeof receiver === 'object' && typeof receiver[Symbol.iterator] === 'function') return true;
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
|
|
478
513
|
// ========= Generic call-site shim (used by Babel transform) =========
|
|
479
514
|
// Decides whether to emit a top-level event based on callee origin tags.
|
|
480
515
|
// No hardcoded library names or file paths.
|
|
@@ -596,13 +631,15 @@ if (!global.__repro_call) {
|
|
|
596
631
|
? (label && label.length ? label : fn.name)
|
|
597
632
|
: '(anonymous)';
|
|
598
633
|
const sourceFile = fn[SYM_SRC_FILE];
|
|
634
|
+
const receiverForTrace = shouldCaptureReceiver(label, thisArg) ? thisArg : undefined;
|
|
599
635
|
const meta = {
|
|
600
|
-
file
|
|
601
|
-
|
|
636
|
+
// Prefer callsite file/line so traces point to where the function was invoked.
|
|
637
|
+
file: callFile || sourceFile || null,
|
|
638
|
+
line: callLine ?? null,
|
|
602
639
|
parentSpanId: forcedParentSpanId
|
|
603
640
|
};
|
|
604
641
|
|
|
605
|
-
trace.enter(name, meta, { args });
|
|
642
|
+
trace.enter(name, meta, { args, receiver: receiverForTrace });
|
|
606
643
|
// After entering, snapshot a clean store that captures the parent + this call’s span,
|
|
607
644
|
// so callbacks invoked during the callee run are isolated per invocation.
|
|
608
645
|
const snapshotForArgs = cloneStore(als.getStore());
|
|
@@ -617,7 +654,8 @@ if (!global.__repro_call) {
|
|
|
617
654
|
const exitDetailBase = {
|
|
618
655
|
returnValue: out,
|
|
619
656
|
args,
|
|
620
|
-
unawaited: shouldForceExit
|
|
657
|
+
unawaited: shouldForceExit,
|
|
658
|
+
receiver: receiverForTrace
|
|
621
659
|
};
|
|
622
660
|
|
|
623
661
|
if (shouldForceExit) markPromiseUnawaited(out);
|
|
@@ -659,7 +697,8 @@ if (!global.__repro_call) {
|
|
|
659
697
|
args,
|
|
660
698
|
threw,
|
|
661
699
|
error,
|
|
662
|
-
unawaited: shouldForceExit
|
|
700
|
+
unawaited: shouldForceExit,
|
|
701
|
+
receiver: receiverForTrace
|
|
663
702
|
};
|
|
664
703
|
runExit(detail);
|
|
665
704
|
return value;
|
|
@@ -679,7 +718,7 @@ if (!global.__repro_call) {
|
|
|
679
718
|
runExit(exitDetailBase);
|
|
680
719
|
return out;
|
|
681
720
|
} catch (e) {
|
|
682
|
-
trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args });
|
|
721
|
+
trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args, receiver: receiverForTrace });
|
|
683
722
|
throw e;
|
|
684
723
|
} finally {
|
|
685
724
|
if (pendingMarker) {
|