@reproapp/node-sdk 0.0.26 → 0.0.28
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 -0
- package/dist/index.js +585 -1
- package/dist/ingest/client.js +18 -3
- package/package.json +2 -2
- package/src/index.ts +651 -0
- package/src/ingest/client.ts +25 -3
- package/test/ingest-critical-retention.test.js +147 -0
- package/test/ingest-critical-retry-retention.test.js +57 -0
- package/test/ingest-high-priority-retention.test.js +75 -0
- package/test/mongodb-integration.test.js +389 -0
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.__reproTestHooks = exports.initRepro = exports.patchSendgridMail = exports.patchRedis = exports.patchAmqplib = exports.patchKafkaJs = exports.reproMongoosePlugin = exports.reproMiddleware = exports.__materializePendingTraceEventsForWorker = exports.isReproTracingEnabled = exports.initReproTracing = exports.disableReproTraceLogs = exports.enableReproTraceLogs = exports.setReproTraceLogsEnabled = exports.setDisabledTraceFiles = exports.setDisabledFunctionTypes = exports.setDisabledFunctionTraces = void 0;
|
|
3
|
+
exports.__reproTestHooks = exports.initRepro = exports.patchSendgridMail = exports.patchMongoDb = exports.patchRedis = exports.patchAmqplib = exports.patchKafkaJs = exports.reproMongoosePlugin = exports.reproMiddleware = exports.__materializePendingTraceEventsForWorker = exports.isReproTracingEnabled = exports.initReproTracing = exports.disableReproTraceLogs = exports.enableReproTraceLogs = exports.setReproTraceLogsEnabled = exports.setDisabledTraceFiles = exports.setDisabledFunctionTypes = exports.setDisabledFunctionTraces = void 0;
|
|
4
4
|
const mongoose = require("mongoose");
|
|
5
5
|
const async_hooks_1 = require("async_hooks");
|
|
6
6
|
const crypto_1 = require("crypto");
|
|
@@ -819,6 +819,57 @@ function buildRequestCaptureManifestPayload(scope, traceBatchTotal, closedAtMs)
|
|
|
819
819
|
}
|
|
820
820
|
const als = new async_hooks_1.AsyncLocalStorage();
|
|
821
821
|
const getCtx = () => als.getStore() || {};
|
|
822
|
+
function normalizeNativeMongoSuppressionOp(op) {
|
|
823
|
+
return String(op ?? '').trim();
|
|
824
|
+
}
|
|
825
|
+
function pushNativeMongoSuppression(collection, ops) {
|
|
826
|
+
const store = als.getStore();
|
|
827
|
+
if (!store)
|
|
828
|
+
return null;
|
|
829
|
+
const normalizedOps = Array.isArray(ops)
|
|
830
|
+
? ops.map(normalizeNativeMongoSuppressionOp).filter(Boolean)
|
|
831
|
+
: [];
|
|
832
|
+
const token = {
|
|
833
|
+
collection: collection == null ? null : String(collection),
|
|
834
|
+
ops: normalizedOps.length ? new Set(normalizedOps) : undefined,
|
|
835
|
+
startedAt: Date.now(),
|
|
836
|
+
};
|
|
837
|
+
if (!Array.isArray(store.nativeMongoSuppressions)) {
|
|
838
|
+
store.nativeMongoSuppressions = [];
|
|
839
|
+
}
|
|
840
|
+
store.nativeMongoSuppressions.push(token);
|
|
841
|
+
return token;
|
|
842
|
+
}
|
|
843
|
+
function popNativeMongoSuppression(token) {
|
|
844
|
+
if (!token)
|
|
845
|
+
return;
|
|
846
|
+
const store = als.getStore();
|
|
847
|
+
const suppressions = store?.nativeMongoSuppressions;
|
|
848
|
+
if (!Array.isArray(suppressions) || suppressions.length === 0)
|
|
849
|
+
return;
|
|
850
|
+
const index = suppressions.indexOf(token);
|
|
851
|
+
if (index >= 0) {
|
|
852
|
+
suppressions.splice(index, 1);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
function isNativeMongoSuppressed(collection, op) {
|
|
856
|
+
const suppressions = getCtx().nativeMongoSuppressions;
|
|
857
|
+
if (!Array.isArray(suppressions) || suppressions.length === 0)
|
|
858
|
+
return false;
|
|
859
|
+
const normalizedCollection = collection == null ? null : String(collection);
|
|
860
|
+
const normalizedOp = normalizeNativeMongoSuppressionOp(op);
|
|
861
|
+
const now = Date.now();
|
|
862
|
+
for (const token of suppressions) {
|
|
863
|
+
if (!token || now - token.startedAt > 60000)
|
|
864
|
+
continue;
|
|
865
|
+
if (token.collection && normalizedCollection && token.collection !== normalizedCollection)
|
|
866
|
+
continue;
|
|
867
|
+
if (token.ops && token.ops.size > 0 && !token.ops.has(normalizedOp))
|
|
868
|
+
continue;
|
|
869
|
+
return true;
|
|
870
|
+
}
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
822
873
|
function currentClockSkewMs() {
|
|
823
874
|
const store = als.getStore();
|
|
824
875
|
const skew = store?.clockSkewMs;
|
|
@@ -3946,6 +3997,7 @@ async function maybeCaptureDbValueAsync(params, sink) {
|
|
|
3946
3997
|
}
|
|
3947
3998
|
function reproMiddleware(cfg) {
|
|
3948
3999
|
const masking = normalizeMaskingConfig(cfg.masking);
|
|
4000
|
+
patchMongoDb(cfg);
|
|
3949
4001
|
return async function (req, res, next) {
|
|
3950
4002
|
const querySid = readRequestQueryParam(req, REPRO_QUERY_SESSION_PARAM);
|
|
3951
4003
|
const queryAid = readRequestQueryParam(req, REPRO_QUERY_ACTION_PARAM);
|
|
@@ -4483,6 +4535,16 @@ exports.reproMiddleware = reproMiddleware;
|
|
|
4483
4535
|
// - ONLY schema middleware (pre/post) for specific ops
|
|
4484
4536
|
// - keeps your existing doc-diff hooks
|
|
4485
4537
|
// ===================================================================
|
|
4538
|
+
function nativeMongoOpsForMongooseOp(op) {
|
|
4539
|
+
if (op === 'findByIdAndUpdate')
|
|
4540
|
+
return ['findOneAndUpdate'];
|
|
4541
|
+
if (op === 'findByIdAndDelete' || op === 'findByIdAndRemove' || op === 'findOneAndRemove') {
|
|
4542
|
+
return ['findOneAndDelete'];
|
|
4543
|
+
}
|
|
4544
|
+
if (op === 'findByIdAndReplace')
|
|
4545
|
+
return ['findOneAndReplace'];
|
|
4546
|
+
return [op];
|
|
4547
|
+
}
|
|
4486
4548
|
function reproMongoosePlugin(cfg) {
|
|
4487
4549
|
return function (schema) {
|
|
4488
4550
|
// -------- pre/post save (unchanged) --------
|
|
@@ -4501,6 +4563,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4501
4563
|
? this.modifiedPaths()
|
|
4502
4564
|
: [],
|
|
4503
4565
|
};
|
|
4566
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression(this.__repro_meta.collection, this.isNew ? ['insertOne'] : ['updateOne', 'replaceOne']);
|
|
4504
4567
|
next();
|
|
4505
4568
|
});
|
|
4506
4569
|
schema.post('save', { document: true }, function () {
|
|
@@ -4534,6 +4597,11 @@ function reproMongoosePlugin(cfg) {
|
|
|
4534
4597
|
t: alignTimestamp(meta.t0 ?? Date.now()),
|
|
4535
4598
|
spanContext,
|
|
4536
4599
|
});
|
|
4600
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4601
|
+
});
|
|
4602
|
+
schema.post('save', { document: true }, function (error, _doc, next) {
|
|
4603
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4604
|
+
next(error);
|
|
4537
4605
|
});
|
|
4538
4606
|
// -------- findOneAndUpdate capture (unchanged) --------
|
|
4539
4607
|
schema.pre('findOneAndUpdate', function (next) {
|
|
@@ -4548,6 +4616,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4548
4616
|
this.__repro_spanContext = captureSpanContextFromTracer(this);
|
|
4549
4617
|
this.__repro_filter = filter;
|
|
4550
4618
|
this.__repro_update = this.getUpdate?.() ?? this._update ?? undefined;
|
|
4619
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression(this.__repro_collection, ['findOneAndUpdate']);
|
|
4551
4620
|
}
|
|
4552
4621
|
catch { }
|
|
4553
4622
|
next();
|
|
@@ -4577,6 +4646,11 @@ function reproMongoosePlugin(cfg) {
|
|
|
4577
4646
|
t: alignTimestamp(this.__repro_t0 ?? Date.now()),
|
|
4578
4647
|
spanContext,
|
|
4579
4648
|
});
|
|
4649
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4650
|
+
});
|
|
4651
|
+
schema.post('findOneAndUpdate', function (error, _res, next) {
|
|
4652
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4653
|
+
next(error);
|
|
4580
4654
|
});
|
|
4581
4655
|
// -------- deleteOne capture (unchanged) --------
|
|
4582
4656
|
schema.pre('deleteOne', { document: false, query: true }, function (next) {
|
|
@@ -4589,6 +4663,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4589
4663
|
this.__repro_collection = resolveCollectionOrWarn(this, 'query');
|
|
4590
4664
|
this.__repro_filter = filter;
|
|
4591
4665
|
this.__repro_spanContext = captureSpanContextFromTracer(this);
|
|
4666
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression(this.__repro_collection, ['deleteOne']);
|
|
4592
4667
|
}
|
|
4593
4668
|
catch { }
|
|
4594
4669
|
next();
|
|
@@ -4613,6 +4688,11 @@ function reproMongoosePlugin(cfg) {
|
|
|
4613
4688
|
t: alignTimestamp(this.__repro_t0 ?? Date.now()),
|
|
4614
4689
|
spanContext,
|
|
4615
4690
|
});
|
|
4691
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4692
|
+
});
|
|
4693
|
+
schema.post('deleteOne', { document: false, query: true }, function (error, _res, next) {
|
|
4694
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4695
|
+
next(error);
|
|
4616
4696
|
});
|
|
4617
4697
|
// -------- NON-intrusive generic query telemetry via schema hooks -------
|
|
4618
4698
|
const READ_OPS = [
|
|
@@ -4653,6 +4733,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4653
4733
|
rawProjection,
|
|
4654
4734
|
rawOptions,
|
|
4655
4735
|
};
|
|
4736
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression(this.__repro_qmeta.collection, nativeMongoOpsForMongooseOp(op));
|
|
4656
4737
|
}
|
|
4657
4738
|
catch {
|
|
4658
4739
|
this.__repro_qmeta = {
|
|
@@ -4661,6 +4742,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4661
4742
|
op,
|
|
4662
4743
|
spanContext: captureSpanContextFromTracer(this),
|
|
4663
4744
|
};
|
|
4745
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression('unknown', nativeMongoOpsForMongooseOp(op));
|
|
4664
4746
|
}
|
|
4665
4747
|
next();
|
|
4666
4748
|
});
|
|
@@ -4684,6 +4766,11 @@ function reproMongoosePlugin(cfg) {
|
|
|
4684
4766
|
t: alignedNow(),
|
|
4685
4767
|
spanContext,
|
|
4686
4768
|
});
|
|
4769
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4770
|
+
});
|
|
4771
|
+
schema.post(op, function (error, _res, next) {
|
|
4772
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4773
|
+
next(error);
|
|
4687
4774
|
});
|
|
4688
4775
|
}
|
|
4689
4776
|
READ_OPS.forEach(attachQueryHooks);
|
|
@@ -4698,6 +4785,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4698
4785
|
rawDocs,
|
|
4699
4786
|
spanContext: captureSpanContextFromTracer(this),
|
|
4700
4787
|
};
|
|
4788
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression(this.__repro_insert_meta.collection, ['insertMany']);
|
|
4701
4789
|
}
|
|
4702
4790
|
catch {
|
|
4703
4791
|
this.__repro_insert_meta = {
|
|
@@ -4705,6 +4793,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4705
4793
|
collection: 'unknown',
|
|
4706
4794
|
spanContext: captureSpanContextFromTracer(this),
|
|
4707
4795
|
};
|
|
4796
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression('unknown', ['insertMany']);
|
|
4708
4797
|
}
|
|
4709
4798
|
next();
|
|
4710
4799
|
});
|
|
@@ -4723,6 +4812,11 @@ function reproMongoosePlugin(cfg) {
|
|
|
4723
4812
|
t: alignedNow(),
|
|
4724
4813
|
spanContext,
|
|
4725
4814
|
});
|
|
4815
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4816
|
+
});
|
|
4817
|
+
schema.post('insertMany', { document: false, query: false }, function (error, _res, next) {
|
|
4818
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4819
|
+
next(error);
|
|
4726
4820
|
});
|
|
4727
4821
|
schema.pre('bulkWrite', { document: false, query: false }, function (next, ops) {
|
|
4728
4822
|
try {
|
|
@@ -4733,6 +4827,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4733
4827
|
rawOps,
|
|
4734
4828
|
spanContext: captureSpanContextFromTracer(this),
|
|
4735
4829
|
};
|
|
4830
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression(this.__repro_bulk_meta.collection, ['bulkWrite']);
|
|
4736
4831
|
}
|
|
4737
4832
|
catch {
|
|
4738
4833
|
this.__repro_bulk_meta = {
|
|
@@ -4740,6 +4835,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4740
4835
|
collection: 'unknown',
|
|
4741
4836
|
spanContext: captureSpanContextFromTracer(this),
|
|
4742
4837
|
};
|
|
4838
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression('unknown', ['bulkWrite']);
|
|
4743
4839
|
}
|
|
4744
4840
|
next();
|
|
4745
4841
|
});
|
|
@@ -4758,6 +4854,11 @@ function reproMongoosePlugin(cfg) {
|
|
|
4758
4854
|
t: alignedNow(),
|
|
4759
4855
|
spanContext,
|
|
4760
4856
|
});
|
|
4857
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4858
|
+
});
|
|
4859
|
+
schema.post('bulkWrite', { document: false, query: false }, function (error, _res, next) {
|
|
4860
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4861
|
+
next(error);
|
|
4761
4862
|
});
|
|
4762
4863
|
// Aggregate middleware (non-intrusive)
|
|
4763
4864
|
schema.pre('aggregate', function (next) {
|
|
@@ -4772,6 +4873,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4772
4873
|
spanContext: captureSpanContextFromTracer(this),
|
|
4773
4874
|
rawPipeline,
|
|
4774
4875
|
};
|
|
4876
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression(this.__repro_aggmeta.collection, ['aggregate']);
|
|
4775
4877
|
}
|
|
4776
4878
|
catch {
|
|
4777
4879
|
this.__repro_aggmeta = {
|
|
@@ -4780,6 +4882,7 @@ function reproMongoosePlugin(cfg) {
|
|
|
4780
4882
|
pipeline: undefined,
|
|
4781
4883
|
spanContext: captureSpanContextFromTracer(this),
|
|
4782
4884
|
};
|
|
4885
|
+
this.__repro_native_mongo_suppression = pushNativeMongoSuppression('unknown', ['aggregate']);
|
|
4783
4886
|
}
|
|
4784
4887
|
next();
|
|
4785
4888
|
});
|
|
@@ -4798,6 +4901,11 @@ function reproMongoosePlugin(cfg) {
|
|
|
4798
4901
|
t: alignedNow(),
|
|
4799
4902
|
spanContext,
|
|
4800
4903
|
});
|
|
4904
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4905
|
+
});
|
|
4906
|
+
schema.post('aggregate', function (error, _res, next) {
|
|
4907
|
+
popNativeMongoSuppression(this.__repro_native_mongo_suppression);
|
|
4908
|
+
next(error);
|
|
4801
4909
|
});
|
|
4802
4910
|
};
|
|
4803
4911
|
}
|
|
@@ -4823,10 +4931,24 @@ function summarizeQueryResult(op, res) {
|
|
|
4823
4931
|
}
|
|
4824
4932
|
return summary;
|
|
4825
4933
|
}
|
|
4934
|
+
if (op === 'insertOne') {
|
|
4935
|
+
const summary = {
|
|
4936
|
+
insertedId: res?.insertedId ?? undefined,
|
|
4937
|
+
acknowledged: res?.acknowledged ?? undefined,
|
|
4938
|
+
};
|
|
4939
|
+
if (typeof resultPreview !== 'undefined')
|
|
4940
|
+
summary.result = resultPreview;
|
|
4941
|
+
return summary;
|
|
4942
|
+
}
|
|
4826
4943
|
if (op === 'insertMany') {
|
|
4827
4944
|
const summary = {};
|
|
4828
4945
|
if (Array.isArray(res))
|
|
4829
4946
|
summary.inserted = res.length;
|
|
4947
|
+
else {
|
|
4948
|
+
summary.inserted = res?.insertedCount ?? undefined;
|
|
4949
|
+
summary.insertedIds = res?.insertedIds ?? undefined;
|
|
4950
|
+
summary.acknowledged = res?.acknowledged ?? undefined;
|
|
4951
|
+
}
|
|
4830
4952
|
if (typeof resultPreview !== 'undefined')
|
|
4831
4953
|
summary.result = resultPreview;
|
|
4832
4954
|
return summary;
|
|
@@ -7409,6 +7531,465 @@ function patchRedis(cfg) {
|
|
|
7409
7531
|
}
|
|
7410
7532
|
}
|
|
7411
7533
|
exports.patchRedis = patchRedis;
|
|
7534
|
+
const mongoDbPatchConfigs = [];
|
|
7535
|
+
let mongoDbRequireHookInstalled = false;
|
|
7536
|
+
const MONGODB_PROMISE_OPS = [
|
|
7537
|
+
'insertOne',
|
|
7538
|
+
'insertMany',
|
|
7539
|
+
'updateOne',
|
|
7540
|
+
'updateMany',
|
|
7541
|
+
'replaceOne',
|
|
7542
|
+
'deleteOne',
|
|
7543
|
+
'deleteMany',
|
|
7544
|
+
'findOne',
|
|
7545
|
+
'countDocuments',
|
|
7546
|
+
'estimatedDocumentCount',
|
|
7547
|
+
'distinct',
|
|
7548
|
+
'bulkWrite',
|
|
7549
|
+
'findOneAndUpdate',
|
|
7550
|
+
'findOneAndDelete',
|
|
7551
|
+
'findOneAndReplace',
|
|
7552
|
+
];
|
|
7553
|
+
const MONGODB_CURSOR_OPS = ['find', 'aggregate'];
|
|
7554
|
+
const MONGODB_CURSOR_TERMINALS = ['toArray', 'next', 'forEach'];
|
|
7555
|
+
function resolveMongoDbRuntimeContext(cfg) {
|
|
7556
|
+
const ctx = getCtx();
|
|
7557
|
+
const fallback = cfg.resolveContext?.() ?? {};
|
|
7558
|
+
return {
|
|
7559
|
+
ctx,
|
|
7560
|
+
sid: ctx.sid ?? fallback.sid ?? null,
|
|
7561
|
+
aid: ctx.aid ?? fallback.aid ?? null,
|
|
7562
|
+
};
|
|
7563
|
+
}
|
|
7564
|
+
function resolveMongoCollectionName(collection) {
|
|
7565
|
+
const candidates = [
|
|
7566
|
+
collection?.collectionName,
|
|
7567
|
+
collection?.namespace?.collection,
|
|
7568
|
+
collection?.s?.namespace?.collection,
|
|
7569
|
+
collection?.s?.namespace?.collectionName,
|
|
7570
|
+
];
|
|
7571
|
+
for (const candidate of candidates) {
|
|
7572
|
+
if (typeof candidate === 'string' && candidate.trim())
|
|
7573
|
+
return candidate;
|
|
7574
|
+
}
|
|
7575
|
+
const namespace = typeof collection?.namespace === 'string'
|
|
7576
|
+
? collection.namespace
|
|
7577
|
+
: typeof collection?.s?.namespace === 'string'
|
|
7578
|
+
? collection.s.namespace
|
|
7579
|
+
: typeof collection?.namespace?.toString === 'function'
|
|
7580
|
+
? collection.namespace.toString()
|
|
7581
|
+
: typeof collection?.s?.namespace?.toString === 'function'
|
|
7582
|
+
? collection.s.namespace.toString()
|
|
7583
|
+
: null;
|
|
7584
|
+
if (namespace && namespace.includes('.')) {
|
|
7585
|
+
return namespace.slice(namespace.indexOf('.') + 1) || namespace;
|
|
7586
|
+
}
|
|
7587
|
+
return namespace || 'unknown';
|
|
7588
|
+
}
|
|
7589
|
+
function resolveMongoDbName(collection) {
|
|
7590
|
+
const candidates = [
|
|
7591
|
+
collection?.dbName,
|
|
7592
|
+
collection?.db?.databaseName,
|
|
7593
|
+
collection?.s?.db?.databaseName,
|
|
7594
|
+
collection?.namespace?.db,
|
|
7595
|
+
collection?.s?.namespace?.db,
|
|
7596
|
+
];
|
|
7597
|
+
for (const candidate of candidates) {
|
|
7598
|
+
if (typeof candidate === 'string' && candidate.trim())
|
|
7599
|
+
return candidate;
|
|
7600
|
+
}
|
|
7601
|
+
const namespace = typeof collection?.namespace === 'string'
|
|
7602
|
+
? collection.namespace
|
|
7603
|
+
: typeof collection?.s?.namespace === 'string'
|
|
7604
|
+
? collection.s.namespace
|
|
7605
|
+
: null;
|
|
7606
|
+
if (namespace && namespace.includes('.')) {
|
|
7607
|
+
return namespace.slice(0, namespace.indexOf('.')) || undefined;
|
|
7608
|
+
}
|
|
7609
|
+
return undefined;
|
|
7610
|
+
}
|
|
7611
|
+
function summarizeMongoSession(session) {
|
|
7612
|
+
if (!session || typeof session !== 'object')
|
|
7613
|
+
return session;
|
|
7614
|
+
let inTransaction = undefined;
|
|
7615
|
+
try {
|
|
7616
|
+
inTransaction = typeof session.inTransaction === 'function' ? session.inTransaction() : undefined;
|
|
7617
|
+
}
|
|
7618
|
+
catch { }
|
|
7619
|
+
return {
|
|
7620
|
+
__kind: 'mongodb_client_session',
|
|
7621
|
+
id: session.id ?? session.serverSession?.id ?? undefined,
|
|
7622
|
+
hasEnded: session.hasEnded ?? undefined,
|
|
7623
|
+
inTransaction,
|
|
7624
|
+
};
|
|
7625
|
+
}
|
|
7626
|
+
function normalizeMongoDriverOptions(options) {
|
|
7627
|
+
if (!options || typeof options !== 'object' || Array.isArray(options))
|
|
7628
|
+
return options;
|
|
7629
|
+
const normalized = {};
|
|
7630
|
+
for (const key of Object.keys(options)) {
|
|
7631
|
+
normalized[key] = key === 'session'
|
|
7632
|
+
? summarizeMongoSession(options[key])
|
|
7633
|
+
: options[key];
|
|
7634
|
+
}
|
|
7635
|
+
return normalized;
|
|
7636
|
+
}
|
|
7637
|
+
function summarizeMongoError(error) {
|
|
7638
|
+
return {
|
|
7639
|
+
name: error?.name ?? undefined,
|
|
7640
|
+
message: error?.message ?? String(error),
|
|
7641
|
+
code: error?.code ?? undefined,
|
|
7642
|
+
codeName: error?.codeName ?? undefined,
|
|
7643
|
+
};
|
|
7644
|
+
}
|
|
7645
|
+
function extractMongoPkFromFilter(filter) {
|
|
7646
|
+
if (filter && typeof filter === 'object' && Object.prototype.hasOwnProperty.call(filter, '_id')) {
|
|
7647
|
+
return { _id: filter._id };
|
|
7648
|
+
}
|
|
7649
|
+
return undefined;
|
|
7650
|
+
}
|
|
7651
|
+
function extractMongoPkFromDoc(doc, result) {
|
|
7652
|
+
const id = doc && typeof doc === 'object' ? doc._id : undefined;
|
|
7653
|
+
const insertedId = result?.insertedId;
|
|
7654
|
+
if (id !== undefined)
|
|
7655
|
+
return { _id: id };
|
|
7656
|
+
if (insertedId !== undefined)
|
|
7657
|
+
return { _id: insertedId };
|
|
7658
|
+
return undefined;
|
|
7659
|
+
}
|
|
7660
|
+
function buildMongoQueryPayload(op, args, dbName) {
|
|
7661
|
+
const withDriver = (payload) => ({
|
|
7662
|
+
driver: 'mongodb',
|
|
7663
|
+
db: dbName,
|
|
7664
|
+
...payload,
|
|
7665
|
+
});
|
|
7666
|
+
if (op === 'insertOne') {
|
|
7667
|
+
return withDriver({ doc: args[0], options: normalizeMongoDriverOptions(args[1]) });
|
|
7668
|
+
}
|
|
7669
|
+
if (op === 'insertMany') {
|
|
7670
|
+
return withDriver({ docs: args[0], options: normalizeMongoDriverOptions(args[1]) });
|
|
7671
|
+
}
|
|
7672
|
+
if (op === 'updateOne' || op === 'updateMany') {
|
|
7673
|
+
return withDriver({ filter: args[0], update: args[1], options: normalizeMongoDriverOptions(args[2]) });
|
|
7674
|
+
}
|
|
7675
|
+
if (op === 'replaceOne') {
|
|
7676
|
+
return withDriver({ filter: args[0], replacement: args[1], options: normalizeMongoDriverOptions(args[2]) });
|
|
7677
|
+
}
|
|
7678
|
+
if (op === 'deleteOne' || op === 'deleteMany') {
|
|
7679
|
+
return withDriver({ filter: args[0], options: normalizeMongoDriverOptions(args[1]) });
|
|
7680
|
+
}
|
|
7681
|
+
if (op === 'findOne' || op === 'find' || op === 'countDocuments') {
|
|
7682
|
+
return withDriver({ filter: args[0], options: normalizeMongoDriverOptions(args[1]) });
|
|
7683
|
+
}
|
|
7684
|
+
if (op === 'estimatedDocumentCount') {
|
|
7685
|
+
return withDriver({ options: normalizeMongoDriverOptions(args[0]) });
|
|
7686
|
+
}
|
|
7687
|
+
if (op === 'distinct') {
|
|
7688
|
+
return withDriver({ key: args[0], filter: args[1], options: normalizeMongoDriverOptions(args[2]) });
|
|
7689
|
+
}
|
|
7690
|
+
if (op === 'bulkWrite') {
|
|
7691
|
+
return withDriver({ ops: args[0], options: normalizeMongoDriverOptions(args[1]) });
|
|
7692
|
+
}
|
|
7693
|
+
if (op === 'findOneAndUpdate') {
|
|
7694
|
+
return withDriver({ filter: args[0], update: args[1], options: normalizeMongoDriverOptions(args[2]) });
|
|
7695
|
+
}
|
|
7696
|
+
if (op === 'findOneAndReplace') {
|
|
7697
|
+
return withDriver({ filter: args[0], replacement: args[1], options: normalizeMongoDriverOptions(args[2]) });
|
|
7698
|
+
}
|
|
7699
|
+
if (op === 'findOneAndDelete') {
|
|
7700
|
+
return withDriver({ filter: args[0], options: normalizeMongoDriverOptions(args[1]) });
|
|
7701
|
+
}
|
|
7702
|
+
if (op === 'aggregate') {
|
|
7703
|
+
return withDriver({ pipeline: args[0], options: normalizeMongoDriverOptions(args[1]) });
|
|
7704
|
+
}
|
|
7705
|
+
return withDriver({ args });
|
|
7706
|
+
}
|
|
7707
|
+
function buildMongoPk(op, args, result) {
|
|
7708
|
+
if (op === 'insertOne')
|
|
7709
|
+
return extractMongoPkFromDoc(args[0], result);
|
|
7710
|
+
if (op === 'updateOne' ||
|
|
7711
|
+
op === 'replaceOne' ||
|
|
7712
|
+
op === 'deleteOne' ||
|
|
7713
|
+
op === 'findOne' ||
|
|
7714
|
+
op === 'findOneAndUpdate' ||
|
|
7715
|
+
op === 'findOneAndDelete' ||
|
|
7716
|
+
op === 'findOneAndReplace') {
|
|
7717
|
+
return extractMongoPkFromFilter(args[0]);
|
|
7718
|
+
}
|
|
7719
|
+
return undefined;
|
|
7720
|
+
}
|
|
7721
|
+
function buildMongoAfter(op, args, result) {
|
|
7722
|
+
if (op === 'insertOne')
|
|
7723
|
+
return args[0] ?? null;
|
|
7724
|
+
if (op === 'insertMany')
|
|
7725
|
+
return args[0] ?? null;
|
|
7726
|
+
if (op === 'findOne' || op === 'findOneAndUpdate' || op === 'findOneAndDelete' || op === 'findOneAndReplace') {
|
|
7727
|
+
return result ?? null;
|
|
7728
|
+
}
|
|
7729
|
+
if (op === 'find' || op === 'aggregate') {
|
|
7730
|
+
return Array.isArray(result) ? result : null;
|
|
7731
|
+
}
|
|
7732
|
+
return null;
|
|
7733
|
+
}
|
|
7734
|
+
function findMongoCallbackIndex(args) {
|
|
7735
|
+
for (let i = args.length - 1; i >= 0; i -= 1) {
|
|
7736
|
+
if (typeof args[i] === 'function')
|
|
7737
|
+
return i;
|
|
7738
|
+
}
|
|
7739
|
+
return -1;
|
|
7740
|
+
}
|
|
7741
|
+
function patchMongoCursorInstance(cursor, meta) {
|
|
7742
|
+
if (!cursor || typeof cursor !== 'object')
|
|
7743
|
+
return cursor;
|
|
7744
|
+
if (cursor.__repro_mongodb_cursor_patched)
|
|
7745
|
+
return cursor;
|
|
7746
|
+
try {
|
|
7747
|
+
Object.defineProperty(cursor, '__repro_mongodb_cursor_patched', {
|
|
7748
|
+
value: true,
|
|
7749
|
+
configurable: true,
|
|
7750
|
+
});
|
|
7751
|
+
}
|
|
7752
|
+
catch {
|
|
7753
|
+
return cursor;
|
|
7754
|
+
}
|
|
7755
|
+
for (const methodName of MONGODB_CURSOR_TERMINALS) {
|
|
7756
|
+
const original = cursor[methodName];
|
|
7757
|
+
if (typeof original !== 'function')
|
|
7758
|
+
continue;
|
|
7759
|
+
cursor[methodName] = function reproPatchedMongoCursorTerminal(...callArgs) {
|
|
7760
|
+
const t0 = Date.now();
|
|
7761
|
+
let emitted = false;
|
|
7762
|
+
let forEachDocs = null;
|
|
7763
|
+
const emitSuccess = (value) => {
|
|
7764
|
+
if (emitted)
|
|
7765
|
+
return;
|
|
7766
|
+
emitted = true;
|
|
7767
|
+
const terminalQueryArgs = [...meta.args];
|
|
7768
|
+
const queryRaw = buildMongoQueryPayload(meta.op, terminalQueryArgs, meta.dbName);
|
|
7769
|
+
queryRaw.cursorMethod = methodName;
|
|
7770
|
+
emitDbQuery(meta.cfg, meta.sid, meta.aid ?? undefined, {
|
|
7771
|
+
type: 'mongo',
|
|
7772
|
+
collection: meta.collection,
|
|
7773
|
+
op: meta.op,
|
|
7774
|
+
pk: buildMongoPk(meta.op, meta.args, value),
|
|
7775
|
+
before: null,
|
|
7776
|
+
after: buildMongoAfter(meta.op, meta.args, forEachDocs ?? value),
|
|
7777
|
+
queryRaw,
|
|
7778
|
+
resultMetaRaw: forEachDocs ?? value,
|
|
7779
|
+
durMs: Date.now() - t0,
|
|
7780
|
+
t: alignedNow(),
|
|
7781
|
+
spanContext: meta.spanContext,
|
|
7782
|
+
});
|
|
7783
|
+
};
|
|
7784
|
+
const emitFailure = (error) => {
|
|
7785
|
+
if (emitted)
|
|
7786
|
+
return;
|
|
7787
|
+
emitted = true;
|
|
7788
|
+
const terminalQueryArgs = [...meta.args];
|
|
7789
|
+
const queryRaw = buildMongoQueryPayload(meta.op, terminalQueryArgs, meta.dbName);
|
|
7790
|
+
queryRaw.cursorMethod = methodName;
|
|
7791
|
+
emitDbQuery(meta.cfg, meta.sid, meta.aid ?? undefined, {
|
|
7792
|
+
type: 'mongo',
|
|
7793
|
+
collection: meta.collection,
|
|
7794
|
+
op: meta.op,
|
|
7795
|
+
queryRaw,
|
|
7796
|
+
error: summarizeMongoError(error),
|
|
7797
|
+
durMs: Date.now() - t0,
|
|
7798
|
+
t: alignedNow(),
|
|
7799
|
+
spanContext: meta.spanContext,
|
|
7800
|
+
});
|
|
7801
|
+
};
|
|
7802
|
+
const actualArgs = [...callArgs];
|
|
7803
|
+
if (methodName === 'forEach' && typeof actualArgs[0] === 'function') {
|
|
7804
|
+
forEachDocs = [];
|
|
7805
|
+
const originalIterator = actualArgs[0];
|
|
7806
|
+
actualArgs[0] = function reproMongoForEachIterator(doc, ...rest) {
|
|
7807
|
+
forEachDocs?.push(doc);
|
|
7808
|
+
return originalIterator.call(this, doc, ...rest);
|
|
7809
|
+
};
|
|
7810
|
+
}
|
|
7811
|
+
try {
|
|
7812
|
+
const value = original.apply(this, actualArgs);
|
|
7813
|
+
if (value && typeof value.then === 'function') {
|
|
7814
|
+
return value.then((resolved) => {
|
|
7815
|
+
emitSuccess(resolved);
|
|
7816
|
+
return resolved;
|
|
7817
|
+
}, (err) => {
|
|
7818
|
+
emitFailure(err);
|
|
7819
|
+
throw err;
|
|
7820
|
+
});
|
|
7821
|
+
}
|
|
7822
|
+
emitSuccess(value);
|
|
7823
|
+
return value;
|
|
7824
|
+
}
|
|
7825
|
+
catch (err) {
|
|
7826
|
+
emitFailure(err);
|
|
7827
|
+
throw err;
|
|
7828
|
+
}
|
|
7829
|
+
};
|
|
7830
|
+
}
|
|
7831
|
+
return cursor;
|
|
7832
|
+
}
|
|
7833
|
+
function patchMongoCollectionMethod(proto, op, cursorOp, cfg) {
|
|
7834
|
+
if (!proto)
|
|
7835
|
+
return;
|
|
7836
|
+
const marker = `__repro_mongodb_${op}_patched`;
|
|
7837
|
+
if (proto[marker])
|
|
7838
|
+
return;
|
|
7839
|
+
const original = proto[op];
|
|
7840
|
+
if (typeof original !== 'function')
|
|
7841
|
+
return;
|
|
7842
|
+
proto[marker] = true;
|
|
7843
|
+
proto[op] = function reproPatchedMongoCollectionMethod(...args) {
|
|
7844
|
+
const collection = resolveMongoCollectionName(this);
|
|
7845
|
+
if (isNativeMongoSuppressed(collection, op)) {
|
|
7846
|
+
return original.apply(this, args);
|
|
7847
|
+
}
|
|
7848
|
+
const { sid, aid } = resolveMongoDbRuntimeContext(cfg);
|
|
7849
|
+
if (!sid) {
|
|
7850
|
+
return original.apply(this, args);
|
|
7851
|
+
}
|
|
7852
|
+
const spanContext = captureSpanContextFromTracer(this);
|
|
7853
|
+
const t0 = Date.now();
|
|
7854
|
+
const dbName = resolveMongoDbName(this);
|
|
7855
|
+
const callbackIndex = cursorOp ? -1 : findMongoCallbackIndex(args);
|
|
7856
|
+
const actualArgs = callbackIndex >= 0 ? [...args] : args;
|
|
7857
|
+
let emitted = false;
|
|
7858
|
+
const emitSuccess = (result) => {
|
|
7859
|
+
if (emitted)
|
|
7860
|
+
return;
|
|
7861
|
+
emitted = true;
|
|
7862
|
+
emitDbQuery(cfg, sid, aid ?? undefined, {
|
|
7863
|
+
type: 'mongo',
|
|
7864
|
+
collection,
|
|
7865
|
+
op,
|
|
7866
|
+
pk: buildMongoPk(op, args, result),
|
|
7867
|
+
before: null,
|
|
7868
|
+
after: buildMongoAfter(op, args, result),
|
|
7869
|
+
queryRaw: buildMongoQueryPayload(op, args, dbName),
|
|
7870
|
+
resultMetaRaw: result,
|
|
7871
|
+
durMs: Date.now() - t0,
|
|
7872
|
+
t: alignedNow(),
|
|
7873
|
+
spanContext,
|
|
7874
|
+
});
|
|
7875
|
+
};
|
|
7876
|
+
const emitFailure = (error) => {
|
|
7877
|
+
if (emitted)
|
|
7878
|
+
return;
|
|
7879
|
+
emitted = true;
|
|
7880
|
+
emitDbQuery(cfg, sid, aid ?? undefined, {
|
|
7881
|
+
type: 'mongo',
|
|
7882
|
+
collection,
|
|
7883
|
+
op,
|
|
7884
|
+
queryRaw: buildMongoQueryPayload(op, args, dbName),
|
|
7885
|
+
error: summarizeMongoError(error),
|
|
7886
|
+
durMs: Date.now() - t0,
|
|
7887
|
+
t: alignedNow(),
|
|
7888
|
+
spanContext,
|
|
7889
|
+
});
|
|
7890
|
+
};
|
|
7891
|
+
if (callbackIndex >= 0) {
|
|
7892
|
+
const originalCallback = args[callbackIndex];
|
|
7893
|
+
actualArgs[callbackIndex] = function reproMongoCallback(err, result, ...rest) {
|
|
7894
|
+
if (err)
|
|
7895
|
+
emitFailure(err);
|
|
7896
|
+
else
|
|
7897
|
+
emitSuccess(result);
|
|
7898
|
+
return originalCallback.call(this, err, result, ...rest);
|
|
7899
|
+
};
|
|
7900
|
+
}
|
|
7901
|
+
try {
|
|
7902
|
+
const result = original.apply(this, actualArgs);
|
|
7903
|
+
if (cursorOp) {
|
|
7904
|
+
return patchMongoCursorInstance(result, {
|
|
7905
|
+
cfg,
|
|
7906
|
+
sid,
|
|
7907
|
+
aid,
|
|
7908
|
+
collection,
|
|
7909
|
+
dbName,
|
|
7910
|
+
op,
|
|
7911
|
+
args,
|
|
7912
|
+
spanContext,
|
|
7913
|
+
});
|
|
7914
|
+
}
|
|
7915
|
+
if (result && typeof result.then === 'function') {
|
|
7916
|
+
return result.then((value) => {
|
|
7917
|
+
emitSuccess(value);
|
|
7918
|
+
return value;
|
|
7919
|
+
}, (error) => {
|
|
7920
|
+
emitFailure(error);
|
|
7921
|
+
throw error;
|
|
7922
|
+
});
|
|
7923
|
+
}
|
|
7924
|
+
if (callbackIndex < 0) {
|
|
7925
|
+
emitSuccess(result);
|
|
7926
|
+
}
|
|
7927
|
+
return result;
|
|
7928
|
+
}
|
|
7929
|
+
catch (error) {
|
|
7930
|
+
emitFailure(error);
|
|
7931
|
+
throw error;
|
|
7932
|
+
}
|
|
7933
|
+
};
|
|
7934
|
+
}
|
|
7935
|
+
function patchMongoCollectionPrototype(proto, cfg) {
|
|
7936
|
+
if (!proto)
|
|
7937
|
+
return;
|
|
7938
|
+
for (const op of MONGODB_PROMISE_OPS) {
|
|
7939
|
+
patchMongoCollectionMethod(proto, op, false, cfg);
|
|
7940
|
+
}
|
|
7941
|
+
for (const op of MONGODB_CURSOR_OPS) {
|
|
7942
|
+
patchMongoCollectionMethod(proto, op, true, cfg);
|
|
7943
|
+
}
|
|
7944
|
+
}
|
|
7945
|
+
function patchMongoDbFromModuleExports(mongoModule, cfg) {
|
|
7946
|
+
if (!mongoModule)
|
|
7947
|
+
return;
|
|
7948
|
+
const constructors = new Set();
|
|
7949
|
+
const addCtor = (candidate) => {
|
|
7950
|
+
if (typeof candidate === 'function' && candidate.prototype) {
|
|
7951
|
+
constructors.add(candidate);
|
|
7952
|
+
}
|
|
7953
|
+
};
|
|
7954
|
+
addCtor(mongoModule?.Collection);
|
|
7955
|
+
addCtor(mongoModule?.default?.Collection);
|
|
7956
|
+
for (const ctor of constructors) {
|
|
7957
|
+
patchMongoCollectionPrototype(ctor.prototype, cfg);
|
|
7958
|
+
}
|
|
7959
|
+
}
|
|
7960
|
+
function installMongoDbRequireHook() {
|
|
7961
|
+
if (mongoDbRequireHookInstalled)
|
|
7962
|
+
return;
|
|
7963
|
+
mongoDbRequireHookInstalled = true;
|
|
7964
|
+
try {
|
|
7965
|
+
const rim = requireOptionalHostModule('require-in-the-middle');
|
|
7966
|
+
const Hook = rim?.Hook ?? rim;
|
|
7967
|
+
if (typeof Hook !== 'function')
|
|
7968
|
+
return;
|
|
7969
|
+
// eslint-disable-next-line no-new
|
|
7970
|
+
new Hook(['mongodb'], (exports) => {
|
|
7971
|
+
for (const cfg of mongoDbPatchConfigs) {
|
|
7972
|
+
patchMongoDbFromModuleExports(exports, cfg);
|
|
7973
|
+
}
|
|
7974
|
+
return exports;
|
|
7975
|
+
});
|
|
7976
|
+
}
|
|
7977
|
+
catch { }
|
|
7978
|
+
}
|
|
7979
|
+
function patchMongoDb(cfg) {
|
|
7980
|
+
mongoDbPatchConfigs.push(cfg);
|
|
7981
|
+
installMongoDbRequireHook();
|
|
7982
|
+
const mongoModules = new Set();
|
|
7983
|
+
for (const loadedMongoModule of getLoadedModuleExportsByPackage('mongodb')) {
|
|
7984
|
+
mongoModules.add(loadedMongoModule);
|
|
7985
|
+
}
|
|
7986
|
+
if (!mongoModules.size)
|
|
7987
|
+
return;
|
|
7988
|
+
for (const mongoModule of mongoModules) {
|
|
7989
|
+
patchMongoDbFromModuleExports(mongoModule, cfg);
|
|
7990
|
+
}
|
|
7991
|
+
}
|
|
7992
|
+
exports.patchMongoDb = patchMongoDb;
|
|
7412
7993
|
// ===================================================================
|
|
7413
7994
|
// Auto init helpers
|
|
7414
7995
|
// ===================================================================
|
|
@@ -7834,6 +8415,7 @@ async function initRepro(cfg) {
|
|
|
7834
8415
|
patchKafkaJs(integrationCfg);
|
|
7835
8416
|
patchAmqplib(integrationCfg);
|
|
7836
8417
|
patchRedis(integrationCfg);
|
|
8418
|
+
patchMongoDb(integrationCfg);
|
|
7837
8419
|
patchSendgridMail(integrationCfg);
|
|
7838
8420
|
patchMongooseIntegration(reproAutoMiddlewareConfig);
|
|
7839
8421
|
await initializeRuntimePrivacyPolicyAtStartup(reproAutoMiddlewareConfig);
|
|
@@ -7881,6 +8463,8 @@ exports.__reproTestHooks = {
|
|
|
7881
8463
|
patchAmqplibConnectionForTest: patchAmqplibConnection,
|
|
7882
8464
|
patchAmqplibChannelForTest: patchAmqplibChannel,
|
|
7883
8465
|
wrapAmqplibConsumeHandlerForTest: wrapAmqplibConsumeHandler,
|
|
8466
|
+
patchMongoDbModuleForTest: patchMongoDbFromModuleExports,
|
|
8467
|
+
patchMongoCollectionPrototypeForTest: patchMongoCollectionPrototype,
|
|
7884
8468
|
chunkTraceEventsForTransportForTest: chunkTraceEventsForTransport,
|
|
7885
8469
|
estimateTraceBatchSerializedBytesForTest: estimateTraceBatchSerializedBytes,
|
|
7886
8470
|
sanitizeTraceValueForPrivacyForTest: sanitizeTraceValueForPrivacy,
|