repro-nest 0.0.208 → 0.0.210
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 +7 -5
- package/dist/index.js +120 -36
- package/package.json +1 -1
- package/src/index.ts +126 -40
- package/tracer/index.js +2 -0
- package/tracer/runtime.js +68 -46
package/dist/index.d.ts
CHANGED
|
@@ -25,17 +25,19 @@
|
|
|
25
25
|
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
26
26
|
import type { Request, Response, NextFunction } from 'express';
|
|
27
27
|
import type { Schema } from 'mongoose';
|
|
28
|
+
type SpanContext = {
|
|
29
|
+
traceId: string | null;
|
|
30
|
+
spanId: string | number | null;
|
|
31
|
+
parentSpanId: string | number | null;
|
|
32
|
+
depth: number | null;
|
|
33
|
+
};
|
|
28
34
|
type TracerApi = {
|
|
29
35
|
init?: (opts: any) => void;
|
|
30
36
|
tracer?: {
|
|
31
37
|
on: (fn: (ev: any) => void) => () => void;
|
|
32
|
-
getCurrentTraceContext?: () => {
|
|
33
|
-
traceId: any;
|
|
34
|
-
spanId: any;
|
|
35
|
-
depth?: number;
|
|
36
|
-
};
|
|
37
38
|
};
|
|
38
39
|
getCurrentTraceId?: () => string | null;
|
|
40
|
+
getCurrentSpanContext?: () => SpanContext | null;
|
|
39
41
|
patchHttp?: () => void;
|
|
40
42
|
setFunctionLogsEnabled?: (enabled: boolean) => void;
|
|
41
43
|
};
|
package/dist/index.js
CHANGED
|
@@ -439,13 +439,6 @@ 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 { }
|
|
449
442
|
applyTraceLogPreference(tracerPkg);
|
|
450
443
|
__TRACER_READY = true;
|
|
451
444
|
patchAllKnownMongooseInstances();
|
|
@@ -466,6 +459,52 @@ exports.initReproTracing = initReproTracing;
|
|
|
466
459
|
/** Optional helper if users want to check it. */
|
|
467
460
|
function isReproTracingEnabled() { return __TRACER_READY; }
|
|
468
461
|
exports.isReproTracingEnabled = isReproTracingEnabled;
|
|
462
|
+
function captureSpanContext(source) {
|
|
463
|
+
try {
|
|
464
|
+
const fromSource = source && source.__repro_span_context;
|
|
465
|
+
if (fromSource) {
|
|
466
|
+
const span = {
|
|
467
|
+
traceId: fromSource.traceId ?? null,
|
|
468
|
+
spanId: fromSource.spanId ?? null,
|
|
469
|
+
parentSpanId: fromSource.parentSpanId ?? null,
|
|
470
|
+
depth: fromSource.depth ?? null,
|
|
471
|
+
};
|
|
472
|
+
return span;
|
|
473
|
+
}
|
|
474
|
+
const ctx = __TRACER__?.getCurrentSpanContext?.();
|
|
475
|
+
if (ctx) {
|
|
476
|
+
const span = {
|
|
477
|
+
traceId: ctx.traceId ?? __TRACER__?.getCurrentTraceId?.() ?? null,
|
|
478
|
+
spanId: ctx.spanId ?? null,
|
|
479
|
+
parentSpanId: ctx.parentSpanId ?? null,
|
|
480
|
+
depth: ctx.depth ?? null,
|
|
481
|
+
};
|
|
482
|
+
if (span.traceId || span.spanId !== null || span.parentSpanId !== null) {
|
|
483
|
+
return span;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
else if (__TRACER__?.getCurrentTraceId) {
|
|
487
|
+
const traceId = __TRACER__?.getCurrentTraceId?.() ?? null;
|
|
488
|
+
if (traceId) {
|
|
489
|
+
return { traceId, spanId: null, parentSpanId: null, depth: null };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
catch { }
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
function attachSpanContext(target, spanSource, fallbackSource) {
|
|
497
|
+
if (!target)
|
|
498
|
+
return target;
|
|
499
|
+
const ctx = spanSource ?? captureSpanContext(fallbackSource);
|
|
500
|
+
if (ctx) {
|
|
501
|
+
try {
|
|
502
|
+
target.spanContext = ctx;
|
|
503
|
+
}
|
|
504
|
+
catch { }
|
|
505
|
+
}
|
|
506
|
+
return target;
|
|
507
|
+
}
|
|
469
508
|
const als = new async_hooks_1.AsyncLocalStorage();
|
|
470
509
|
const getCtx = () => als.getStore() || {};
|
|
471
510
|
function currentClockSkewMs() {
|
|
@@ -807,8 +846,7 @@ const SESSION_DRAIN_TIMEOUT_MS = (() => {
|
|
|
807
846
|
if (Number.isFinite(env) && env >= 0)
|
|
808
847
|
return env;
|
|
809
848
|
// Bound wait for draining sessions to avoid lost flushes when a request hangs.
|
|
810
|
-
|
|
811
|
-
return 60000;
|
|
849
|
+
return 10000;
|
|
812
850
|
})();
|
|
813
851
|
function isThenable(value) {
|
|
814
852
|
return value != null && typeof value === 'object' && typeof value.then === 'function';
|
|
@@ -1335,9 +1373,6 @@ function reproMiddleware(cfg) {
|
|
|
1335
1373
|
if (ev.args !== undefined) {
|
|
1336
1374
|
evt.args = sanitizeTraceArgs(ev.args);
|
|
1337
1375
|
}
|
|
1338
|
-
if (ev.receiver !== undefined) {
|
|
1339
|
-
evt.receiver = sanitizeTraceValue(ev.receiver);
|
|
1340
|
-
}
|
|
1341
1376
|
if (ev.returnValue !== undefined) {
|
|
1342
1377
|
evt.returnValue = sanitizeTraceValue(ev.returnValue);
|
|
1343
1378
|
}
|
|
@@ -1547,6 +1582,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1547
1582
|
wasNew: this.isNew,
|
|
1548
1583
|
before,
|
|
1549
1584
|
collection: resolveCollectionOrWarn(this, 'doc'),
|
|
1585
|
+
spanContext: captureSpanContext(this),
|
|
1550
1586
|
};
|
|
1551
1587
|
next();
|
|
1552
1588
|
});
|
|
@@ -1560,13 +1596,21 @@ function reproMongoosePlugin(cfg) {
|
|
|
1560
1596
|
const before = meta.before ?? null;
|
|
1561
1597
|
const after = this.toObject({ depopulate: true });
|
|
1562
1598
|
const collection = meta.collection || resolveCollectionOrWarn(this, 'doc');
|
|
1599
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1563
1600
|
const query = meta.wasNew
|
|
1564
1601
|
? { op: 'insertOne', doc: after }
|
|
1565
1602
|
: { filter: { _id: this._id }, update: buildMinimalUpdate(before, after), options: { upsert: false } };
|
|
1566
1603
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
|
|
1567
1604
|
entries: [{
|
|
1568
1605
|
actionId: getCtx().aid,
|
|
1569
|
-
db: [{
|
|
1606
|
+
db: [attachSpanContext({
|
|
1607
|
+
collection,
|
|
1608
|
+
pk: { _id: this._id },
|
|
1609
|
+
before,
|
|
1610
|
+
after,
|
|
1611
|
+
op: meta.wasNew ? 'insert' : 'update',
|
|
1612
|
+
query,
|
|
1613
|
+
}, spanContext)],
|
|
1570
1614
|
t: alignedNow(),
|
|
1571
1615
|
}]
|
|
1572
1616
|
});
|
|
@@ -1582,6 +1626,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1582
1626
|
this.__repro_before = await model.findOne(filter).lean().exec();
|
|
1583
1627
|
this.setOptions({ new: true });
|
|
1584
1628
|
this.__repro_collection = resolveCollectionOrWarn(this, 'query');
|
|
1629
|
+
this.__repro_spanContext = captureSpanContext(this);
|
|
1585
1630
|
}
|
|
1586
1631
|
catch { }
|
|
1587
1632
|
next();
|
|
@@ -1593,11 +1638,18 @@ function reproMongoosePlugin(cfg) {
|
|
|
1593
1638
|
const before = this.__repro_before ?? null;
|
|
1594
1639
|
const after = res ?? null;
|
|
1595
1640
|
const collection = this.__repro_collection || resolveCollectionOrWarn(this, 'query');
|
|
1641
|
+
const spanContext = this.__repro_spanContext || captureSpanContext(this);
|
|
1596
1642
|
const pk = after?._id ?? before?._id;
|
|
1597
1643
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
|
|
1598
1644
|
entries: [{
|
|
1599
1645
|
actionId: getCtx().aid,
|
|
1600
|
-
db: [{
|
|
1646
|
+
db: [attachSpanContext({
|
|
1647
|
+
collection,
|
|
1648
|
+
pk: { _id: pk },
|
|
1649
|
+
before,
|
|
1650
|
+
after,
|
|
1651
|
+
op: after && before ? 'update' : after ? 'insert' : 'update',
|
|
1652
|
+
}, spanContext)],
|
|
1601
1653
|
t: alignedNow()
|
|
1602
1654
|
}]
|
|
1603
1655
|
});
|
|
@@ -1612,6 +1664,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1612
1664
|
this.__repro_before = await this.model.findOne(filter).lean().exec();
|
|
1613
1665
|
this.__repro_collection = resolveCollectionOrWarn(this, 'query');
|
|
1614
1666
|
this.__repro_filter = filter;
|
|
1667
|
+
this.__repro_spanContext = captureSpanContext(this);
|
|
1615
1668
|
}
|
|
1616
1669
|
catch { }
|
|
1617
1670
|
next();
|
|
@@ -1625,10 +1678,18 @@ function reproMongoosePlugin(cfg) {
|
|
|
1625
1678
|
return;
|
|
1626
1679
|
const collection = this.__repro_collection || resolveCollectionOrWarn(this, 'query');
|
|
1627
1680
|
const filter = this.__repro_filter ?? { _id: before._id };
|
|
1681
|
+
const spanContext = this.__repro_spanContext || captureSpanContext(this);
|
|
1628
1682
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
|
|
1629
1683
|
entries: [{
|
|
1630
1684
|
actionId: getCtx().aid,
|
|
1631
|
-
db: [{
|
|
1685
|
+
db: [attachSpanContext({
|
|
1686
|
+
collection,
|
|
1687
|
+
pk: { _id: before._id },
|
|
1688
|
+
before,
|
|
1689
|
+
after: null,
|
|
1690
|
+
op: 'delete',
|
|
1691
|
+
query: { filter },
|
|
1692
|
+
}, spanContext)],
|
|
1632
1693
|
t: alignedNow()
|
|
1633
1694
|
}]
|
|
1634
1695
|
});
|
|
@@ -1666,6 +1727,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1666
1727
|
t0: Date.now(),
|
|
1667
1728
|
collection: this?.model?.collection?.name || 'unknown',
|
|
1668
1729
|
op,
|
|
1730
|
+
spanContext: captureSpanContext(this),
|
|
1669
1731
|
filter: sanitizeDbValue(this.getFilter?.() ?? this._conditions ?? undefined),
|
|
1670
1732
|
update: sanitizeDbValue(this.getUpdate?.() ?? this._update ?? undefined),
|
|
1671
1733
|
projection: sanitizeDbValue(this.projection?.() ?? this._fields ?? undefined),
|
|
@@ -1673,7 +1735,12 @@ function reproMongoosePlugin(cfg) {
|
|
|
1673
1735
|
};
|
|
1674
1736
|
}
|
|
1675
1737
|
catch {
|
|
1676
|
-
this.__repro_qmeta = {
|
|
1738
|
+
this.__repro_qmeta = {
|
|
1739
|
+
t0: Date.now(),
|
|
1740
|
+
collection: 'unknown',
|
|
1741
|
+
op,
|
|
1742
|
+
spanContext: captureSpanContext(this),
|
|
1743
|
+
};
|
|
1677
1744
|
}
|
|
1678
1745
|
next();
|
|
1679
1746
|
});
|
|
@@ -1683,6 +1750,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1683
1750
|
return;
|
|
1684
1751
|
const meta = this.__repro_qmeta || { t0: Date.now(), collection: 'unknown', op };
|
|
1685
1752
|
const resultMeta = summarizeQueryResult(op, res);
|
|
1753
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1686
1754
|
emitDbQuery(cfg, sid, aid, {
|
|
1687
1755
|
collection: meta.collection,
|
|
1688
1756
|
op,
|
|
@@ -1690,6 +1758,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1690
1758
|
resultMeta,
|
|
1691
1759
|
durMs: Date.now() - meta.t0,
|
|
1692
1760
|
t: alignedNow(),
|
|
1761
|
+
spanContext,
|
|
1693
1762
|
});
|
|
1694
1763
|
});
|
|
1695
1764
|
}
|
|
@@ -1702,10 +1771,15 @@ function reproMongoosePlugin(cfg) {
|
|
|
1702
1771
|
t0: Date.now(),
|
|
1703
1772
|
collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
|
|
1704
1773
|
docs: sanitizeDbValue(docs),
|
|
1774
|
+
spanContext: captureSpanContext(this),
|
|
1705
1775
|
};
|
|
1706
1776
|
}
|
|
1707
1777
|
catch {
|
|
1708
|
-
this.__repro_insert_meta = {
|
|
1778
|
+
this.__repro_insert_meta = {
|
|
1779
|
+
t0: Date.now(),
|
|
1780
|
+
collection: 'unknown',
|
|
1781
|
+
spanContext: captureSpanContext(this),
|
|
1782
|
+
};
|
|
1709
1783
|
}
|
|
1710
1784
|
next();
|
|
1711
1785
|
});
|
|
@@ -1715,6 +1789,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1715
1789
|
return;
|
|
1716
1790
|
const meta = this.__repro_insert_meta || { t0: Date.now(), collection: 'unknown' };
|
|
1717
1791
|
const resultMeta = Array.isArray(docs) ? { inserted: docs.length } : summarizeQueryResult('insertMany', docs);
|
|
1792
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1718
1793
|
emitDbQuery(cfg, sid, aid, {
|
|
1719
1794
|
collection: meta.collection,
|
|
1720
1795
|
op: 'insertMany',
|
|
@@ -1722,6 +1797,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1722
1797
|
resultMeta,
|
|
1723
1798
|
durMs: Date.now() - meta.t0,
|
|
1724
1799
|
t: alignedNow(),
|
|
1800
|
+
spanContext,
|
|
1725
1801
|
});
|
|
1726
1802
|
});
|
|
1727
1803
|
schema.pre('bulkWrite', { document: false, query: false }, function (next, ops) {
|
|
@@ -1730,10 +1806,15 @@ function reproMongoosePlugin(cfg) {
|
|
|
1730
1806
|
t0: Date.now(),
|
|
1731
1807
|
collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
|
|
1732
1808
|
ops: sanitizeDbValue(ops),
|
|
1809
|
+
spanContext: captureSpanContext(this),
|
|
1733
1810
|
};
|
|
1734
1811
|
}
|
|
1735
1812
|
catch {
|
|
1736
|
-
this.__repro_bulk_meta = {
|
|
1813
|
+
this.__repro_bulk_meta = {
|
|
1814
|
+
t0: Date.now(),
|
|
1815
|
+
collection: 'unknown',
|
|
1816
|
+
spanContext: captureSpanContext(this),
|
|
1817
|
+
};
|
|
1737
1818
|
}
|
|
1738
1819
|
next();
|
|
1739
1820
|
});
|
|
@@ -1744,6 +1825,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1744
1825
|
const meta = this.__repro_bulk_meta || { t0: Date.now(), collection: 'unknown' };
|
|
1745
1826
|
const bulkResult = summarizeBulkResult(res);
|
|
1746
1827
|
const resultMeta = { ...bulkResult, result: sanitizeResultForMeta(res?.result ?? res) };
|
|
1828
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1747
1829
|
emitDbQuery(cfg, sid, aid, {
|
|
1748
1830
|
collection: meta.collection,
|
|
1749
1831
|
op: 'bulkWrite',
|
|
@@ -1751,6 +1833,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1751
1833
|
resultMeta,
|
|
1752
1834
|
durMs: Date.now() - meta.t0,
|
|
1753
1835
|
t: alignedNow(),
|
|
1836
|
+
spanContext,
|
|
1754
1837
|
});
|
|
1755
1838
|
});
|
|
1756
1839
|
// Aggregate middleware (non-intrusive)
|
|
@@ -1762,11 +1845,17 @@ function reproMongoosePlugin(cfg) {
|
|
|
1762
1845
|
this?._model?.collection?.name ||
|
|
1763
1846
|
(this?.model && this.model.collection?.name) ||
|
|
1764
1847
|
'unknown',
|
|
1848
|
+
spanContext: captureSpanContext(this),
|
|
1765
1849
|
pipeline: sanitizeDbValue(this.pipeline?.() ?? this._pipeline ?? undefined),
|
|
1766
1850
|
};
|
|
1767
1851
|
}
|
|
1768
1852
|
catch {
|
|
1769
|
-
this.__repro_aggmeta = {
|
|
1853
|
+
this.__repro_aggmeta = {
|
|
1854
|
+
t0: Date.now(),
|
|
1855
|
+
collection: 'unknown',
|
|
1856
|
+
pipeline: undefined,
|
|
1857
|
+
spanContext: captureSpanContext(this),
|
|
1858
|
+
};
|
|
1770
1859
|
}
|
|
1771
1860
|
next();
|
|
1772
1861
|
});
|
|
@@ -1776,6 +1865,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1776
1865
|
return;
|
|
1777
1866
|
const meta = this.__repro_aggmeta || { t0: Date.now(), collection: 'unknown' };
|
|
1778
1867
|
const resultMeta = summarizeQueryResult('aggregate', res);
|
|
1868
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1779
1869
|
emitDbQuery(cfg, sid, aid, {
|
|
1780
1870
|
collection: meta.collection,
|
|
1781
1871
|
op: 'aggregate',
|
|
@@ -1783,6 +1873,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
1783
1873
|
resultMeta,
|
|
1784
1874
|
durMs: Date.now() - meta.t0,
|
|
1785
1875
|
t: alignedNow(),
|
|
1876
|
+
spanContext,
|
|
1786
1877
|
});
|
|
1787
1878
|
});
|
|
1788
1879
|
};
|
|
@@ -1899,26 +1990,19 @@ function dehydrateComplexValue(value) {
|
|
|
1899
1990
|
function emitDbQuery(cfg, sid, aid, payload) {
|
|
1900
1991
|
if (!sid)
|
|
1901
1992
|
return;
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1993
|
+
const dbEntry = attachSpanContext({
|
|
1994
|
+
collection: payload.collection,
|
|
1995
|
+
op: payload.op,
|
|
1996
|
+
query: payload.query ?? undefined,
|
|
1997
|
+
resultMeta: payload.resultMeta ?? undefined,
|
|
1998
|
+
durMs: payload.durMs ?? undefined,
|
|
1999
|
+
pk: null, before: null, after: null,
|
|
2000
|
+
error: payload.error ?? undefined,
|
|
2001
|
+
}, payload?.spanContext);
|
|
1908
2002
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
|
|
1909
2003
|
entries: [{
|
|
1910
2004
|
actionId: aid ?? null,
|
|
1911
|
-
db: [
|
|
1912
|
-
collection: payload.collection,
|
|
1913
|
-
op: payload.op,
|
|
1914
|
-
query: payload.query ?? undefined,
|
|
1915
|
-
resultMeta: payload.resultMeta ?? undefined,
|
|
1916
|
-
durMs: payload.durMs ?? undefined,
|
|
1917
|
-
traceId: traceCtx?.traceId ?? null,
|
|
1918
|
-
spanId: traceCtx?.spanId ?? null,
|
|
1919
|
-
pk: null, before: null, after: null,
|
|
1920
|
-
error: payload.error ?? undefined,
|
|
1921
|
-
}],
|
|
2005
|
+
db: [dbEntry],
|
|
1922
2006
|
t: payload.t,
|
|
1923
2007
|
}]
|
|
1924
2008
|
});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -172,13 +172,18 @@ function patchAllKnownMongooseInstances() {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// ====== tiny, safe tracer auto-init (no node_modules patches) ======
|
|
175
|
+
type SpanContext = {
|
|
176
|
+
traceId: string | null;
|
|
177
|
+
spanId: string | number | null;
|
|
178
|
+
parentSpanId: string | number | null;
|
|
179
|
+
depth: number | null;
|
|
180
|
+
};
|
|
181
|
+
|
|
175
182
|
type TracerApi = {
|
|
176
183
|
init?: (opts: any) => void;
|
|
177
|
-
tracer?: {
|
|
178
|
-
on: (fn: (ev: any) => void) => () => void;
|
|
179
|
-
getCurrentTraceContext?: () => { traceId: any; spanId: any; depth?: number };
|
|
180
|
-
};
|
|
184
|
+
tracer?: { on: (fn: (ev: any) => void) => () => void };
|
|
181
185
|
getCurrentTraceId?: () => string | null;
|
|
186
|
+
getCurrentSpanContext?: () => SpanContext | null;
|
|
182
187
|
patchHttp?: () => void; // optional in your tracer
|
|
183
188
|
setFunctionLogsEnabled?: (enabled: boolean) => void;
|
|
184
189
|
};
|
|
@@ -213,7 +218,6 @@ type TraceEventRecord = {
|
|
|
213
218
|
spanId?: string | number | null;
|
|
214
219
|
parentSpanId?: string | number | null;
|
|
215
220
|
args?: any;
|
|
216
|
-
receiver?: any;
|
|
217
221
|
returnValue?: any;
|
|
218
222
|
threw?: boolean;
|
|
219
223
|
error?: any;
|
|
@@ -626,12 +630,6 @@ export function initReproTracing(opts?: ReproTracingInitOptions) {
|
|
|
626
630
|
const initOpts = { ...defaultTracerInitOpts(), ...(rest as TracerInitOpts) };
|
|
627
631
|
tracerPkg.init?.(initOpts);
|
|
628
632
|
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 {}
|
|
635
633
|
applyTraceLogPreference(tracerPkg);
|
|
636
634
|
__TRACER_READY = true;
|
|
637
635
|
patchAllKnownMongooseInstances();
|
|
@@ -650,6 +648,49 @@ export function initReproTracing(opts?: ReproTracingInitOptions) {
|
|
|
650
648
|
/** Optional helper if users want to check it. */
|
|
651
649
|
export function isReproTracingEnabled() { return __TRACER_READY; }
|
|
652
650
|
|
|
651
|
+
function captureSpanContext(source?: any): SpanContext | null {
|
|
652
|
+
try {
|
|
653
|
+
const fromSource = source && source.__repro_span_context;
|
|
654
|
+
if (fromSource) {
|
|
655
|
+
const span: SpanContext = {
|
|
656
|
+
traceId: fromSource.traceId ?? null,
|
|
657
|
+
spanId: fromSource.spanId ?? null,
|
|
658
|
+
parentSpanId: fromSource.parentSpanId ?? null,
|
|
659
|
+
depth: fromSource.depth ?? null,
|
|
660
|
+
};
|
|
661
|
+
return span;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const ctx = __TRACER__?.getCurrentSpanContext?.();
|
|
665
|
+
if (ctx) {
|
|
666
|
+
const span: SpanContext = {
|
|
667
|
+
traceId: ctx.traceId ?? __TRACER__?.getCurrentTraceId?.() ?? null,
|
|
668
|
+
spanId: ctx.spanId ?? null,
|
|
669
|
+
parentSpanId: ctx.parentSpanId ?? null,
|
|
670
|
+
depth: ctx.depth ?? null,
|
|
671
|
+
};
|
|
672
|
+
if (span.traceId || span.spanId !== null || span.parentSpanId !== null) {
|
|
673
|
+
return span;
|
|
674
|
+
}
|
|
675
|
+
} else if (__TRACER__?.getCurrentTraceId) {
|
|
676
|
+
const traceId = __TRACER__?.getCurrentTraceId?.() ?? null;
|
|
677
|
+
if (traceId) {
|
|
678
|
+
return { traceId, spanId: null, parentSpanId: null, depth: null };
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
} catch {}
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
function attachSpanContext<T extends Record<string, any>>(target: T, spanSource?: SpanContext | null, fallbackSource?: any): T {
|
|
686
|
+
if (!target) return target;
|
|
687
|
+
const ctx = spanSource ?? captureSpanContext(fallbackSource);
|
|
688
|
+
if (ctx) {
|
|
689
|
+
try { (target as any).spanContext = ctx; } catch {}
|
|
690
|
+
}
|
|
691
|
+
return target;
|
|
692
|
+
}
|
|
693
|
+
|
|
653
694
|
type Ctx = { sid?: string; aid?: string; clockSkewMs?: number };
|
|
654
695
|
const als = new AsyncLocalStorage<Ctx>();
|
|
655
696
|
const getCtx = () => als.getStore() || {};
|
|
@@ -1033,8 +1074,7 @@ const SESSION_DRAIN_TIMEOUT_MS = (() => {
|
|
|
1033
1074
|
const env = Number(process.env.SESSION_DRAIN_TIMEOUT_MS);
|
|
1034
1075
|
if (Number.isFinite(env) && env >= 0) return env;
|
|
1035
1076
|
// Bound wait for draining sessions to avoid lost flushes when a request hangs.
|
|
1036
|
-
|
|
1037
|
-
return 60000;
|
|
1077
|
+
return 10000;
|
|
1038
1078
|
})();
|
|
1039
1079
|
|
|
1040
1080
|
function isThenable(value: any): value is PromiseLike<any> {
|
|
@@ -1543,9 +1583,6 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1543
1583
|
if (ev.args !== undefined) {
|
|
1544
1584
|
evt.args = sanitizeTraceArgs(ev.args);
|
|
1545
1585
|
}
|
|
1546
|
-
if (ev.receiver !== undefined) {
|
|
1547
|
-
evt.receiver = sanitizeTraceValue(ev.receiver);
|
|
1548
|
-
}
|
|
1549
1586
|
if (ev.returnValue !== undefined) {
|
|
1550
1587
|
evt.returnValue = sanitizeTraceValue(ev.returnValue);
|
|
1551
1588
|
}
|
|
@@ -1759,6 +1796,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1759
1796
|
wasNew: this.isNew,
|
|
1760
1797
|
before,
|
|
1761
1798
|
collection: resolveCollectionOrWarn(this, 'doc'),
|
|
1799
|
+
spanContext: captureSpanContext(this),
|
|
1762
1800
|
};
|
|
1763
1801
|
next();
|
|
1764
1802
|
});
|
|
@@ -1772,6 +1810,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1772
1810
|
const before = meta.before ?? null;
|
|
1773
1811
|
const after = this.toObject({ depopulate: true });
|
|
1774
1812
|
const collection = meta.collection || resolveCollectionOrWarn(this, 'doc');
|
|
1813
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1775
1814
|
|
|
1776
1815
|
const query = meta.wasNew
|
|
1777
1816
|
? { op: 'insertOne', doc: after }
|
|
@@ -1780,7 +1819,14 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1780
1819
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
|
|
1781
1820
|
entries: [{
|
|
1782
1821
|
actionId: (getCtx() as Ctx).aid!,
|
|
1783
|
-
db: [{
|
|
1822
|
+
db: [attachSpanContext({
|
|
1823
|
+
collection,
|
|
1824
|
+
pk: { _id: (this as any)._id },
|
|
1825
|
+
before,
|
|
1826
|
+
after,
|
|
1827
|
+
op: meta.wasNew ? 'insert' : 'update',
|
|
1828
|
+
query,
|
|
1829
|
+
}, spanContext)],
|
|
1784
1830
|
t: alignedNow(),
|
|
1785
1831
|
}]
|
|
1786
1832
|
});
|
|
@@ -1796,6 +1842,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1796
1842
|
(this as any).__repro_before = await model.findOne(filter).lean().exec();
|
|
1797
1843
|
this.setOptions({ new: true });
|
|
1798
1844
|
(this as any).__repro_collection = resolveCollectionOrWarn(this, 'query');
|
|
1845
|
+
(this as any).__repro_spanContext = captureSpanContext(this);
|
|
1799
1846
|
} catch {}
|
|
1800
1847
|
next();
|
|
1801
1848
|
});
|
|
@@ -1807,12 +1854,19 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1807
1854
|
const before = (this as any).__repro_before ?? null;
|
|
1808
1855
|
const after = res ?? null;
|
|
1809
1856
|
const collection = (this as any).__repro_collection || resolveCollectionOrWarn(this, 'query');
|
|
1857
|
+
const spanContext = (this as any).__repro_spanContext || captureSpanContext(this);
|
|
1810
1858
|
const pk = after?._id ?? before?._id;
|
|
1811
1859
|
|
|
1812
1860
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
|
|
1813
1861
|
entries: [{
|
|
1814
1862
|
actionId: (getCtx() as Ctx).aid!,
|
|
1815
|
-
db: [{
|
|
1863
|
+
db: [attachSpanContext({
|
|
1864
|
+
collection,
|
|
1865
|
+
pk: { _id: pk },
|
|
1866
|
+
before,
|
|
1867
|
+
after,
|
|
1868
|
+
op: after && before ? 'update' : after ? 'insert' : 'update',
|
|
1869
|
+
}, spanContext)],
|
|
1816
1870
|
t: alignedNow()
|
|
1817
1871
|
}]
|
|
1818
1872
|
});
|
|
@@ -1826,6 +1880,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1826
1880
|
(this as any).__repro_before = await (this.model as Model<any>).findOne(filter).lean().exec();
|
|
1827
1881
|
(this as any).__repro_collection = resolveCollectionOrWarn(this, 'query');
|
|
1828
1882
|
(this as any).__repro_filter = filter;
|
|
1883
|
+
(this as any).__repro_spanContext = captureSpanContext(this);
|
|
1829
1884
|
} catch {}
|
|
1830
1885
|
next();
|
|
1831
1886
|
});
|
|
@@ -1836,10 +1891,18 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1836
1891
|
if (!before) return;
|
|
1837
1892
|
const collection = (this as any).__repro_collection || resolveCollectionOrWarn(this, 'query');
|
|
1838
1893
|
const filter = (this as any).__repro_filter ?? { _id: before._id };
|
|
1894
|
+
const spanContext = (this as any).__repro_spanContext || captureSpanContext(this);
|
|
1839
1895
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
|
|
1840
1896
|
entries: [{
|
|
1841
1897
|
actionId: (getCtx() as Ctx).aid!,
|
|
1842
|
-
db: [{
|
|
1898
|
+
db: [attachSpanContext({
|
|
1899
|
+
collection,
|
|
1900
|
+
pk: { _id: before._id },
|
|
1901
|
+
before,
|
|
1902
|
+
after: null,
|
|
1903
|
+
op: 'delete',
|
|
1904
|
+
query: { filter },
|
|
1905
|
+
}, spanContext)],
|
|
1843
1906
|
t: alignedNow()
|
|
1844
1907
|
}]
|
|
1845
1908
|
});
|
|
@@ -1881,13 +1944,19 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1881
1944
|
t0: Date.now(),
|
|
1882
1945
|
collection: this?.model?.collection?.name || 'unknown',
|
|
1883
1946
|
op,
|
|
1947
|
+
spanContext: captureSpanContext(this),
|
|
1884
1948
|
filter: sanitizeDbValue(this.getFilter?.() ?? this._conditions ?? undefined),
|
|
1885
1949
|
update: sanitizeDbValue(this.getUpdate?.() ?? this._update ?? undefined),
|
|
1886
1950
|
projection: sanitizeDbValue(this.projection?.() ?? this._fields ?? undefined),
|
|
1887
1951
|
options: sanitizeDbValue(this.getOptions?.() ?? this.options ?? undefined),
|
|
1888
1952
|
};
|
|
1889
1953
|
} catch {
|
|
1890
|
-
(this as any).__repro_qmeta = {
|
|
1954
|
+
(this as any).__repro_qmeta = {
|
|
1955
|
+
t0: Date.now(),
|
|
1956
|
+
collection: 'unknown',
|
|
1957
|
+
op,
|
|
1958
|
+
spanContext: captureSpanContext(this),
|
|
1959
|
+
};
|
|
1891
1960
|
}
|
|
1892
1961
|
next();
|
|
1893
1962
|
});
|
|
@@ -1898,6 +1967,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1898
1967
|
|
|
1899
1968
|
const meta = (this as any).__repro_qmeta || { t0: Date.now(), collection: 'unknown', op };
|
|
1900
1969
|
const resultMeta = summarizeQueryResult(op, res);
|
|
1970
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1901
1971
|
|
|
1902
1972
|
emitDbQuery(cfg, sid, aid, {
|
|
1903
1973
|
collection: meta.collection,
|
|
@@ -1906,6 +1976,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1906
1976
|
resultMeta,
|
|
1907
1977
|
durMs: Date.now() - meta.t0,
|
|
1908
1978
|
t: alignedNow(),
|
|
1979
|
+
spanContext,
|
|
1909
1980
|
});
|
|
1910
1981
|
});
|
|
1911
1982
|
}
|
|
@@ -1920,9 +1991,14 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1920
1991
|
t0: Date.now(),
|
|
1921
1992
|
collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
|
|
1922
1993
|
docs: sanitizeDbValue(docs),
|
|
1994
|
+
spanContext: captureSpanContext(this),
|
|
1923
1995
|
};
|
|
1924
1996
|
} catch {
|
|
1925
|
-
(this as any).__repro_insert_meta = {
|
|
1997
|
+
(this as any).__repro_insert_meta = {
|
|
1998
|
+
t0: Date.now(),
|
|
1999
|
+
collection: 'unknown',
|
|
2000
|
+
spanContext: captureSpanContext(this),
|
|
2001
|
+
};
|
|
1926
2002
|
}
|
|
1927
2003
|
next();
|
|
1928
2004
|
} as any);
|
|
@@ -1932,6 +2008,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1932
2008
|
if (!sid) return;
|
|
1933
2009
|
const meta = (this as any).__repro_insert_meta || { t0: Date.now(), collection: 'unknown' };
|
|
1934
2010
|
const resultMeta = Array.isArray(docs) ? { inserted: docs.length } : summarizeQueryResult('insertMany', docs);
|
|
2011
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1935
2012
|
|
|
1936
2013
|
emitDbQuery(cfg, sid, aid, {
|
|
1937
2014
|
collection: meta.collection,
|
|
@@ -1940,6 +2017,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1940
2017
|
resultMeta,
|
|
1941
2018
|
durMs: Date.now() - meta.t0,
|
|
1942
2019
|
t: alignedNow(),
|
|
2020
|
+
spanContext,
|
|
1943
2021
|
});
|
|
1944
2022
|
} as any);
|
|
1945
2023
|
|
|
@@ -1949,9 +2027,14 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1949
2027
|
t0: Date.now(),
|
|
1950
2028
|
collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
|
|
1951
2029
|
ops: sanitizeDbValue(ops),
|
|
2030
|
+
spanContext: captureSpanContext(this),
|
|
1952
2031
|
};
|
|
1953
2032
|
} catch {
|
|
1954
|
-
(this as any).__repro_bulk_meta = {
|
|
2033
|
+
(this as any).__repro_bulk_meta = {
|
|
2034
|
+
t0: Date.now(),
|
|
2035
|
+
collection: 'unknown',
|
|
2036
|
+
spanContext: captureSpanContext(this),
|
|
2037
|
+
};
|
|
1955
2038
|
}
|
|
1956
2039
|
next();
|
|
1957
2040
|
} as any);
|
|
@@ -1962,6 +2045,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1962
2045
|
const meta = (this as any).__repro_bulk_meta || { t0: Date.now(), collection: 'unknown' };
|
|
1963
2046
|
const bulkResult = summarizeBulkResult(res);
|
|
1964
2047
|
const resultMeta = { ...bulkResult, result: sanitizeResultForMeta(res?.result ?? res) };
|
|
2048
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
1965
2049
|
|
|
1966
2050
|
emitDbQuery(cfg, sid, aid, {
|
|
1967
2051
|
collection: meta.collection,
|
|
@@ -1970,6 +2054,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1970
2054
|
resultMeta,
|
|
1971
2055
|
durMs: Date.now() - meta.t0,
|
|
1972
2056
|
t: alignedNow(),
|
|
2057
|
+
spanContext,
|
|
1973
2058
|
});
|
|
1974
2059
|
} as any);
|
|
1975
2060
|
|
|
@@ -1983,10 +2068,16 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1983
2068
|
this?._model?.collection?.name ||
|
|
1984
2069
|
(this?.model && this.model.collection?.name) ||
|
|
1985
2070
|
'unknown',
|
|
2071
|
+
spanContext: captureSpanContext(this),
|
|
1986
2072
|
pipeline: sanitizeDbValue(this.pipeline?.() ?? this._pipeline ?? undefined),
|
|
1987
2073
|
};
|
|
1988
2074
|
} catch {
|
|
1989
|
-
(this as any).__repro_aggmeta = {
|
|
2075
|
+
(this as any).__repro_aggmeta = {
|
|
2076
|
+
t0: Date.now(),
|
|
2077
|
+
collection: 'unknown',
|
|
2078
|
+
pipeline: undefined,
|
|
2079
|
+
spanContext: captureSpanContext(this),
|
|
2080
|
+
};
|
|
1990
2081
|
}
|
|
1991
2082
|
next();
|
|
1992
2083
|
});
|
|
@@ -1997,6 +2088,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
1997
2088
|
|
|
1998
2089
|
const meta = (this as any).__repro_aggmeta || { t0: Date.now(), collection: 'unknown' };
|
|
1999
2090
|
const resultMeta = summarizeQueryResult('aggregate', res);
|
|
2091
|
+
const spanContext = meta.spanContext || captureSpanContext(this);
|
|
2000
2092
|
|
|
2001
2093
|
emitDbQuery(cfg, sid, aid, {
|
|
2002
2094
|
collection: meta.collection,
|
|
@@ -2005,6 +2097,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
|
|
|
2005
2097
|
resultMeta,
|
|
2006
2098
|
durMs: Date.now() - meta.t0,
|
|
2007
2099
|
t: alignedNow(),
|
|
2100
|
+
spanContext,
|
|
2008
2101
|
});
|
|
2009
2102
|
});
|
|
2010
2103
|
};
|
|
@@ -2114,26 +2207,19 @@ function dehydrateComplexValue(value: any) {
|
|
|
2114
2207
|
|
|
2115
2208
|
function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
|
|
2116
2209
|
if (!sid) return;
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2210
|
+
const dbEntry = attachSpanContext({
|
|
2211
|
+
collection: payload.collection,
|
|
2212
|
+
op: payload.op,
|
|
2213
|
+
query: payload.query ?? undefined,
|
|
2214
|
+
resultMeta: payload.resultMeta ?? undefined,
|
|
2215
|
+
durMs: payload.durMs ?? undefined,
|
|
2216
|
+
pk: null, before: null, after: null,
|
|
2217
|
+
error: payload.error ?? undefined,
|
|
2218
|
+
}, payload?.spanContext);
|
|
2123
2219
|
post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
|
|
2124
2220
|
entries: [{
|
|
2125
2221
|
actionId: aid ?? null,
|
|
2126
|
-
db: [
|
|
2127
|
-
collection: payload.collection,
|
|
2128
|
-
op: payload.op,
|
|
2129
|
-
query: payload.query ?? undefined,
|
|
2130
|
-
resultMeta: payload.resultMeta ?? undefined,
|
|
2131
|
-
durMs: payload.durMs ?? undefined,
|
|
2132
|
-
traceId: traceCtx?.traceId ?? null,
|
|
2133
|
-
spanId: traceCtx?.spanId ?? null,
|
|
2134
|
-
pk: null, before: null, after: null,
|
|
2135
|
-
error: payload.error ?? undefined,
|
|
2136
|
-
}],
|
|
2222
|
+
db: [dbEntry],
|
|
2137
2223
|
t: payload.t,
|
|
2138
2224
|
}]
|
|
2139
2225
|
});
|
package/tracer/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
printV8,
|
|
10
10
|
patchConsole,
|
|
11
11
|
getCurrentTraceId,
|
|
12
|
+
getCurrentSpanContext,
|
|
12
13
|
setFunctionLogsEnabled
|
|
13
14
|
} = require('./runtime');
|
|
14
15
|
const { installCJS } = require('./cjs-hook');
|
|
@@ -60,6 +61,7 @@ function api(){
|
|
|
60
61
|
tracer: trace,
|
|
61
62
|
withTrace: trace.withTrace,
|
|
62
63
|
getCurrentTraceId,
|
|
64
|
+
getCurrentSpanContext,
|
|
63
65
|
setFunctionLogsEnabled,
|
|
64
66
|
};
|
|
65
67
|
}
|
package/tracer/runtime.js
CHANGED
|
@@ -100,17 +100,6 @@ 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
|
-
},
|
|
114
103
|
enter(fn, meta, detail){
|
|
115
104
|
const parentSpanIdOverride = meta && Object.prototype.hasOwnProperty.call(meta, 'parentSpanId')
|
|
116
105
|
? meta.parentSpanId
|
|
@@ -143,7 +132,6 @@ const trace = {
|
|
|
143
132
|
traceId: ctx.traceId,
|
|
144
133
|
depth: ctx.depth,
|
|
145
134
|
args: detail?.args,
|
|
146
|
-
receiver: detail?.receiver,
|
|
147
135
|
spanId: span.id,
|
|
148
136
|
parentSpanId: span.parentId
|
|
149
137
|
});
|
|
@@ -171,8 +159,7 @@ const trace = {
|
|
|
171
159
|
returnValue: detail?.returnValue,
|
|
172
160
|
error: detail?.error,
|
|
173
161
|
threw: detail?.threw === true,
|
|
174
|
-
unawaited: detail?.unawaited === true || frameUnawaited
|
|
175
|
-
receiver: detail?.receiver
|
|
162
|
+
unawaited: detail?.unawaited === true || frameUnawaited
|
|
176
163
|
};
|
|
177
164
|
|
|
178
165
|
const promiseTaggedUnawaited = !!(baseDetail.returnValue && baseDetail.returnValue[SYM_UNAWAITED]);
|
|
@@ -192,9 +179,6 @@ const trace = {
|
|
|
192
179
|
unawaited: overrides.hasOwnProperty('unawaited')
|
|
193
180
|
? overrides.unawaited
|
|
194
181
|
: forceUnawaited,
|
|
195
|
-
receiver: overrides.hasOwnProperty('receiver')
|
|
196
|
-
? overrides.receiver
|
|
197
|
-
: baseDetail.receiver,
|
|
198
182
|
args: overrides.hasOwnProperty('args')
|
|
199
183
|
? overrides.args
|
|
200
184
|
: baseDetail.args
|
|
@@ -215,7 +199,6 @@ const trace = {
|
|
|
215
199
|
threw: finalDetail.threw === true,
|
|
216
200
|
error: finalDetail.error,
|
|
217
201
|
args: finalDetail.args,
|
|
218
|
-
receiver: finalDetail.receiver,
|
|
219
202
|
unawaited: finalDetail.unawaited === true
|
|
220
203
|
});
|
|
221
204
|
};
|
|
@@ -279,6 +262,12 @@ const trace = {
|
|
|
279
262
|
return;
|
|
280
263
|
}
|
|
281
264
|
if (queueQueryFinalizer(rv, finalize)) return;
|
|
265
|
+
setQuerySpanContext(rv, {
|
|
266
|
+
traceId: traceIdAtExit,
|
|
267
|
+
spanId: spanForExit.id,
|
|
268
|
+
parentSpanId: spanForExit.parentId,
|
|
269
|
+
depth: spanForExit.depth ?? depthAtExit
|
|
270
|
+
});
|
|
282
271
|
emitNow({ unawaited: forceUnawaited, returnValue: rv }, spanForExit, spanStackForExit);
|
|
283
272
|
return;
|
|
284
273
|
}
|
|
@@ -289,6 +278,12 @@ const trace = {
|
|
|
289
278
|
}
|
|
290
279
|
|
|
291
280
|
if (isQuery) {
|
|
281
|
+
setQuerySpanContext(rv, {
|
|
282
|
+
traceId: traceIdAtExit,
|
|
283
|
+
spanId: spanInfoPeek.id,
|
|
284
|
+
parentSpanId: spanInfoPeek.parentId,
|
|
285
|
+
depth: spanInfoPeek.depth ?? depthAtExit
|
|
286
|
+
});
|
|
292
287
|
emitNow({ unawaited: forceUnawaited });
|
|
293
288
|
return;
|
|
294
289
|
}
|
|
@@ -492,24 +487,6 @@ function forkAlsStoreForUnawaited(baseStore) {
|
|
|
492
487
|
return cloned;
|
|
493
488
|
}
|
|
494
489
|
|
|
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
|
-
|
|
513
490
|
// ========= Generic call-site shim (used by Babel transform) =========
|
|
514
491
|
// Decides whether to emit a top-level event based on callee origin tags.
|
|
515
492
|
// No hardcoded library names or file paths.
|
|
@@ -631,15 +608,13 @@ if (!global.__repro_call) {
|
|
|
631
608
|
? (label && label.length ? label : fn.name)
|
|
632
609
|
: '(anonymous)';
|
|
633
610
|
const sourceFile = fn[SYM_SRC_FILE];
|
|
634
|
-
const receiverForTrace = shouldCaptureReceiver(label, thisArg) ? thisArg : undefined;
|
|
635
611
|
const meta = {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
line: callLine ?? null,
|
|
612
|
+
file: sourceFile || callFile || null,
|
|
613
|
+
line: sourceFile ? null : (callLine || null),
|
|
639
614
|
parentSpanId: forcedParentSpanId
|
|
640
615
|
};
|
|
641
616
|
|
|
642
|
-
trace.enter(name, meta, { args
|
|
617
|
+
trace.enter(name, meta, { args });
|
|
643
618
|
// After entering, snapshot a clean store that captures the parent + this call’s span,
|
|
644
619
|
// so callbacks invoked during the callee run are isolated per invocation.
|
|
645
620
|
const snapshotForArgs = cloneStore(als.getStore());
|
|
@@ -654,8 +629,7 @@ if (!global.__repro_call) {
|
|
|
654
629
|
const exitDetailBase = {
|
|
655
630
|
returnValue: out,
|
|
656
631
|
args,
|
|
657
|
-
unawaited: shouldForceExit
|
|
658
|
-
receiver: receiverForTrace
|
|
632
|
+
unawaited: shouldForceExit
|
|
659
633
|
};
|
|
660
634
|
|
|
661
635
|
if (shouldForceExit) markPromiseUnawaited(out);
|
|
@@ -697,8 +671,7 @@ if (!global.__repro_call) {
|
|
|
697
671
|
args,
|
|
698
672
|
threw,
|
|
699
673
|
error,
|
|
700
|
-
unawaited: shouldForceExit
|
|
701
|
-
receiver: receiverForTrace
|
|
674
|
+
unawaited: shouldForceExit
|
|
702
675
|
};
|
|
703
676
|
runExit(detail);
|
|
704
677
|
return value;
|
|
@@ -718,7 +691,7 @@ if (!global.__repro_call) {
|
|
|
718
691
|
runExit(exitDetailBase);
|
|
719
692
|
return out;
|
|
720
693
|
} catch (e) {
|
|
721
|
-
trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args
|
|
694
|
+
trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args });
|
|
722
695
|
throw e;
|
|
723
696
|
} finally {
|
|
724
697
|
if (pendingMarker) {
|
|
@@ -880,6 +853,54 @@ function getCurrentTraceId() {
|
|
|
880
853
|
return s && s.traceId || null;
|
|
881
854
|
}
|
|
882
855
|
|
|
856
|
+
function setQuerySpanContext(target, ctx) {
|
|
857
|
+
if (!target || typeof target !== 'object' || !ctx) return;
|
|
858
|
+
const safeCtx = {
|
|
859
|
+
traceId: ctx.traceId || null,
|
|
860
|
+
spanId: ctx.spanId ?? null,
|
|
861
|
+
parentSpanId: ctx.parentSpanId ?? null,
|
|
862
|
+
depth: ctx.depth ?? null
|
|
863
|
+
};
|
|
864
|
+
try {
|
|
865
|
+
if (!target.__repro_span_context) {
|
|
866
|
+
Object.defineProperty(target, '__repro_span_context', {
|
|
867
|
+
value: safeCtx,
|
|
868
|
+
configurable: true,
|
|
869
|
+
writable: true,
|
|
870
|
+
enumerable: false
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
} catch {
|
|
874
|
+
try { target.__repro_span_context = safeCtx; } catch {}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function getCurrentSpanContext() {
|
|
879
|
+
try {
|
|
880
|
+
const store = als.getStore();
|
|
881
|
+
if (!store) return null;
|
|
882
|
+
|
|
883
|
+
const stack = Array.isArray(store.__repro_span_stack) ? store.__repro_span_stack : [];
|
|
884
|
+
const top = stack.length ? stack[stack.length - 1] : null;
|
|
885
|
+
const spanId = top && top.id != null ? top.id : null;
|
|
886
|
+
const parentSpanId = top && top.parentId != null
|
|
887
|
+
? top.parentId
|
|
888
|
+
: (stack.length >= 2 ? (stack[stack.length - 2]?.id ?? null) : null);
|
|
889
|
+
const depth = top && top.depth != null
|
|
890
|
+
? top.depth
|
|
891
|
+
: (typeof store.depth === 'number'
|
|
892
|
+
? store.depth
|
|
893
|
+
: (stack.length ? stack.length : null));
|
|
894
|
+
|
|
895
|
+
const traceId = store.traceId || null;
|
|
896
|
+
|
|
897
|
+
if (spanId === null && parentSpanId === null && traceId === null) return null;
|
|
898
|
+
return { traceId, spanId, parentSpanId, depth: depth == null ? null : depth };
|
|
899
|
+
} catch {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
883
904
|
// ---- Promise propagation fallback: ensure continuations run with the captured store ----
|
|
884
905
|
let PROMISE_PATCHED = false;
|
|
885
906
|
function patchPromise() {
|
|
@@ -924,6 +945,7 @@ module.exports = {
|
|
|
924
945
|
printV8,
|
|
925
946
|
patchConsole,
|
|
926
947
|
getCurrentTraceId,
|
|
948
|
+
getCurrentSpanContext,
|
|
927
949
|
setFunctionLogsEnabled,
|
|
928
950
|
// export symbols so the require hook can tag function origins
|
|
929
951
|
SYM_SRC_FILE,
|