repro-nest 0.0.215 → 0.0.217
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 -2
- package/dist/index.js +9 -2
- package/docs/tracing.md +3 -2
- package/package.json +1 -1
- package/src/index.ts +17 -7
- package/tracer/runtime.js +57 -21
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ type TracerApi = {
|
|
|
42
42
|
setFunctionLogsEnabled?: (enabled: boolean) => void;
|
|
43
43
|
};
|
|
44
44
|
type TraceEventPhase = 'enter' | 'exit';
|
|
45
|
-
export type TraceRulePattern = string | RegExp | Array<string | RegExp>;
|
|
45
|
+
export type TraceRulePattern = string | number | RegExp | Array<string | number | RegExp>;
|
|
46
46
|
export type TraceEventForFilter = {
|
|
47
47
|
type: TraceEventPhase;
|
|
48
48
|
eventType: TraceEventPhase;
|
|
@@ -50,6 +50,7 @@ export type TraceEventForFilter = {
|
|
|
50
50
|
fn?: string;
|
|
51
51
|
wrapperClass?: string | null;
|
|
52
52
|
file?: string | null;
|
|
53
|
+
line?: number | null;
|
|
53
54
|
depth?: number;
|
|
54
55
|
library?: string | null;
|
|
55
56
|
};
|
|
@@ -100,8 +101,10 @@ export type DisableFunctionTraceRule = {
|
|
|
100
101
|
className?: TraceRulePattern;
|
|
101
102
|
/** Alias for {@link wrapperClass}. */
|
|
102
103
|
owner?: TraceRulePattern;
|
|
103
|
-
/**
|
|
104
|
+
/** Source filename reported by the trace event. */
|
|
104
105
|
file?: TraceRulePattern;
|
|
106
|
+
/** Line number reported by the trace event. */
|
|
107
|
+
line?: TraceRulePattern;
|
|
105
108
|
/** Shortcut for {@link library}. */
|
|
106
109
|
lib?: TraceRulePattern;
|
|
107
110
|
/** Library/package name inferred from the file path (e.g. `"mongoose"`). */
|
package/dist/index.js
CHANGED
|
@@ -325,6 +325,8 @@ function matchesRule(rule, event) {
|
|
|
325
325
|
return false;
|
|
326
326
|
if (!matchesPattern(event.file, rule.file))
|
|
327
327
|
return false;
|
|
328
|
+
if (!matchesPattern(event.line == null ? null : String(event.line), rule.line))
|
|
329
|
+
return false;
|
|
328
330
|
const libPattern = rule.lib ?? rule.library;
|
|
329
331
|
if (!matchesPattern(event.library, libPattern))
|
|
330
332
|
return false;
|
|
@@ -385,7 +387,7 @@ function flattenTraceFilePatterns(config) {
|
|
|
385
387
|
if (Array.isArray(config)) {
|
|
386
388
|
return config.flatMap(entry => flattenTraceFilePatterns(entry));
|
|
387
389
|
}
|
|
388
|
-
if (config instanceof RegExp || typeof config === 'string') {
|
|
390
|
+
if (config instanceof RegExp || typeof config === 'string' || typeof config === 'number') {
|
|
389
391
|
return [config];
|
|
390
392
|
}
|
|
391
393
|
if (typeof config === 'object' && 'file' in config) {
|
|
@@ -1635,6 +1637,9 @@ function reproMiddleware(cfg) {
|
|
|
1635
1637
|
unsubscribe = __TRACER__.tracer.on((ev) => {
|
|
1636
1638
|
if (!ev || ev.traceId !== tidNow)
|
|
1637
1639
|
return;
|
|
1640
|
+
const sourceFileForLibrary = typeof ev.sourceFile === 'string' && ev.sourceFile
|
|
1641
|
+
? String(ev.sourceFile)
|
|
1642
|
+
: null;
|
|
1638
1643
|
const evt = {
|
|
1639
1644
|
t: alignTimestamp(ev.t),
|
|
1640
1645
|
type: ev.type,
|
|
@@ -1655,8 +1660,9 @@ function reproMiddleware(cfg) {
|
|
|
1655
1660
|
fn: evt.fn,
|
|
1656
1661
|
wrapperClass: inferWrapperClassFromFn(evt.fn),
|
|
1657
1662
|
file: evt.file ?? null,
|
|
1663
|
+
line: evt.line ?? null,
|
|
1658
1664
|
depth: evt.depth,
|
|
1659
|
-
library: inferLibraryNameFromFile(evt.file),
|
|
1665
|
+
library: inferLibraryNameFromFile(sourceFileForLibrary ?? evt.file),
|
|
1660
1666
|
};
|
|
1661
1667
|
if (ev.args !== undefined) {
|
|
1662
1668
|
evt.args = applyMasking('trace.args', sanitizeTraceArgs(ev.args), maskReq, candidate, masking);
|
|
@@ -1765,6 +1771,7 @@ function reproMiddleware(cfg) {
|
|
|
1765
1771
|
fn: chosenEndpoint.fn ?? undefined,
|
|
1766
1772
|
wrapperClass: inferWrapperClassFromFn(chosenEndpoint.fn),
|
|
1767
1773
|
file: chosenEndpoint.file ?? null,
|
|
1774
|
+
line: chosenEndpoint.line ?? null,
|
|
1768
1775
|
functionType: chosenEndpoint.functionType ?? null,
|
|
1769
1776
|
library: inferLibraryNameFromFile(chosenEndpoint.file),
|
|
1770
1777
|
};
|
package/docs/tracing.md
CHANGED
|
@@ -51,7 +51,8 @@ captured in the session payload.
|
|
|
51
51
|
| --------------- | ------------------------------------------------------------------------------------------------- |
|
|
52
52
|
| `fn`/`functionName` | Match against the instrumented function name (substring or RegExp). |
|
|
53
53
|
| `wrapper`/`wrapperClass`/`className`/`owner` | Match the wrapper/owner inferred from the function name (e.g. `"UserService"` in `"UserService.create"`). |
|
|
54
|
-
| `file` | Match the
|
|
54
|
+
| `file` | Match the filename reported by the trace event (callsite when available; may fall back to the function definition file when the caller is not instrumented). |
|
|
55
|
+
| `line` | Match the line number reported by the trace event. |
|
|
55
56
|
| `lib`/`library` | Match the npm package inferred from the file path (e.g. `"mongoose"`). |
|
|
56
57
|
| `type`/`functionType` | Match the detected function kind (e.g. `"constructor"`, `"method"`, `"arrow"`). |
|
|
57
58
|
| `event`/`eventType` | Match the trace phase (`"enter"` or `"exit"`) to suppress only specific edges of a call. |
|
|
@@ -94,7 +95,7 @@ function inputs/outputs before they are persisted.
|
|
|
94
95
|
### Rules
|
|
95
96
|
|
|
96
97
|
- `when.method` / `when.path` / `when.key` scope rules by endpoint (`key` is `"METHOD /path"` without query string).
|
|
97
|
-
- For function-specific rules, `when` supports the same fields as `disableFunctionTraces` (`fn`, `wrapperClass`, `file`, etc). This is useful when multiple functions share the same name.
|
|
98
|
+
- For function-specific rules, `when` supports the same fields as `disableFunctionTraces` (`fn`, `wrapperClass`, `file`, `line`, etc). This is useful when multiple functions share the same name.
|
|
98
99
|
- `paths` uses dot/bracket syntax and supports `*`, `[0]`, `[*]` (example: `"items[*].token"` or `"0.password"` for trace args arrays).
|
|
99
100
|
- `keys` masks matching key names anywhere in the payload (string/RegExp/array).
|
|
100
101
|
- `replacement` overrides the default replacement value (defaults to `"[REDACTED]"`).
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -229,7 +229,7 @@ let __TRACER__: TracerApi | null = null;
|
|
|
229
229
|
let __TRACER_READY = false;
|
|
230
230
|
|
|
231
231
|
type TraceEventPhase = 'enter' | 'exit';
|
|
232
|
-
export type TraceRulePattern = string | RegExp | Array<string | RegExp>;
|
|
232
|
+
export type TraceRulePattern = string | number | RegExp | Array<string | number | RegExp>;
|
|
233
233
|
|
|
234
234
|
export type TraceEventForFilter = {
|
|
235
235
|
type: TraceEventPhase; // legacy alias for eventType
|
|
@@ -238,6 +238,7 @@ export type TraceEventForFilter = {
|
|
|
238
238
|
fn?: string;
|
|
239
239
|
wrapperClass?: string | null;
|
|
240
240
|
file?: string | null;
|
|
241
|
+
line?: number | null;
|
|
241
242
|
depth?: number;
|
|
242
243
|
library?: string | null;
|
|
243
244
|
};
|
|
@@ -323,8 +324,10 @@ export type DisableFunctionTraceRule = {
|
|
|
323
324
|
className?: TraceRulePattern;
|
|
324
325
|
/** Alias for {@link wrapperClass}. */
|
|
325
326
|
owner?: TraceRulePattern;
|
|
326
|
-
/**
|
|
327
|
+
/** Source filename reported by the trace event. */
|
|
327
328
|
file?: TraceRulePattern;
|
|
329
|
+
/** Line number reported by the trace event. */
|
|
330
|
+
line?: TraceRulePattern;
|
|
328
331
|
/** Shortcut for {@link library}. */
|
|
329
332
|
lib?: TraceRulePattern;
|
|
330
333
|
/** Library/package name inferred from the file path (e.g. `"mongoose"`). */
|
|
@@ -409,8 +412,8 @@ function refreshDisabledFunctionTraceRules() {
|
|
|
409
412
|
}
|
|
410
413
|
|
|
411
414
|
let disabledFunctionTraceRules: DisableFunctionTraceConfig[] = computeDisabledFunctionTraceRules();
|
|
412
|
-
let disabledFunctionTypePatterns: Array<string | RegExp> = [];
|
|
413
|
-
let disabledTraceFilePatterns: Array<string | RegExp> = [];
|
|
415
|
+
let disabledFunctionTypePatterns: Array<string | number | RegExp> = [];
|
|
416
|
+
let disabledTraceFilePatterns: Array<string | number | RegExp> = [];
|
|
414
417
|
let __TRACE_LOG_PREF: boolean | null = null;
|
|
415
418
|
|
|
416
419
|
function setInterceptorTracingEnabled(enabled: boolean) {
|
|
@@ -489,6 +492,7 @@ function matchesRule(rule: DisableFunctionTraceRule, event: TraceEventForFilter)
|
|
|
489
492
|
if (!matchesPattern(event.wrapperClass, wrapperPattern)) return false;
|
|
490
493
|
|
|
491
494
|
if (!matchesPattern(event.file, rule.file)) return false;
|
|
495
|
+
if (!matchesPattern(event.line == null ? null : String(event.line), rule.line)) return false;
|
|
492
496
|
|
|
493
497
|
const libPattern = rule.lib ?? rule.library;
|
|
494
498
|
if (!matchesPattern(event.library, libPattern)) return false;
|
|
@@ -541,12 +545,12 @@ export function setDisabledFunctionTypes(patterns?: TraceRulePattern | null) {
|
|
|
541
545
|
disabledFunctionTypePatterns = normalizePatternArray(patterns);
|
|
542
546
|
}
|
|
543
547
|
|
|
544
|
-
function flattenTraceFilePatterns(config: DisableTraceFileConfig): Array<string | RegExp> {
|
|
548
|
+
function flattenTraceFilePatterns(config: DisableTraceFileConfig): Array<string | number | RegExp> {
|
|
545
549
|
if (config === null || config === undefined) return [];
|
|
546
550
|
if (Array.isArray(config)) {
|
|
547
551
|
return config.flatMap(entry => flattenTraceFilePatterns(entry));
|
|
548
552
|
}
|
|
549
|
-
if (config instanceof RegExp || typeof config === 'string') {
|
|
553
|
+
if (config instanceof RegExp || typeof config === 'string' || typeof config === 'number') {
|
|
550
554
|
return [config];
|
|
551
555
|
}
|
|
552
556
|
if (typeof config === 'object' && 'file' in config) {
|
|
@@ -1910,6 +1914,10 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1910
1914
|
unsubscribe = __TRACER__.tracer.on((ev: any) => {
|
|
1911
1915
|
if (!ev || ev.traceId !== tidNow) return;
|
|
1912
1916
|
|
|
1917
|
+
const sourceFileForLibrary = typeof ev.sourceFile === 'string' && ev.sourceFile
|
|
1918
|
+
? String(ev.sourceFile)
|
|
1919
|
+
: null;
|
|
1920
|
+
|
|
1913
1921
|
const evt: TraceEventRecord = {
|
|
1914
1922
|
t: alignTimestamp(ev.t),
|
|
1915
1923
|
type: ev.type,
|
|
@@ -1932,8 +1940,9 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1932
1940
|
fn: evt.fn,
|
|
1933
1941
|
wrapperClass: inferWrapperClassFromFn(evt.fn),
|
|
1934
1942
|
file: evt.file ?? null,
|
|
1943
|
+
line: evt.line ?? null,
|
|
1935
1944
|
depth: evt.depth,
|
|
1936
|
-
library: inferLibraryNameFromFile(evt.file),
|
|
1945
|
+
library: inferLibraryNameFromFile(sourceFileForLibrary ?? evt.file),
|
|
1937
1946
|
};
|
|
1938
1947
|
|
|
1939
1948
|
if (ev.args !== undefined) {
|
|
@@ -2060,6 +2069,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
2060
2069
|
fn: chosenEndpoint.fn ?? undefined,
|
|
2061
2070
|
wrapperClass: inferWrapperClassFromFn(chosenEndpoint.fn),
|
|
2062
2071
|
file: chosenEndpoint.file ?? null,
|
|
2072
|
+
line: chosenEndpoint.line ?? null,
|
|
2063
2073
|
functionType: chosenEndpoint.functionType ?? null,
|
|
2064
2074
|
library: inferLibraryNameFromFile(chosenEndpoint.file),
|
|
2065
2075
|
};
|
package/tracer/runtime.js
CHANGED
|
@@ -86,15 +86,15 @@ function pushSpan(ctx, depth, explicitParentId = null) {
|
|
|
86
86
|
const parent = explicitParentId !== null && explicitParentId !== undefined
|
|
87
87
|
? { id: explicitParentId, parentId: null }
|
|
88
88
|
: (stack.length ? stack[stack.length - 1] : null);
|
|
89
|
-
const span = { id: ++SPAN_COUNTER, parentId: parent ? parent.id : null, depth };
|
|
89
|
+
const span = { id: ++SPAN_COUNTER, parentId: parent ? parent.id : null, depth, file: null, line: null, sourceFile: null };
|
|
90
90
|
stack.push(span);
|
|
91
91
|
return span;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function popSpan(ctx) {
|
|
95
95
|
const stack = ctx.__repro_span_stack;
|
|
96
|
-
if (!Array.isArray(stack) || !stack.length) return { id: null, parentId: null, depth: null };
|
|
97
|
-
return stack.pop() || { id: null, parentId: null, depth: null };
|
|
96
|
+
if (!Array.isArray(stack) || !stack.length) return { id: null, parentId: null, depth: null, file: null, line: null, sourceFile: null };
|
|
97
|
+
return stack.pop() || { id: null, parentId: null, depth: null, file: null, line: null, sourceFile: null };
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
const trace = {
|
|
@@ -120,14 +120,36 @@ const trace = {
|
|
|
120
120
|
}
|
|
121
121
|
frameStack.push(frameUnawaited);
|
|
122
122
|
|
|
123
|
+
const fallbackDefinitionFile = meta?.file || null;
|
|
124
|
+
let file = meta?.file || null;
|
|
125
|
+
let line = meta?.line || null;
|
|
126
|
+
let sourceFile = meta?.sourceFile || null;
|
|
127
|
+
try {
|
|
128
|
+
const queue = ctx.__repro_callsite_queue;
|
|
129
|
+
if (Array.isArray(queue) && queue.length) {
|
|
130
|
+
const override = queue.shift();
|
|
131
|
+
if (override && (override.file || override.line !== null && override.line !== undefined)) {
|
|
132
|
+
if (!sourceFile && fallbackDefinitionFile) sourceFile = fallbackDefinitionFile;
|
|
133
|
+
if (override.file) file = override.file;
|
|
134
|
+
if (override.line !== null && override.line !== undefined) line = override.line;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch {}
|
|
138
|
+
|
|
123
139
|
const span = pushSpan(ctx, ctx.depth, parentSpanIdOverride);
|
|
140
|
+
try {
|
|
141
|
+
span.file = file;
|
|
142
|
+
span.line = line;
|
|
143
|
+
span.sourceFile = sourceFile;
|
|
144
|
+
} catch {}
|
|
124
145
|
|
|
125
146
|
emit({
|
|
126
147
|
type: 'enter',
|
|
127
148
|
t: Date.now(),
|
|
128
149
|
fn,
|
|
129
|
-
file
|
|
130
|
-
line
|
|
150
|
+
file,
|
|
151
|
+
line,
|
|
152
|
+
sourceFile,
|
|
131
153
|
functionType: meta?.functionType || null,
|
|
132
154
|
traceId: ctx.traceId,
|
|
133
155
|
depth: ctx.depth,
|
|
@@ -144,6 +166,7 @@ const trace = {
|
|
|
144
166
|
fn: meta?.fn,
|
|
145
167
|
file: meta?.file,
|
|
146
168
|
line: meta?.line,
|
|
169
|
+
sourceFile: meta?.sourceFile || null,
|
|
147
170
|
functionType: meta?.functionType || null
|
|
148
171
|
};
|
|
149
172
|
const frameStack = ctx.__repro_frame_unawaited;
|
|
@@ -153,7 +176,7 @@ const trace = {
|
|
|
153
176
|
const spanStackRef = Array.isArray(ctx.__repro_span_stack) ? ctx.__repro_span_stack : [];
|
|
154
177
|
const spanInfoPeek = spanStackRef.length
|
|
155
178
|
? spanStackRef[spanStackRef.length - 1]
|
|
156
|
-
: { id: null, parentId: null, depth: depthAtExit };
|
|
179
|
+
: { id: null, parentId: null, depth: depthAtExit, file: baseMeta.file, line: baseMeta.line, sourceFile: baseMeta.sourceFile };
|
|
157
180
|
const baseDetail = {
|
|
158
181
|
args: detail?.args,
|
|
159
182
|
returnValue: detail?.returnValue,
|
|
@@ -188,8 +211,9 @@ const trace = {
|
|
|
188
211
|
type: 'exit',
|
|
189
212
|
t: Date.now(),
|
|
190
213
|
fn: baseMeta.fn,
|
|
191
|
-
file: baseMeta.file,
|
|
192
|
-
line: baseMeta.line,
|
|
214
|
+
file: spanInfo.file !== null && spanInfo.file !== undefined ? spanInfo.file : baseMeta.file,
|
|
215
|
+
line: spanInfo.line !== null && spanInfo.line !== undefined ? spanInfo.line : baseMeta.line,
|
|
216
|
+
sourceFile: spanInfo.sourceFile !== null && spanInfo.sourceFile !== undefined ? spanInfo.sourceFile : baseMeta.sourceFile,
|
|
193
217
|
functionType: baseMeta.functionType || null,
|
|
194
218
|
traceId: traceIdAtExit,
|
|
195
219
|
depth: spanInfo.depth ?? depthAtExit,
|
|
@@ -601,10 +625,14 @@ if (!global.__repro_call) {
|
|
|
601
625
|
const name = (label && label.length) || fn.name
|
|
602
626
|
? (label && label.length ? label : fn.name)
|
|
603
627
|
: '(anonymous)';
|
|
604
|
-
const
|
|
628
|
+
const definitionFile = fn[SYM_SRC_FILE];
|
|
629
|
+
const normalizedCallFile = callFile ? String(callFile).trim() : '';
|
|
630
|
+
const callsiteFile = normalizedCallFile ? normalizedCallFile : null;
|
|
631
|
+
const callsiteLine = Number.isFinite(Number(callLine)) && Number(callLine) > 0 ? Number(callLine) : null;
|
|
605
632
|
const meta = {
|
|
606
|
-
file:
|
|
607
|
-
line:
|
|
633
|
+
file: callsiteFile || definitionFile || null,
|
|
634
|
+
line: callsiteLine,
|
|
635
|
+
sourceFile: definitionFile || null,
|
|
608
636
|
parentSpanId: forcedParentSpanId
|
|
609
637
|
};
|
|
610
638
|
|
|
@@ -638,7 +666,7 @@ if (!global.__repro_call) {
|
|
|
638
666
|
})();
|
|
639
667
|
|
|
640
668
|
const runExit = (detail) => {
|
|
641
|
-
const runner = () => trace.exit({ fn: name, file: meta.file, line: meta.line }, detail);
|
|
669
|
+
const runner = () => trace.exit({ fn: name, file: meta.file, line: meta.line, sourceFile: meta.sourceFile }, detail);
|
|
642
670
|
if (exitStore) return als.run(exitStore, runner);
|
|
643
671
|
return runner();
|
|
644
672
|
};
|
|
@@ -685,7 +713,7 @@ if (!global.__repro_call) {
|
|
|
685
713
|
runExit(exitDetailBase);
|
|
686
714
|
return out;
|
|
687
715
|
} catch (e) {
|
|
688
|
-
trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args });
|
|
716
|
+
trace.exit({ fn: name, file: meta.file, line: meta.line, sourceFile: meta.sourceFile }, { threw: true, error: e, args });
|
|
689
717
|
throw e;
|
|
690
718
|
} finally {
|
|
691
719
|
if (pendingMarker) {
|
|
@@ -713,14 +741,22 @@ if (!global.__repro_call) {
|
|
|
713
741
|
const isolatedStore = isUnawaitedCall
|
|
714
742
|
? (forkAlsStoreForUnawaited(callStoreForArgs || ctx) || cloneStore(callStoreForArgs || ctx))
|
|
715
743
|
: null;
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
744
|
+
try {
|
|
745
|
+
const shouldWrap = !isAsyncLocalContextSetter(fn, thisArg);
|
|
746
|
+
const argsForCall = shouldWrap ? wrapArgsWithStore(args, callStoreForArgs || ctx) : args;
|
|
747
|
+
const normalizedCallFile = callFile ? String(callFile).trim() : '';
|
|
748
|
+
const callsiteFile = normalizedCallFile ? normalizedCallFile : null;
|
|
749
|
+
const callsiteLine = Number.isFinite(Number(callLine)) && Number(callLine) > 0 ? Number(callLine) : null;
|
|
750
|
+
const callsiteStore = isolatedStore || ctx;
|
|
751
|
+
if (callsiteStore && (callsiteFile || callsiteLine !== null)) {
|
|
752
|
+
const queue = callsiteStore.__repro_callsite_queue || (callsiteStore.__repro_callsite_queue = []);
|
|
753
|
+
queue.push({ file: callsiteFile, line: callsiteLine });
|
|
754
|
+
}
|
|
755
|
+
let out;
|
|
756
|
+
if (isolatedStore) {
|
|
757
|
+
als.run(isolatedStore, () => {
|
|
758
|
+
out = fn.apply(thisArg, argsForCall);
|
|
759
|
+
});
|
|
724
760
|
} else {
|
|
725
761
|
out = fn.apply(thisArg, argsForCall);
|
|
726
762
|
}
|