repro-nest 0.0.204 → 0.0.207
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 +68 -28
- package/package.json +1 -1
- package/src/index.ts +63 -24
- package/tracer/runtime.js +35 -7
package/dist/index.js
CHANGED
|
@@ -93,39 +93,76 @@ function flushQueryFinalizers(query, value, threw, error) {
|
|
|
93
93
|
catch { }
|
|
94
94
|
}
|
|
95
95
|
function patchMongooseExecCapture(targetMongoose = mongoose) {
|
|
96
|
+
// Patch Query.prototype.exec to capture resolved results for trace return values.
|
|
96
97
|
try {
|
|
97
98
|
const Qp = targetMongoose?.Query?.prototype;
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
if (Qp && !Qp.__repro_exec_patched) {
|
|
100
|
+
const origExec = Qp.exec;
|
|
101
|
+
if (typeof origExec === 'function') {
|
|
102
|
+
Qp.__repro_exec_patched = true;
|
|
103
|
+
Qp.exec = function reproPatchedExec(...args) {
|
|
104
|
+
try {
|
|
105
|
+
this.__repro_is_query = true;
|
|
106
|
+
}
|
|
107
|
+
catch { }
|
|
108
|
+
const p = origExec.apply(this, args);
|
|
109
|
+
try {
|
|
110
|
+
if (p && typeof p.then === 'function') {
|
|
111
|
+
this.__repro_result_promise = p;
|
|
112
|
+
p.then((res) => {
|
|
113
|
+
try {
|
|
114
|
+
this.__repro_result = res;
|
|
115
|
+
}
|
|
116
|
+
catch { }
|
|
117
|
+
flushQueryFinalizers(this, res, false, null);
|
|
118
|
+
return res;
|
|
119
|
+
}, (err) => {
|
|
120
|
+
flushQueryFinalizers(this, undefined, true, err);
|
|
121
|
+
return err;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch { }
|
|
126
|
+
return p;
|
|
127
|
+
};
|
|
107
128
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch { }
|
|
132
|
+
// Patch Aggregate.prototype.exec as well so aggregation pipelines surface their results in traces.
|
|
133
|
+
try {
|
|
134
|
+
const Ap = targetMongoose?.Aggregate?.prototype;
|
|
135
|
+
if (Ap && !Ap.__repro_agg_exec_patched) {
|
|
136
|
+
const origAggExec = Ap.exec;
|
|
137
|
+
if (typeof origAggExec === 'function') {
|
|
138
|
+
Ap.__repro_agg_exec_patched = true;
|
|
139
|
+
Ap.exec = function reproPatchedAggExec(...args) {
|
|
140
|
+
try {
|
|
141
|
+
this.__repro_is_query = true;
|
|
142
|
+
}
|
|
143
|
+
catch { }
|
|
144
|
+
const p = origAggExec.apply(this, args);
|
|
145
|
+
try {
|
|
146
|
+
if (p && typeof p.then === 'function') {
|
|
147
|
+
this.__repro_result_promise = p;
|
|
148
|
+
p.then((res) => {
|
|
149
|
+
try {
|
|
150
|
+
this.__repro_result = res;
|
|
151
|
+
}
|
|
152
|
+
catch { }
|
|
153
|
+
flushQueryFinalizers(this, res, false, null);
|
|
154
|
+
return res;
|
|
155
|
+
}, (err) => {
|
|
156
|
+
flushQueryFinalizers(this, undefined, true, err);
|
|
157
|
+
return err;
|
|
158
|
+
});
|
|
116
159
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
flushQueryFinalizers(this, undefined, true, err);
|
|
122
|
-
return err;
|
|
123
|
-
});
|
|
124
|
-
}
|
|
160
|
+
}
|
|
161
|
+
catch { }
|
|
162
|
+
return p;
|
|
163
|
+
};
|
|
125
164
|
}
|
|
126
|
-
|
|
127
|
-
return p;
|
|
128
|
-
};
|
|
165
|
+
}
|
|
129
166
|
}
|
|
130
167
|
catch { }
|
|
131
168
|
}
|
|
@@ -1290,6 +1327,9 @@ function reproMiddleware(cfg) {
|
|
|
1290
1327
|
if (ev.args !== undefined) {
|
|
1291
1328
|
evt.args = sanitizeTraceArgs(ev.args);
|
|
1292
1329
|
}
|
|
1330
|
+
if (ev.receiver !== undefined) {
|
|
1331
|
+
evt.receiver = sanitizeTraceValue(ev.receiver);
|
|
1332
|
+
}
|
|
1293
1333
|
if (ev.returnValue !== undefined) {
|
|
1294
1334
|
evt.returnValue = sanitizeTraceValue(ev.returnValue);
|
|
1295
1335
|
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -87,33 +87,68 @@ function flushQueryFinalizers(query: any, value: any, threw: boolean, error: any
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
function patchMongooseExecCapture(targetMongoose: any = mongoose) {
|
|
90
|
+
// Patch Query.prototype.exec to capture resolved results for trace return values.
|
|
90
91
|
try {
|
|
91
92
|
const Qp: any = targetMongoose?.Query?.prototype;
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
93
|
+
if (Qp && !Qp.__repro_exec_patched) {
|
|
94
|
+
const origExec = Qp.exec;
|
|
95
|
+
if (typeof origExec === 'function') {
|
|
96
|
+
Qp.__repro_exec_patched = true;
|
|
97
|
+
Qp.exec = function reproPatchedExec(this: any, ...args: any[]) {
|
|
98
|
+
try { (this as any).__repro_is_query = true; } catch {}
|
|
99
|
+
const p = origExec.apply(this, args);
|
|
100
|
+
try {
|
|
101
|
+
if (p && typeof p.then === 'function') {
|
|
102
|
+
this.__repro_result_promise = p;
|
|
103
|
+
p.then(
|
|
104
|
+
(res: any) => {
|
|
105
|
+
try { this.__repro_result = res; } catch {}
|
|
106
|
+
flushQueryFinalizers(this, res, false, null);
|
|
107
|
+
return res;
|
|
108
|
+
},
|
|
109
|
+
(err: any) => {
|
|
110
|
+
flushQueryFinalizers(this, undefined, true, err);
|
|
111
|
+
return err;
|
|
112
|
+
}
|
|
113
|
+
);
|
|
111
114
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
115
|
+
} catch {}
|
|
116
|
+
return p;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch {}
|
|
121
|
+
|
|
122
|
+
// Patch Aggregate.prototype.exec as well so aggregation pipelines surface their results in traces.
|
|
123
|
+
try {
|
|
124
|
+
const Ap: any = targetMongoose?.Aggregate?.prototype;
|
|
125
|
+
if (Ap && !Ap.__repro_agg_exec_patched) {
|
|
126
|
+
const origAggExec = Ap.exec;
|
|
127
|
+
if (typeof origAggExec === 'function') {
|
|
128
|
+
Ap.__repro_agg_exec_patched = true;
|
|
129
|
+
Ap.exec = function reproPatchedAggExec(this: any, ...args: any[]) {
|
|
130
|
+
try { (this as any).__repro_is_query = true; } catch {}
|
|
131
|
+
const p = origAggExec.apply(this, args);
|
|
132
|
+
try {
|
|
133
|
+
if (p && typeof p.then === 'function') {
|
|
134
|
+
this.__repro_result_promise = p;
|
|
135
|
+
p.then(
|
|
136
|
+
(res: any) => {
|
|
137
|
+
try { this.__repro_result = res; } catch {}
|
|
138
|
+
flushQueryFinalizers(this, res, false, null);
|
|
139
|
+
return res;
|
|
140
|
+
},
|
|
141
|
+
(err: any) => {
|
|
142
|
+
flushQueryFinalizers(this, undefined, true, err);
|
|
143
|
+
return err;
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
} catch {}
|
|
148
|
+
return p;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
117
152
|
} catch {}
|
|
118
153
|
}
|
|
119
154
|
|
|
@@ -175,6 +210,7 @@ type TraceEventRecord = {
|
|
|
175
210
|
spanId?: string | number | null;
|
|
176
211
|
parentSpanId?: string | number | null;
|
|
177
212
|
args?: any;
|
|
213
|
+
receiver?: any;
|
|
178
214
|
returnValue?: any;
|
|
179
215
|
threw?: boolean;
|
|
180
216
|
error?: any;
|
|
@@ -1497,6 +1533,9 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1497
1533
|
if (ev.args !== undefined) {
|
|
1498
1534
|
evt.args = sanitizeTraceArgs(ev.args);
|
|
1499
1535
|
}
|
|
1536
|
+
if (ev.receiver !== undefined) {
|
|
1537
|
+
evt.receiver = sanitizeTraceValue(ev.receiver);
|
|
1538
|
+
}
|
|
1500
1539
|
if (ev.returnValue !== undefined) {
|
|
1501
1540
|
evt.returnValue = sanitizeTraceValue(ev.returnValue);
|
|
1502
1541
|
}
|
package/tracer/runtime.js
CHANGED
|
@@ -132,6 +132,7 @@ const trace = {
|
|
|
132
132
|
traceId: ctx.traceId,
|
|
133
133
|
depth: ctx.depth,
|
|
134
134
|
args: detail?.args,
|
|
135
|
+
receiver: detail?.receiver,
|
|
135
136
|
spanId: span.id,
|
|
136
137
|
parentSpanId: span.parentId
|
|
137
138
|
});
|
|
@@ -159,7 +160,8 @@ const trace = {
|
|
|
159
160
|
returnValue: detail?.returnValue,
|
|
160
161
|
error: detail?.error,
|
|
161
162
|
threw: detail?.threw === true,
|
|
162
|
-
unawaited: detail?.unawaited === true || frameUnawaited
|
|
163
|
+
unawaited: detail?.unawaited === true || frameUnawaited,
|
|
164
|
+
receiver: detail?.receiver
|
|
163
165
|
};
|
|
164
166
|
|
|
165
167
|
const promiseTaggedUnawaited = !!(baseDetail.returnValue && baseDetail.returnValue[SYM_UNAWAITED]);
|
|
@@ -179,6 +181,9 @@ const trace = {
|
|
|
179
181
|
unawaited: overrides.hasOwnProperty('unawaited')
|
|
180
182
|
? overrides.unawaited
|
|
181
183
|
: forceUnawaited,
|
|
184
|
+
receiver: overrides.hasOwnProperty('receiver')
|
|
185
|
+
? overrides.receiver
|
|
186
|
+
: baseDetail.receiver,
|
|
182
187
|
args: overrides.hasOwnProperty('args')
|
|
183
188
|
? overrides.args
|
|
184
189
|
: baseDetail.args
|
|
@@ -199,6 +204,7 @@ const trace = {
|
|
|
199
204
|
threw: finalDetail.threw === true,
|
|
200
205
|
error: finalDetail.error,
|
|
201
206
|
args: finalDetail.args,
|
|
207
|
+
receiver: finalDetail.receiver,
|
|
202
208
|
unawaited: finalDetail.unawaited === true
|
|
203
209
|
});
|
|
204
210
|
};
|
|
@@ -475,6 +481,24 @@ function forkAlsStoreForUnawaited(baseStore) {
|
|
|
475
481
|
return cloned;
|
|
476
482
|
}
|
|
477
483
|
|
|
484
|
+
// Only capture receiver/collection snapshots for common array iteration helpers to keep noise low.
|
|
485
|
+
const RECEIVER_METHOD_NAMES = new Set([
|
|
486
|
+
// Array iterators
|
|
487
|
+
'map', 'forEach', 'filter', 'find', 'findIndex', 'findLast', 'findLastIndex',
|
|
488
|
+
'some', 'every', 'reduce', 'reduceRight', 'flatMap', 'flat',
|
|
489
|
+
// Set / Map mutators
|
|
490
|
+
'add', 'delete', 'clear', 'set'
|
|
491
|
+
]);
|
|
492
|
+
|
|
493
|
+
function shouldCaptureReceiver(label, receiver) {
|
|
494
|
+
if (!label || receiver === null || receiver === undefined) return false;
|
|
495
|
+
const method = String(label).split('.').pop() || '';
|
|
496
|
+
if (!RECEIVER_METHOD_NAMES.has(method)) return false;
|
|
497
|
+
if (Array.isArray(receiver)) return true;
|
|
498
|
+
if (typeof receiver === 'object' && typeof receiver[Symbol.iterator] === 'function') return true;
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
|
|
478
502
|
// ========= Generic call-site shim (used by Babel transform) =========
|
|
479
503
|
// Decides whether to emit a top-level event based on callee origin tags.
|
|
480
504
|
// No hardcoded library names or file paths.
|
|
@@ -596,13 +620,15 @@ if (!global.__repro_call) {
|
|
|
596
620
|
? (label && label.length ? label : fn.name)
|
|
597
621
|
: '(anonymous)';
|
|
598
622
|
const sourceFile = fn[SYM_SRC_FILE];
|
|
623
|
+
const receiverForTrace = shouldCaptureReceiver(label, thisArg) ? thisArg : undefined;
|
|
599
624
|
const meta = {
|
|
600
|
-
file
|
|
601
|
-
|
|
625
|
+
// Prefer callsite file/line so traces point to where the function was invoked.
|
|
626
|
+
file: callFile || sourceFile || null,
|
|
627
|
+
line: callLine ?? null,
|
|
602
628
|
parentSpanId: forcedParentSpanId
|
|
603
629
|
};
|
|
604
630
|
|
|
605
|
-
trace.enter(name, meta, { args });
|
|
631
|
+
trace.enter(name, meta, { args, receiver: receiverForTrace });
|
|
606
632
|
// After entering, snapshot a clean store that captures the parent + this call’s span,
|
|
607
633
|
// so callbacks invoked during the callee run are isolated per invocation.
|
|
608
634
|
const snapshotForArgs = cloneStore(als.getStore());
|
|
@@ -617,7 +643,8 @@ if (!global.__repro_call) {
|
|
|
617
643
|
const exitDetailBase = {
|
|
618
644
|
returnValue: out,
|
|
619
645
|
args,
|
|
620
|
-
unawaited: shouldForceExit
|
|
646
|
+
unawaited: shouldForceExit,
|
|
647
|
+
receiver: receiverForTrace
|
|
621
648
|
};
|
|
622
649
|
|
|
623
650
|
if (shouldForceExit) markPromiseUnawaited(out);
|
|
@@ -659,7 +686,8 @@ if (!global.__repro_call) {
|
|
|
659
686
|
args,
|
|
660
687
|
threw,
|
|
661
688
|
error,
|
|
662
|
-
unawaited: shouldForceExit
|
|
689
|
+
unawaited: shouldForceExit,
|
|
690
|
+
receiver: receiverForTrace
|
|
663
691
|
};
|
|
664
692
|
runExit(detail);
|
|
665
693
|
return value;
|
|
@@ -679,7 +707,7 @@ if (!global.__repro_call) {
|
|
|
679
707
|
runExit(exitDetailBase);
|
|
680
708
|
return out;
|
|
681
709
|
} catch (e) {
|
|
682
|
-
trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args });
|
|
710
|
+
trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args, receiver: receiverForTrace });
|
|
683
711
|
throw e;
|
|
684
712
|
} finally {
|
|
685
713
|
if (pendingMarker) {
|