@use-tusk/drift-node-sdk 0.1.7 → 0.1.8
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/README.md +1 -0
- package/dist/index.cjs +1617 -139
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1617 -140
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -58,6 +58,10 @@ let __use_tusk_drift_schemas_backend_span_export_service = require("@use-tusk/dr
|
|
|
58
58
|
__use_tusk_drift_schemas_backend_span_export_service = __toESM(__use_tusk_drift_schemas_backend_span_export_service);
|
|
59
59
|
let jsonpath = require("jsonpath");
|
|
60
60
|
jsonpath = __toESM(jsonpath);
|
|
61
|
+
let net = require("net");
|
|
62
|
+
net = __toESM(net);
|
|
63
|
+
let stream = require("stream");
|
|
64
|
+
stream = __toESM(stream);
|
|
61
65
|
let __opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
62
66
|
__opentelemetry_semantic_conventions = __toESM(__opentelemetry_semantic_conventions);
|
|
63
67
|
let __use_tusk_drift_schemas_backend_span_export_service_client = require("@use-tusk/drift-schemas/backend/span_export_service.client");
|
|
@@ -66,8 +70,6 @@ let __protobuf_ts_twirp_transport = require("@protobuf-ts/twirp-transport");
|
|
|
66
70
|
__protobuf_ts_twirp_transport = __toESM(__protobuf_ts_twirp_transport);
|
|
67
71
|
let __opentelemetry_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
|
|
68
72
|
__opentelemetry_sdk_trace_node = __toESM(__opentelemetry_sdk_trace_node);
|
|
69
|
-
let net = require("net");
|
|
70
|
-
net = __toESM(net);
|
|
71
73
|
let child_process = require("child_process");
|
|
72
74
|
child_process = __toESM(child_process);
|
|
73
75
|
let __use_tusk_drift_schemas_core_communication = require("@use-tusk/drift-schemas/core/communication");
|
|
@@ -273,7 +275,7 @@ var TdInstrumentationAbstract = class {
|
|
|
273
275
|
|
|
274
276
|
//#endregion
|
|
275
277
|
//#region package.json
|
|
276
|
-
var version = "0.1.
|
|
278
|
+
var version = "0.1.8";
|
|
277
279
|
|
|
278
280
|
//#endregion
|
|
279
281
|
//#region src/version.ts
|
|
@@ -470,6 +472,20 @@ function loadTuskConfig() {
|
|
|
470
472
|
}
|
|
471
473
|
}
|
|
472
474
|
|
|
475
|
+
//#endregion
|
|
476
|
+
//#region src/core/utils/runtimeDetectionUtils.ts
|
|
477
|
+
function isNextJsRuntime() {
|
|
478
|
+
return process.env.NEXT_RUNTIME !== void 0 || typeof global.__NEXT_DATA__ !== "undefined";
|
|
479
|
+
}
|
|
480
|
+
function isEsm(moduleExports) {
|
|
481
|
+
if (!moduleExports || typeof moduleExports !== "object") return false;
|
|
482
|
+
try {
|
|
483
|
+
return moduleExports[Symbol.toStringTag] === "Module";
|
|
484
|
+
} catch (error) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
473
489
|
//#endregion
|
|
474
490
|
//#region src/core/utils/logger.ts
|
|
475
491
|
var Logger = class {
|
|
@@ -749,9 +765,11 @@ var TdInstrumentationNodeModule = class {
|
|
|
749
765
|
|
|
750
766
|
//#endregion
|
|
751
767
|
//#region src/core/types.ts
|
|
768
|
+
const TD_INSTRUMENTATION_LIBRARY_NAME = "tusk-drift-sdk";
|
|
752
769
|
const REPLAY_TRACE_ID_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.replayTraceId");
|
|
753
770
|
const SPAN_KIND_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.spanKind");
|
|
754
771
|
const IS_PRE_APP_START_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.isPreAppStart");
|
|
772
|
+
const STOP_RECORDING_CHILD_SPANS_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.stopRecordingChildSpans");
|
|
755
773
|
const CALLING_LIBRARY_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.callingLibrary");
|
|
756
774
|
let TdSpanAttributes = /* @__PURE__ */ function(TdSpanAttributes$1) {
|
|
757
775
|
/**
|
|
@@ -794,6 +812,74 @@ let TdSpanAttributes = /* @__PURE__ */ function(TdSpanAttributes$1) {
|
|
|
794
812
|
return TdSpanAttributes$1;
|
|
795
813
|
}({});
|
|
796
814
|
|
|
815
|
+
//#endregion
|
|
816
|
+
//#region src/core/tracing/TraceBlockingManager.ts
|
|
817
|
+
/**
|
|
818
|
+
* Manages blocked trace IDs to prevent creation and export of spans
|
|
819
|
+
* that belong to traces exceeding size limits.
|
|
820
|
+
*
|
|
821
|
+
* This class uses an in-memory Set for O(1) lookup performance and
|
|
822
|
+
* automatically cleans up old entries to prevent memory leaks.
|
|
823
|
+
*/
|
|
824
|
+
var TraceBlockingManager = class TraceBlockingManager {
|
|
825
|
+
constructor() {
|
|
826
|
+
this.blockedTraceIds = /* @__PURE__ */ new Set();
|
|
827
|
+
this.traceTimestamps = /* @__PURE__ */ new Map();
|
|
828
|
+
this.cleanupIntervalId = null;
|
|
829
|
+
this.DEFAULT_TTL_MS = 600 * 1e3;
|
|
830
|
+
this.CLEANUP_INTERVAL_MS = 120 * 1e3;
|
|
831
|
+
this.startCleanupInterval();
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Get singleton instance
|
|
835
|
+
*/
|
|
836
|
+
static getInstance() {
|
|
837
|
+
if (!TraceBlockingManager.instance) TraceBlockingManager.instance = new TraceBlockingManager();
|
|
838
|
+
return TraceBlockingManager.instance;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Check if a trace ID is blocked
|
|
842
|
+
*/
|
|
843
|
+
isTraceBlocked(traceId) {
|
|
844
|
+
return this.blockedTraceIds.has(traceId);
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Block a trace ID and all future spans for this trace
|
|
848
|
+
*/
|
|
849
|
+
blockTrace(traceId) {
|
|
850
|
+
if (!this.blockedTraceIds.has(traceId)) {
|
|
851
|
+
this.blockedTraceIds.add(traceId);
|
|
852
|
+
const originalDate = OriginalGlobalUtils.getOriginalDate();
|
|
853
|
+
this.traceTimestamps.set(traceId, originalDate.getTime());
|
|
854
|
+
logger.debug(`[TraceBlockingManager] Blocked trace: ${traceId}`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Start periodic cleanup of old blocked trace IDs
|
|
859
|
+
*/
|
|
860
|
+
startCleanupInterval() {
|
|
861
|
+
if (this.cleanupIntervalId) return;
|
|
862
|
+
this.cleanupIntervalId = setInterval(() => {
|
|
863
|
+
this.cleanupOldTraces();
|
|
864
|
+
}, this.CLEANUP_INTERVAL_MS);
|
|
865
|
+
if (this.cleanupIntervalId.unref) this.cleanupIntervalId.unref();
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Clean up trace IDs older than TTL
|
|
869
|
+
*/
|
|
870
|
+
cleanupOldTraces() {
|
|
871
|
+
const now = OriginalGlobalUtils.getOriginalDate().getTime();
|
|
872
|
+
const expiredTraces = [];
|
|
873
|
+
for (const [traceId, timestamp] of this.traceTimestamps.entries()) if (now - timestamp > this.DEFAULT_TTL_MS) expiredTraces.push(traceId);
|
|
874
|
+
for (const traceId of expiredTraces) {
|
|
875
|
+
this.blockedTraceIds.delete(traceId);
|
|
876
|
+
this.traceTimestamps.delete(traceId);
|
|
877
|
+
}
|
|
878
|
+
if (expiredTraces.length > 0) logger.debug(`[TraceBlockingManager] Cleaned up ${expiredTraces.length} expired blocked trace(s)`);
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
TraceBlockingManager.instance = null;
|
|
882
|
+
|
|
797
883
|
//#endregion
|
|
798
884
|
//#region src/core/tracing/SpanUtils.ts
|
|
799
885
|
var SpanUtils = class SpanUtils {
|
|
@@ -804,6 +890,14 @@ var SpanUtils = class SpanUtils {
|
|
|
804
890
|
try {
|
|
805
891
|
const tracer = TuskDriftCore.getInstance().getTracer();
|
|
806
892
|
const parentContext = options.parentContext || __opentelemetry_api.context.active();
|
|
893
|
+
const activeSpan = __opentelemetry_api.trace.getSpan(parentContext);
|
|
894
|
+
if (activeSpan) {
|
|
895
|
+
const parentTraceId = activeSpan.spanContext().traceId;
|
|
896
|
+
if (TraceBlockingManager.getInstance().isTraceBlocked(parentTraceId)) {
|
|
897
|
+
logger.debug(`[SpanUtils] Skipping span creation for '${options.name}' - trace ${parentTraceId} is blocked`);
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
807
901
|
const span = tracer.startSpan(options.name, {
|
|
808
902
|
kind: options.kind || __opentelemetry_api.SpanKind.CLIENT,
|
|
809
903
|
attributes: options.attributes || {}
|
|
@@ -843,7 +937,14 @@ var SpanUtils = class SpanUtils {
|
|
|
843
937
|
* @returns The result of the function execution
|
|
844
938
|
*/
|
|
845
939
|
static createAndExecuteSpan(mode, originalFunctionCall, options, fn) {
|
|
846
|
-
const
|
|
940
|
+
const spanContext = __opentelemetry_api.trace.getActiveSpan()?.spanContext();
|
|
941
|
+
if (spanContext) {
|
|
942
|
+
if (__opentelemetry_api.context.active().getValue(STOP_RECORDING_CHILD_SPANS_CONTEXT_KEY)) {
|
|
943
|
+
logger.debug(`[SpanUtils] Stopping recording of child spans for span ${spanContext.spanId}, packageName: ${options.packageName}, instrumentationName: ${options.instrumentationName}`);
|
|
944
|
+
return originalFunctionCall();
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
const { name, kind, packageName, instrumentationName, packageType, submodule, inputValue, inputSchemaMerges, isPreAppStart, metadata, stopRecordingChildSpans } = options;
|
|
847
948
|
let spanInfo = null;
|
|
848
949
|
try {
|
|
849
950
|
spanInfo = SpanUtils.createSpan({
|
|
@@ -868,6 +969,7 @@ var SpanUtils = class SpanUtils {
|
|
|
868
969
|
}
|
|
869
970
|
if (!spanInfo) if (mode === TuskDriftMode.REPLAY) throw new Error("Error creating span in replay mode");
|
|
870
971
|
else return originalFunctionCall();
|
|
972
|
+
if (stopRecordingChildSpans) spanInfo.context = spanInfo.context.setValue(STOP_RECORDING_CHILD_SPANS_CONTEXT_KEY, true);
|
|
871
973
|
return SpanUtils.withSpan(spanInfo, () => fn(spanInfo));
|
|
872
974
|
}
|
|
873
975
|
/**
|
|
@@ -1123,6 +1225,22 @@ function getDecodedType(contentType) {
|
|
|
1123
1225
|
const mainType = contentTypeString.toLowerCase().split(";")[0].trim();
|
|
1124
1226
|
return CONTENT_TYPE_MAPPING[mainType];
|
|
1125
1227
|
}
|
|
1228
|
+
const STATIC_ASSET_TYPES = new Set([
|
|
1229
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.HTML,
|
|
1230
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.CSS,
|
|
1231
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.JAVASCRIPT,
|
|
1232
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.JPEG,
|
|
1233
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.PNG,
|
|
1234
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.GIF,
|
|
1235
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.WEBP,
|
|
1236
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.SVG,
|
|
1237
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.PDF,
|
|
1238
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.AUDIO,
|
|
1239
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.VIDEO,
|
|
1240
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.BINARY,
|
|
1241
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.ZIP,
|
|
1242
|
+
__use_tusk_drift_schemas_core_json_schema.DecodedType.GZIP
|
|
1243
|
+
]);
|
|
1126
1244
|
|
|
1127
1245
|
//#endregion
|
|
1128
1246
|
//#region src/instrumentation/libraries/http/mocks/TdHttpMockSocket.ts
|
|
@@ -1597,6 +1715,28 @@ async function findMockResponseAsync({ mockRequestData, tuskDrift, inputValueSch
|
|
|
1597
1715
|
return null;
|
|
1598
1716
|
}
|
|
1599
1717
|
}
|
|
1718
|
+
function findMockResponseSync({ mockRequestData, tuskDrift, inputValueSchemaMerges }) {
|
|
1719
|
+
const outboundSpan = convertMockRequestDataToCleanSpanData(mockRequestData, tuskDrift, inputValueSchemaMerges);
|
|
1720
|
+
try {
|
|
1721
|
+
const replayTraceId = SpanUtils.getCurrentReplayTraceId();
|
|
1722
|
+
logger.debug(`Finding ${outboundSpan.traceId} mock for replay trace ID: ${replayTraceId}`);
|
|
1723
|
+
const mockResponse = tuskDrift.requestMockSync({
|
|
1724
|
+
outboundSpan,
|
|
1725
|
+
testId: replayTraceId || ""
|
|
1726
|
+
});
|
|
1727
|
+
if (!mockResponse || !mockResponse.found) {
|
|
1728
|
+
logger.debug(`No matching mock found for ${outboundSpan.traceId} with input value: ${JSON.stringify(outboundSpan.inputValue)}`, replayTraceId);
|
|
1729
|
+
return null;
|
|
1730
|
+
}
|
|
1731
|
+
const responseBody = mockResponse.response?.response?.body;
|
|
1732
|
+
logger.debug(`Found ${outboundSpan.traceId} mock response and timestamp:`, responseBody, { timestamp: mockResponse.response?.timestamp });
|
|
1733
|
+
if (mockResponse.response?.timestamp) DateTracker.updateLatestTimestamp(replayTraceId || "", mockResponse.response.timestamp);
|
|
1734
|
+
return { result: responseBody };
|
|
1735
|
+
} catch (error) {
|
|
1736
|
+
logger.error(`Error finding ${outboundSpan.traceId} mock response:`, error);
|
|
1737
|
+
return null;
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1600
1740
|
|
|
1601
1741
|
//#endregion
|
|
1602
1742
|
//#region src/instrumentation/libraries/http/mocks/TdMockClientRequest.ts
|
|
@@ -2009,7 +2149,7 @@ function wrap(target, propertyName, wrapper) {
|
|
|
2009
2149
|
* Helper functions for capturing stack traces in replay mode
|
|
2010
2150
|
*
|
|
2011
2151
|
* TODO: Consider using a structured format for stack frames:
|
|
2012
|
-
*
|
|
2152
|
+
*
|
|
2013
2153
|
* {
|
|
2014
2154
|
* "frames": [
|
|
2015
2155
|
* {
|
|
@@ -2025,7 +2165,7 @@ function wrap(target, propertyName, wrapper) {
|
|
|
2025
2165
|
* It would also allow for more accurate stack trace reconstruction in replay mode.
|
|
2026
2166
|
*/
|
|
2027
2167
|
/**
|
|
2028
|
-
*
|
|
2168
|
+
*
|
|
2029
2169
|
* @param excludeClassNames - Class names to exclude from the stack trace
|
|
2030
2170
|
* @returns The stack trace as a string
|
|
2031
2171
|
*/
|
|
@@ -2438,7 +2578,7 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2438
2578
|
logger.debug(`[HttpInstrumentation] ${protocolUpper} module already patched, skipping`);
|
|
2439
2579
|
return httpModule;
|
|
2440
2580
|
}
|
|
2441
|
-
if (httpModule
|
|
2581
|
+
if (isEsm(httpModule)) {
|
|
2442
2582
|
if (httpModule.default) {
|
|
2443
2583
|
this._wrap(httpModule.default, "request", this._getRequestPatchFn(protocol));
|
|
2444
2584
|
this._wrap(httpModule.default, "get", this._getGetPatchFn(protocol));
|
|
@@ -2457,11 +2597,18 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2457
2597
|
return httpModule;
|
|
2458
2598
|
}
|
|
2459
2599
|
_createServerSpan({ req, res, originalHandler, protocol }) {
|
|
2600
|
+
if (isNextJsRuntime()) {
|
|
2601
|
+
logger.debug(`[HttpInstrumentation] Skipping recording/replaying for nextJs runtime, handled by nextJs instrumentation`);
|
|
2602
|
+
return originalHandler.call(this);
|
|
2603
|
+
}
|
|
2460
2604
|
const method = req.method || "GET";
|
|
2461
2605
|
const url = req.url || "/";
|
|
2462
2606
|
const target = req.url || "/";
|
|
2463
2607
|
const spanProtocol = this._normalizeProtocol(protocol, "http");
|
|
2464
|
-
if (isTuskDriftIngestionUrl(url) || isTuskDriftIngestionUrl(target))
|
|
2608
|
+
if (isTuskDriftIngestionUrl(url) || isTuskDriftIngestionUrl(target)) {
|
|
2609
|
+
logger.debug(`[HttpInstrumentation] Ignoring drift ingestion endpoints`);
|
|
2610
|
+
return originalHandler.call(this);
|
|
2611
|
+
}
|
|
2465
2612
|
if (this.transformEngine.shouldDropInboundRequest(method, url, req.headers)) {
|
|
2466
2613
|
logger.debug(`[HttpInstrumentation] Dropping inbound request due to transforms: ${method} ${url}`);
|
|
2467
2614
|
return originalHandler.call(this);
|
|
@@ -2479,7 +2626,10 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2479
2626
|
remotePort: req.socket?.remotePort
|
|
2480
2627
|
};
|
|
2481
2628
|
const replayTraceId = this.replayHooks.extractTraceIdFromHeaders(req);
|
|
2482
|
-
if (!replayTraceId)
|
|
2629
|
+
if (!replayTraceId) {
|
|
2630
|
+
logger.debug(`[HttpInstrumentation] No trace id found in headers`, req.headers);
|
|
2631
|
+
return originalHandler.call(this);
|
|
2632
|
+
}
|
|
2483
2633
|
logger.debug(`[HttpInstrumentation] Setting replay trace id`, replayTraceId);
|
|
2484
2634
|
const envVars = this.replayHooks.extractEnvVarsFromHeaders(req);
|
|
2485
2635
|
if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
|
|
@@ -2511,13 +2661,6 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2511
2661
|
} });
|
|
2512
2662
|
else if (this.mode === TuskDriftMode.RECORD) {
|
|
2513
2663
|
if (method.toUpperCase() === "OPTIONS" || !!req.headers["access-control-request-method"]) return originalHandler.call(this);
|
|
2514
|
-
if (!shouldSample({
|
|
2515
|
-
samplingRate: this.tuskDrift.getSamplingRate(),
|
|
2516
|
-
isAppReady: this.tuskDrift.isAppReady()
|
|
2517
|
-
})) {
|
|
2518
|
-
logger.debug(`Skipping server span due to sampling rate`, url, this.tuskDrift.getSamplingRate());
|
|
2519
|
-
return originalHandler.call(this);
|
|
2520
|
-
}
|
|
2521
2664
|
logger.debug(`[HttpInstrumentation] Creating server span for ${method} ${url}`);
|
|
2522
2665
|
return handleRecordMode({
|
|
2523
2666
|
originalFunctionCall: () => originalHandler.call(this),
|
|
@@ -2611,7 +2754,6 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2611
2754
|
outputValue.bodySize = responseBuffer.length;
|
|
2612
2755
|
} catch (error) {
|
|
2613
2756
|
logger.error(`[HttpInstrumentation] Error processing server response body:`, error);
|
|
2614
|
-
outputValue.bodyProcessingError = error instanceof Error ? error.message : String(error);
|
|
2615
2757
|
}
|
|
2616
2758
|
try {
|
|
2617
2759
|
const spanData = {
|
|
@@ -2629,7 +2771,7 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2629
2771
|
outputSchemaMerges: {
|
|
2630
2772
|
body: {
|
|
2631
2773
|
encoding: __use_tusk_drift_schemas_core_json_schema.EncodingType.BASE64,
|
|
2632
|
-
decodedType: getDecodedType(spanData.outputValue
|
|
2774
|
+
decodedType: getDecodedType(spanData.outputValue?.headers?.["content-type"] || "")
|
|
2633
2775
|
},
|
|
2634
2776
|
headers: { matchImportance: 0 }
|
|
2635
2777
|
},
|
|
@@ -2642,6 +2784,11 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2642
2784
|
message: `HTTP ${statusCode}`
|
|
2643
2785
|
} : { code: __opentelemetry_api.SpanStatusCode.OK };
|
|
2644
2786
|
SpanUtils.setStatus(spanInfo.span, status);
|
|
2787
|
+
const decodedType = getDecodedType(outputValue.headers?.["content-type"] || "");
|
|
2788
|
+
if (decodedType && STATIC_ASSET_TYPES.has(decodedType)) {
|
|
2789
|
+
TraceBlockingManager.getInstance().blockTrace(spanInfo.traceId);
|
|
2790
|
+
logger.debug(`[HttpInstrumentation] Blocking trace ${spanInfo.traceId} because it is an static asset response. Decoded type: ${decodedType}`);
|
|
2791
|
+
}
|
|
2645
2792
|
SpanUtils.endSpan(spanInfo.span);
|
|
2646
2793
|
} catch (error) {
|
|
2647
2794
|
logger.error(`[HttpInstrumentation] Error adding response attributes to span:`, error);
|
|
@@ -3143,6 +3290,12 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
3143
3290
|
return (originalEmit) => {
|
|
3144
3291
|
return function(eventName, ...args) {
|
|
3145
3292
|
if (eventName === "request") {
|
|
3293
|
+
if (self.mode === TuskDriftMode.RECORD) {
|
|
3294
|
+
if (!shouldSample({
|
|
3295
|
+
samplingRate: self.tuskDrift.getSamplingRate(),
|
|
3296
|
+
isAppReady: self.tuskDrift.isAppReady()
|
|
3297
|
+
})) return originalEmit.apply(this, [eventName, ...args]);
|
|
3298
|
+
}
|
|
3146
3299
|
const req = args[0];
|
|
3147
3300
|
const res = args[1];
|
|
3148
3301
|
return self._createServerSpan({
|
|
@@ -4055,7 +4208,7 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
|
|
|
4055
4208
|
return postgresModule;
|
|
4056
4209
|
}
|
|
4057
4210
|
const self = this;
|
|
4058
|
-
if (postgresModule
|
|
4211
|
+
if (isEsm(postgresModule)) {
|
|
4059
4212
|
logger.debug(`[PostgresInstrumentation] Wrapping ESM default export`);
|
|
4060
4213
|
this._wrap(postgresModule, "default", (originalFunction) => {
|
|
4061
4214
|
return function(...args) {
|
|
@@ -5821,6 +5974,7 @@ var TcpInstrumentation = class extends TdInstrumentationBase {
|
|
|
5821
5974
|
super("tcp", config);
|
|
5822
5975
|
this.loggedSpans = /* @__PURE__ */ new Set();
|
|
5823
5976
|
this.mode = config.mode || TuskDriftMode.DISABLED;
|
|
5977
|
+
this._patchLoadedModules();
|
|
5824
5978
|
}
|
|
5825
5979
|
init() {
|
|
5826
5980
|
return [new TdInstrumentationNodeModule({
|
|
@@ -5829,6 +5983,17 @@ var TcpInstrumentation = class extends TdInstrumentationBase {
|
|
|
5829
5983
|
patch: (moduleExports) => this._patchNetModule(moduleExports)
|
|
5830
5984
|
})];
|
|
5831
5985
|
}
|
|
5986
|
+
_patchLoadedModules() {
|
|
5987
|
+
if (isNextJsRuntime()) {
|
|
5988
|
+
logger.debug(`[TcpInstrumentation] Next.js environment detected - force-loading net module to ensure patching`);
|
|
5989
|
+
try {
|
|
5990
|
+
require("net");
|
|
5991
|
+
logger.debug(`[TcpInstrumentation] net module force-loaded`);
|
|
5992
|
+
} catch (err) {
|
|
5993
|
+
logger.error(`[TcpInstrumentation] Error force-loading net module:`, err);
|
|
5994
|
+
}
|
|
5995
|
+
} else logger.debug(`[TcpInstrumentation] Regular Node.js environment - hooks will catch net module on first require`);
|
|
5996
|
+
}
|
|
5832
5997
|
_patchNetModule(netModule) {
|
|
5833
5998
|
logger.debug(`[TcpInstrumentation] Patching NET module in ${this.mode} mode`);
|
|
5834
5999
|
if (this.isModulePatched(netModule)) {
|
|
@@ -6981,7 +7146,7 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
|
|
|
6981
7146
|
logger.debug(`[IORedisInstrumentation] IORedis module already patched, skipping`);
|
|
6982
7147
|
return moduleExports;
|
|
6983
7148
|
}
|
|
6984
|
-
const actualExports = moduleExports
|
|
7149
|
+
const actualExports = isEsm(moduleExports) ? moduleExports.default : moduleExports;
|
|
6985
7150
|
if (!actualExports || !actualExports.prototype) {
|
|
6986
7151
|
logger.error(`[IORedisInstrumentation] Invalid module exports, cannot patch`);
|
|
6987
7152
|
return moduleExports;
|
|
@@ -7020,7 +7185,7 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
|
|
|
7020
7185
|
logger.debug(`[IORedisInstrumentation] Pipeline module already patched, skipping`);
|
|
7021
7186
|
return moduleExports;
|
|
7022
7187
|
}
|
|
7023
|
-
const actualExports = moduleExports
|
|
7188
|
+
const actualExports = isEsm(moduleExports) ? moduleExports.default : moduleExports;
|
|
7024
7189
|
if (!actualExports || !actualExports.prototype) {
|
|
7025
7190
|
logger.debug(`[IORedisInstrumentation] Invalid Pipeline module exports, cannot patch`);
|
|
7026
7191
|
return moduleExports;
|
|
@@ -7613,6 +7778,7 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
|
|
|
7613
7778
|
return;
|
|
7614
7779
|
}
|
|
7615
7780
|
this._wrap(clientPrototype, "makeUnaryRequest", this._getMakeUnaryRequestPatchFn(version$1));
|
|
7781
|
+
this._wrap(clientPrototype, "makeServerStreamRequest", this._getMakeServerStreamRequestPatchFn(version$1));
|
|
7616
7782
|
this._wrap(clientPrototype, "waitForReady", this._getWaitForReadyPatchFn());
|
|
7617
7783
|
this._wrap(clientPrototype, "close", this._getClosePatchFn());
|
|
7618
7784
|
this._wrap(clientPrototype, "getChannel", this._getGetChannelPatchFn());
|
|
@@ -7662,6 +7828,7 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
|
|
|
7662
7828
|
logger.debug(`[GrpcInstrumentation] _getMakeUnaryRequestPatchFn called for version: ${version$1}`);
|
|
7663
7829
|
return (original) => {
|
|
7664
7830
|
return function makeUnaryRequest(...args) {
|
|
7831
|
+
logger.debug(`[GrpcInstrumentation] makeUnaryRequest called! args length: ${args.length}`);
|
|
7665
7832
|
const MetadataConstructor = GrpcInstrumentation.metadataStore.get(version$1) || self.Metadata;
|
|
7666
7833
|
if (!MetadataConstructor) {
|
|
7667
7834
|
logger.warn(`[GrpcInstrumentation] Metadata constructor not found for version ${version$1}`);
|
|
@@ -7737,6 +7904,115 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
|
|
|
7737
7904
|
};
|
|
7738
7905
|
};
|
|
7739
7906
|
}
|
|
7907
|
+
_getMakeServerStreamRequestPatchFn(version$1) {
|
|
7908
|
+
const self = this;
|
|
7909
|
+
logger.debug(`[GrpcInstrumentation] _getMakeServerStreamRequestPatchFn called for version: ${version$1}`);
|
|
7910
|
+
return (original) => {
|
|
7911
|
+
return function makeServerStreamRequest(...args) {
|
|
7912
|
+
logger.debug(`[GrpcInstrumentation] makeServerStreamRequest called! args length: ${args.length}`);
|
|
7913
|
+
const MetadataConstructor = GrpcInstrumentation.metadataStore.get(version$1) || self.Metadata;
|
|
7914
|
+
if (!MetadataConstructor) {
|
|
7915
|
+
logger.warn(`[GrpcInstrumentation] Metadata constructor not found for version ${version$1}`);
|
|
7916
|
+
return original.apply(this, args);
|
|
7917
|
+
}
|
|
7918
|
+
let parsedParams;
|
|
7919
|
+
try {
|
|
7920
|
+
parsedParams = self.extractServerStreamRequestParameters(args, MetadataConstructor);
|
|
7921
|
+
} catch (error) {
|
|
7922
|
+
logger.error(`[GrpcInstrumentation] Error parsing makeServerStreamRequest arguments:`, error);
|
|
7923
|
+
return original.apply(this, args);
|
|
7924
|
+
}
|
|
7925
|
+
const { method: path$5, argument, metadata, options } = parsedParams;
|
|
7926
|
+
let method;
|
|
7927
|
+
let service;
|
|
7928
|
+
let readableBody;
|
|
7929
|
+
let bufferMap;
|
|
7930
|
+
let jsonableStringMap;
|
|
7931
|
+
let readableMetadata;
|
|
7932
|
+
try {
|
|
7933
|
+
({method, service} = parseGrpcPath(path$5));
|
|
7934
|
+
({readableBody, bufferMap, jsonableStringMap} = serializeGrpcPayload(argument));
|
|
7935
|
+
readableMetadata = serializeGrpcMetadata(metadata);
|
|
7936
|
+
} catch (error) {
|
|
7937
|
+
logger.error(`[GrpcInstrumentation] Error parsing makeServerStreamRequest arguments:`, error);
|
|
7938
|
+
return original.apply(this, args);
|
|
7939
|
+
}
|
|
7940
|
+
const inputValue = {
|
|
7941
|
+
method,
|
|
7942
|
+
service,
|
|
7943
|
+
body: readableBody,
|
|
7944
|
+
metadata: readableMetadata,
|
|
7945
|
+
inputMeta: {
|
|
7946
|
+
bufferMap,
|
|
7947
|
+
jsonableStringMap
|
|
7948
|
+
}
|
|
7949
|
+
};
|
|
7950
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
7951
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => original.apply(this, args), {
|
|
7952
|
+
name: "grpc.client.server_stream",
|
|
7953
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
7954
|
+
submodule: "client",
|
|
7955
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
|
|
7956
|
+
packageName: GRPC_MODULE_NAME,
|
|
7957
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
7958
|
+
inputValue,
|
|
7959
|
+
isPreAppStart: false
|
|
7960
|
+
}, (spanInfo) => {
|
|
7961
|
+
return self._handleReplayServerStreamRequest(spanInfo, inputValue, MetadataConstructor);
|
|
7962
|
+
});
|
|
7963
|
+
} });
|
|
7964
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
7965
|
+
originalFunctionCall: () => original.apply(this, args),
|
|
7966
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
7967
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => original.apply(this, args), {
|
|
7968
|
+
name: "grpc.client.server_stream",
|
|
7969
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
7970
|
+
submodule: "client",
|
|
7971
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
|
|
7972
|
+
packageName: GRPC_MODULE_NAME,
|
|
7973
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
7974
|
+
inputValue,
|
|
7975
|
+
isPreAppStart
|
|
7976
|
+
}, (spanInfo) => {
|
|
7977
|
+
return self._handleRecordServerStreamRequest(spanInfo, original, this, parsedParams);
|
|
7978
|
+
});
|
|
7979
|
+
},
|
|
7980
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
7981
|
+
});
|
|
7982
|
+
else return original.apply(this, args);
|
|
7983
|
+
};
|
|
7984
|
+
};
|
|
7985
|
+
}
|
|
7986
|
+
extractServerStreamRequestParameters(args, MetadataConstructor) {
|
|
7987
|
+
const method = args[0];
|
|
7988
|
+
const serialize = args[1];
|
|
7989
|
+
const deserialize = args[2];
|
|
7990
|
+
const argument = args[3];
|
|
7991
|
+
let metadata;
|
|
7992
|
+
let options;
|
|
7993
|
+
if (args.length === 6) {
|
|
7994
|
+
metadata = args[4];
|
|
7995
|
+
options = args[5];
|
|
7996
|
+
} else if (args.length === 5) if (args[4] instanceof MetadataConstructor) {
|
|
7997
|
+
metadata = args[4];
|
|
7998
|
+
options = {};
|
|
7999
|
+
} else {
|
|
8000
|
+
metadata = new MetadataConstructor();
|
|
8001
|
+
options = args[4] || {};
|
|
8002
|
+
}
|
|
8003
|
+
else {
|
|
8004
|
+
metadata = new MetadataConstructor();
|
|
8005
|
+
options = {};
|
|
8006
|
+
}
|
|
8007
|
+
return {
|
|
8008
|
+
method,
|
|
8009
|
+
serialize,
|
|
8010
|
+
deserialize,
|
|
8011
|
+
argument,
|
|
8012
|
+
metadata,
|
|
8013
|
+
options
|
|
8014
|
+
};
|
|
8015
|
+
}
|
|
7740
8016
|
_handleRecordUnaryRequest(spanInfo, original, context$4, parsedParams, callback) {
|
|
7741
8017
|
let isResponseReceived = false;
|
|
7742
8018
|
let isStatusEmitted = false;
|
|
@@ -7847,105 +8123,1160 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
|
|
|
7847
8123
|
isGrpcErrorOutput(result) {
|
|
7848
8124
|
return "error" in result;
|
|
7849
8125
|
}
|
|
7850
|
-
|
|
8126
|
+
_handleReplayUnaryRequest(spanInfo, inputValue, callback, MetadataConstructor, stackTrace) {
|
|
7851
8127
|
logger.debug(`[GrpcInstrumentation] Replaying gRPC unary request`);
|
|
7852
|
-
const
|
|
8128
|
+
const emitter = Object.assign(new events.EventEmitter(), {
|
|
8129
|
+
cancel() {},
|
|
8130
|
+
getPeer: () => "0.0.0.0:0000",
|
|
8131
|
+
call: void 0
|
|
8132
|
+
});
|
|
8133
|
+
findMockResponseAsync({
|
|
7853
8134
|
mockRequestData: {
|
|
7854
8135
|
traceId: spanInfo.traceId,
|
|
7855
8136
|
spanId: spanInfo.spanId,
|
|
7856
8137
|
name: "grpc.client.unary",
|
|
7857
8138
|
inputValue,
|
|
7858
8139
|
packageName: GRPC_MODULE_NAME,
|
|
8140
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
|
|
7859
8141
|
instrumentationName: this.INSTRUMENTATION_NAME,
|
|
7860
8142
|
submoduleName: "client",
|
|
7861
8143
|
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
7862
8144
|
stackTrace
|
|
7863
8145
|
},
|
|
7864
8146
|
tuskDrift: this.tuskDrift
|
|
7865
|
-
})
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
8147
|
+
}).then((mockData) => {
|
|
8148
|
+
if (!mockData) {
|
|
8149
|
+
logger.warn(`[GrpcInstrumentation] No mock data found for gRPC request: ${inputValue.service}/${inputValue.method}`, inputValue);
|
|
8150
|
+
callback(/* @__PURE__ */ new Error("No mock data found"));
|
|
8151
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.ERROR });
|
|
8152
|
+
return;
|
|
8153
|
+
}
|
|
8154
|
+
const mockResult = mockData.result;
|
|
8155
|
+
let status;
|
|
8156
|
+
if (this.isGrpcErrorOutput(mockResult)) {
|
|
8157
|
+
const { error, status: errorStatus } = mockResult;
|
|
8158
|
+
status = {
|
|
8159
|
+
code: errorStatus.code,
|
|
8160
|
+
details: errorStatus.details,
|
|
8161
|
+
metadata: deserializeGrpcMetadata(MetadataConstructor, errorStatus.metadata)
|
|
8162
|
+
};
|
|
8163
|
+
const errorObj = Object.assign(new Error(error.message), {
|
|
8164
|
+
name: error.name,
|
|
8165
|
+
stack: error.stack,
|
|
8166
|
+
...status
|
|
8167
|
+
});
|
|
8168
|
+
callback(errorObj);
|
|
8169
|
+
} else {
|
|
8170
|
+
const { body, status: successStatus, bufferMap, jsonableStringMap } = mockResult;
|
|
8171
|
+
const bufferMapToUse = bufferMap || {};
|
|
8172
|
+
const jsonableStringMapToUse = jsonableStringMap || {};
|
|
8173
|
+
status = {
|
|
8174
|
+
code: successStatus.code,
|
|
8175
|
+
details: successStatus.details,
|
|
8176
|
+
metadata: deserializeGrpcMetadata(MetadataConstructor, successStatus.metadata)
|
|
8177
|
+
};
|
|
8178
|
+
const realResponse = deserializeGrpcPayload(body, bufferMapToUse, jsonableStringMapToUse);
|
|
8179
|
+
callback(null, realResponse);
|
|
8180
|
+
}
|
|
8181
|
+
process.nextTick(() => {
|
|
8182
|
+
if (mockResult.metadata) emitter.emit("metadata", deserializeGrpcMetadata(MetadataConstructor, mockResult.metadata));
|
|
8183
|
+
emitter.emit("status", status);
|
|
7872
8184
|
});
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
8185
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: mockResult });
|
|
8186
|
+
SpanUtils.endSpan(spanInfo.span, { code: mockResult.error ? __opentelemetry_api.SpanStatusCode.ERROR : __opentelemetry_api.SpanStatusCode.OK });
|
|
8187
|
+
}).catch((error) => {
|
|
8188
|
+
logger.error(`[GrpcInstrumentation] Error fetching mock data:`, error);
|
|
8189
|
+
callback(error);
|
|
8190
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.ERROR });
|
|
8191
|
+
});
|
|
8192
|
+
return emitter;
|
|
8193
|
+
}
|
|
8194
|
+
_handleRecordServerStreamRequest(spanInfo, original, context$4, parsedParams) {
|
|
8195
|
+
let hasErrorOccurred = false;
|
|
8196
|
+
let isSpanCompleted = false;
|
|
8197
|
+
let streamResponses = [];
|
|
7876
8198
|
let status;
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
})
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
8199
|
+
let responseMetadataInitial = {};
|
|
8200
|
+
let serviceError;
|
|
8201
|
+
/**
|
|
8202
|
+
* Completes the span exactly once
|
|
8203
|
+
*/
|
|
8204
|
+
const completeSpan = (output, statusCode, errorMessage) => {
|
|
8205
|
+
if (isSpanCompleted) return;
|
|
8206
|
+
isSpanCompleted = true;
|
|
8207
|
+
try {
|
|
8208
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: output });
|
|
8209
|
+
SpanUtils.endSpan(spanInfo.span, { code: statusCode });
|
|
8210
|
+
} catch (e) {
|
|
8211
|
+
logger.error(`[GrpcInstrumentation] Error completing span:`, e);
|
|
8212
|
+
}
|
|
8213
|
+
};
|
|
8214
|
+
const inputArgs = [
|
|
8215
|
+
parsedParams.method,
|
|
8216
|
+
parsedParams.serialize,
|
|
8217
|
+
parsedParams.deserialize,
|
|
8218
|
+
parsedParams.argument,
|
|
8219
|
+
parsedParams.metadata,
|
|
8220
|
+
parsedParams.options
|
|
8221
|
+
];
|
|
8222
|
+
const stream$1 = original.apply(context$4, inputArgs);
|
|
8223
|
+
stream$1.on("data", (data) => {
|
|
8224
|
+
try {
|
|
8225
|
+
const { readableBody, bufferMap, jsonableStringMap } = serializeGrpcPayload(data);
|
|
8226
|
+
streamResponses.push({
|
|
8227
|
+
body: readableBody,
|
|
8228
|
+
bufferMap,
|
|
8229
|
+
jsonableStringMap
|
|
8230
|
+
});
|
|
8231
|
+
} catch (e) {
|
|
8232
|
+
logger.error(`[GrpcInstrumentation] Error serializing stream data:`, e);
|
|
8233
|
+
}
|
|
8234
|
+
});
|
|
8235
|
+
stream$1.on("metadata", (initialMetadata) => {
|
|
8236
|
+
responseMetadataInitial = serializeGrpcMetadata(initialMetadata);
|
|
8237
|
+
});
|
|
8238
|
+
stream$1.on("error", (err) => {
|
|
8239
|
+
serviceError = err;
|
|
8240
|
+
hasErrorOccurred = true;
|
|
8241
|
+
});
|
|
8242
|
+
stream$1.on("status", (responseStatus) => {
|
|
7894
8243
|
status = {
|
|
7895
|
-
code:
|
|
7896
|
-
details:
|
|
7897
|
-
metadata:
|
|
8244
|
+
code: responseStatus.code,
|
|
8245
|
+
details: responseStatus.details,
|
|
8246
|
+
metadata: serializeGrpcMetadata(responseStatus.metadata)
|
|
7898
8247
|
};
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
8248
|
+
if (!hasErrorOccurred && streamResponses.length > 0) completeSpan({
|
|
8249
|
+
body: streamResponses,
|
|
8250
|
+
metadata: responseMetadataInitial,
|
|
8251
|
+
status,
|
|
8252
|
+
bufferMap: {},
|
|
8253
|
+
jsonableStringMap: {}
|
|
8254
|
+
}, __opentelemetry_api.SpanStatusCode.OK);
|
|
8255
|
+
else if (!hasErrorOccurred && streamResponses.length === 0) completeSpan({
|
|
8256
|
+
body: [],
|
|
8257
|
+
metadata: responseMetadataInitial,
|
|
8258
|
+
status,
|
|
8259
|
+
bufferMap: {},
|
|
8260
|
+
jsonableStringMap: {}
|
|
8261
|
+
}, __opentelemetry_api.SpanStatusCode.OK);
|
|
8262
|
+
else if (hasErrorOccurred) {
|
|
8263
|
+
const errorOutput = {
|
|
8264
|
+
error: {
|
|
8265
|
+
message: serviceError.message,
|
|
8266
|
+
name: serviceError.name,
|
|
8267
|
+
stack: serviceError.stack
|
|
8268
|
+
},
|
|
8269
|
+
status,
|
|
8270
|
+
metadata: responseMetadataInitial
|
|
8271
|
+
};
|
|
8272
|
+
completeSpan(errorOutput, __opentelemetry_api.SpanStatusCode.ERROR, serviceError.message);
|
|
8273
|
+
}
|
|
8274
|
+
});
|
|
8275
|
+
return stream$1;
|
|
8276
|
+
}
|
|
8277
|
+
_handleReplayServerStreamRequest(spanInfo, inputValue, MetadataConstructor) {
|
|
8278
|
+
logger.debug(`[GrpcInstrumentation] Replaying gRPC server stream request`);
|
|
8279
|
+
const stream$1 = new stream.Readable({
|
|
8280
|
+
objectMode: true,
|
|
8281
|
+
read() {}
|
|
8282
|
+
});
|
|
8283
|
+
Object.assign(stream$1, {
|
|
7903
8284
|
cancel() {},
|
|
7904
8285
|
getPeer: () => "0.0.0.0:0000",
|
|
7905
8286
|
call: void 0
|
|
7906
8287
|
});
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
8288
|
+
findMockResponseAsync({
|
|
8289
|
+
mockRequestData: {
|
|
8290
|
+
traceId: spanInfo.traceId,
|
|
8291
|
+
spanId: spanInfo.spanId,
|
|
8292
|
+
name: "grpc.client.server_stream",
|
|
8293
|
+
inputValue,
|
|
8294
|
+
packageName: GRPC_MODULE_NAME,
|
|
8295
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
|
|
8296
|
+
instrumentationName: this.INSTRUMENTATION_NAME,
|
|
8297
|
+
submoduleName: "client",
|
|
8298
|
+
kind: __opentelemetry_api.SpanKind.CLIENT
|
|
8299
|
+
},
|
|
8300
|
+
tuskDrift: this.tuskDrift
|
|
8301
|
+
}).then((mockData) => {
|
|
8302
|
+
if (!mockData) {
|
|
8303
|
+
logger.warn(`[GrpcInstrumentation] No mock data found for gRPC server stream request: ${inputValue.service}/${inputValue.method}`, inputValue);
|
|
8304
|
+
const error = /* @__PURE__ */ new Error("No mock data found");
|
|
8305
|
+
process.nextTick(() => {
|
|
8306
|
+
stream$1.emit("error", error);
|
|
8307
|
+
stream$1.emit("status", {
|
|
8308
|
+
code: 2,
|
|
8309
|
+
details: "No mock data found",
|
|
8310
|
+
metadata: new MetadataConstructor()
|
|
8311
|
+
});
|
|
8312
|
+
stream$1.push(null);
|
|
8313
|
+
});
|
|
8314
|
+
SpanUtils.endSpan(spanInfo.span, {
|
|
8315
|
+
code: __opentelemetry_api.SpanStatusCode.ERROR,
|
|
8316
|
+
message: "No mock data found"
|
|
8317
|
+
});
|
|
8318
|
+
return;
|
|
8319
|
+
}
|
|
8320
|
+
const mockResult = mockData.result;
|
|
8321
|
+
process.nextTick(() => {
|
|
8322
|
+
if (this.isGrpcErrorOutput(mockResult)) {
|
|
8323
|
+
const { error, status: errorStatus } = mockResult;
|
|
8324
|
+
const status = {
|
|
8325
|
+
code: errorStatus.code,
|
|
8326
|
+
details: errorStatus.details,
|
|
8327
|
+
metadata: deserializeGrpcMetadata(MetadataConstructor, errorStatus.metadata)
|
|
8328
|
+
};
|
|
8329
|
+
if (mockResult.metadata) stream$1.emit("metadata", deserializeGrpcMetadata(MetadataConstructor, mockResult.metadata));
|
|
8330
|
+
const errorObj = Object.assign(new Error(error.message), {
|
|
8331
|
+
name: error.name,
|
|
8332
|
+
stack: error.stack,
|
|
8333
|
+
...status
|
|
8334
|
+
});
|
|
8335
|
+
stream$1.emit("error", errorObj);
|
|
8336
|
+
stream$1.emit("status", status);
|
|
8337
|
+
stream$1.push(null);
|
|
8338
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: mockResult });
|
|
8339
|
+
SpanUtils.endSpan(spanInfo.span, {
|
|
8340
|
+
code: __opentelemetry_api.SpanStatusCode.ERROR,
|
|
8341
|
+
message: error.message
|
|
8342
|
+
});
|
|
8343
|
+
} else {
|
|
8344
|
+
const { body, status: successStatus } = mockResult;
|
|
8345
|
+
const status = {
|
|
8346
|
+
code: successStatus.code,
|
|
8347
|
+
details: successStatus.details,
|
|
8348
|
+
metadata: deserializeGrpcMetadata(MetadataConstructor, successStatus.metadata)
|
|
8349
|
+
};
|
|
8350
|
+
if (mockResult.metadata) stream$1.emit("metadata", deserializeGrpcMetadata(MetadataConstructor, mockResult.metadata));
|
|
8351
|
+
if (Array.isArray(body)) body.forEach((item) => {
|
|
8352
|
+
const bufferMapToUse = item.bufferMap || {};
|
|
8353
|
+
const jsonableStringMapToUse = item.jsonableStringMap || {};
|
|
8354
|
+
const realResponse = deserializeGrpcPayload(item.body, bufferMapToUse, jsonableStringMapToUse);
|
|
8355
|
+
stream$1.push(realResponse);
|
|
8356
|
+
});
|
|
8357
|
+
stream$1.push(null);
|
|
8358
|
+
stream$1.emit("status", status);
|
|
8359
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: mockResult });
|
|
8360
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
|
|
8361
|
+
}
|
|
8362
|
+
});
|
|
8363
|
+
}).catch((error) => {
|
|
8364
|
+
logger.error(`[GrpcInstrumentation] Error fetching mock data for server stream:`, error);
|
|
8365
|
+
process.nextTick(() => {
|
|
8366
|
+
stream$1.emit("error", error);
|
|
8367
|
+
stream$1.emit("status", {
|
|
8368
|
+
code: 2,
|
|
8369
|
+
details: error.message,
|
|
8370
|
+
metadata: new MetadataConstructor()
|
|
8371
|
+
});
|
|
8372
|
+
stream$1.push(null);
|
|
8373
|
+
});
|
|
8374
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.ERROR });
|
|
8375
|
+
});
|
|
8376
|
+
return stream$1;
|
|
8377
|
+
}
|
|
8378
|
+
_getWaitForReadyPatchFn() {
|
|
8379
|
+
const self = this;
|
|
8380
|
+
return (original) => {
|
|
8381
|
+
return function waitForReady(deadline, callback) {
|
|
8382
|
+
if (self.mode === TuskDriftMode.REPLAY) {
|
|
8383
|
+
process.nextTick(() => callback());
|
|
7921
8384
|
return;
|
|
7922
8385
|
} else return original.apply(this, [deadline, callback]);
|
|
7923
8386
|
};
|
|
7924
8387
|
};
|
|
7925
8388
|
}
|
|
7926
|
-
_getClosePatchFn() {
|
|
8389
|
+
_getClosePatchFn() {
|
|
8390
|
+
const self = this;
|
|
8391
|
+
return (original) => {
|
|
8392
|
+
return function close() {
|
|
8393
|
+
if (self.mode === TuskDriftMode.REPLAY) return;
|
|
8394
|
+
else return original.apply(this, arguments);
|
|
8395
|
+
};
|
|
8396
|
+
};
|
|
8397
|
+
}
|
|
8398
|
+
_getGetChannelPatchFn() {
|
|
8399
|
+
const self = this;
|
|
8400
|
+
return (original) => {
|
|
8401
|
+
return function getChannel() {
|
|
8402
|
+
if (self.mode === TuskDriftMode.REPLAY) return {};
|
|
8403
|
+
else return original.apply(this, arguments);
|
|
8404
|
+
};
|
|
8405
|
+
};
|
|
8406
|
+
}
|
|
8407
|
+
_wrap(target, propertyName, wrapper) {
|
|
8408
|
+
wrap(target, propertyName, wrapper);
|
|
8409
|
+
}
|
|
8410
|
+
};
|
|
8411
|
+
GrpcInstrumentation.metadataStore = /* @__PURE__ */ new Map();
|
|
8412
|
+
|
|
8413
|
+
//#endregion
|
|
8414
|
+
//#region src/instrumentation/libraries/firestore/mocks/TdFirestoreDocumentMock.ts
|
|
8415
|
+
/**
|
|
8416
|
+
* Mock Firestore DocumentSnapshot for replay mode
|
|
8417
|
+
* Mimics the Firestore DocumentSnapshot API
|
|
8418
|
+
*/
|
|
8419
|
+
var TdFirestoreDocumentMock = class {
|
|
8420
|
+
constructor(documentData) {
|
|
8421
|
+
this.documentData = documentData;
|
|
8422
|
+
}
|
|
8423
|
+
/**
|
|
8424
|
+
* The document's identifier within its collection
|
|
8425
|
+
*/
|
|
8426
|
+
get id() {
|
|
8427
|
+
return this.documentData.id;
|
|
8428
|
+
}
|
|
8429
|
+
/**
|
|
8430
|
+
* Whether the document exists
|
|
8431
|
+
*/
|
|
8432
|
+
get exists() {
|
|
8433
|
+
return this.documentData.exists;
|
|
8434
|
+
}
|
|
8435
|
+
/**
|
|
8436
|
+
* A DocumentReference to the document location
|
|
8437
|
+
*/
|
|
8438
|
+
get ref() {
|
|
8439
|
+
return {
|
|
8440
|
+
id: this.documentData.id,
|
|
8441
|
+
path: this.documentData.path
|
|
8442
|
+
};
|
|
8443
|
+
}
|
|
8444
|
+
/**
|
|
8445
|
+
* The time the document was created (if available)
|
|
8446
|
+
*/
|
|
8447
|
+
get createTime() {
|
|
8448
|
+
return this.documentData.createTime ? {
|
|
8449
|
+
seconds: this.documentData.createTime.seconds,
|
|
8450
|
+
nanoseconds: this.documentData.createTime.nanoseconds,
|
|
8451
|
+
toDate: () => /* @__PURE__ */ new Date(this.documentData.createTime.seconds * 1e3 + this.documentData.createTime.nanoseconds / 1e6)
|
|
8452
|
+
} : null;
|
|
8453
|
+
}
|
|
8454
|
+
/**
|
|
8455
|
+
* The time the document was last updated (if available)
|
|
8456
|
+
*/
|
|
8457
|
+
get updateTime() {
|
|
8458
|
+
return this.documentData.updateTime ? {
|
|
8459
|
+
seconds: this.documentData.updateTime.seconds,
|
|
8460
|
+
nanoseconds: this.documentData.updateTime.nanoseconds,
|
|
8461
|
+
toDate: () => /* @__PURE__ */ new Date(this.documentData.updateTime.seconds * 1e3 + this.documentData.updateTime.nanoseconds / 1e6)
|
|
8462
|
+
} : null;
|
|
8463
|
+
}
|
|
8464
|
+
/**
|
|
8465
|
+
* The time the document was read (if available)
|
|
8466
|
+
*/
|
|
8467
|
+
get readTime() {
|
|
8468
|
+
return this.documentData.readTime ? {
|
|
8469
|
+
seconds: this.documentData.readTime.seconds,
|
|
8470
|
+
nanoseconds: this.documentData.readTime.nanoseconds,
|
|
8471
|
+
toDate: () => /* @__PURE__ */ new Date(this.documentData.readTime.seconds * 1e3 + this.documentData.readTime.nanoseconds / 1e6)
|
|
8472
|
+
} : null;
|
|
8473
|
+
}
|
|
8474
|
+
/**
|
|
8475
|
+
* Retrieves all fields in the document as an object
|
|
8476
|
+
*/
|
|
8477
|
+
data() {
|
|
8478
|
+
return this.documentData.data;
|
|
8479
|
+
}
|
|
8480
|
+
/**
|
|
8481
|
+
* Retrieves the field specified by fieldPath
|
|
8482
|
+
*/
|
|
8483
|
+
get(fieldPath) {
|
|
8484
|
+
if (!this.documentData.data) return;
|
|
8485
|
+
return this.documentData.data[fieldPath];
|
|
8486
|
+
}
|
|
8487
|
+
/**
|
|
8488
|
+
* Returns true if the document's data and path are equal to the provided value
|
|
8489
|
+
*/
|
|
8490
|
+
isEqual(other) {
|
|
8491
|
+
return this.documentData.path === other.documentData.path;
|
|
8492
|
+
}
|
|
8493
|
+
};
|
|
8494
|
+
|
|
8495
|
+
//#endregion
|
|
8496
|
+
//#region src/instrumentation/libraries/firestore/mocks/TdFirestoreQueryMock.ts
|
|
8497
|
+
/**
|
|
8498
|
+
* Mock Firestore QuerySnapshot for replay mode
|
|
8499
|
+
* Mimics the Firestore QuerySnapshot API
|
|
8500
|
+
*/
|
|
8501
|
+
var TdFirestoreQueryMock = class {
|
|
8502
|
+
constructor(queryResult) {
|
|
8503
|
+
this.queryResult = queryResult;
|
|
8504
|
+
this._docs = queryResult.docs.map((doc) => new TdFirestoreDocumentMock(doc));
|
|
8505
|
+
}
|
|
8506
|
+
/**
|
|
8507
|
+
* An array of all the documents in the QuerySnapshot
|
|
8508
|
+
*/
|
|
8509
|
+
get docs() {
|
|
8510
|
+
return this._docs;
|
|
8511
|
+
}
|
|
8512
|
+
/**
|
|
8513
|
+
* The number of documents in the QuerySnapshot
|
|
8514
|
+
*/
|
|
8515
|
+
get size() {
|
|
8516
|
+
return this.queryResult.size;
|
|
8517
|
+
}
|
|
8518
|
+
/**
|
|
8519
|
+
* True if there are no documents in the QuerySnapshot
|
|
8520
|
+
*/
|
|
8521
|
+
get empty() {
|
|
8522
|
+
return this.queryResult.empty;
|
|
8523
|
+
}
|
|
8524
|
+
/**
|
|
8525
|
+
* The time the query snapshot was read
|
|
8526
|
+
*/
|
|
8527
|
+
get readTime() {
|
|
8528
|
+
return this.queryResult.readTime ? {
|
|
8529
|
+
seconds: this.queryResult.readTime.seconds,
|
|
8530
|
+
nanoseconds: this.queryResult.readTime.nanoseconds,
|
|
8531
|
+
toDate: () => /* @__PURE__ */ new Date(this.queryResult.readTime.seconds * 1e3 + this.queryResult.readTime.nanoseconds / 1e6)
|
|
8532
|
+
} : null;
|
|
8533
|
+
}
|
|
8534
|
+
/**
|
|
8535
|
+
* The query on which you called get or onSnapshot
|
|
8536
|
+
*/
|
|
8537
|
+
get query() {
|
|
8538
|
+
return {};
|
|
8539
|
+
}
|
|
8540
|
+
/**
|
|
8541
|
+
* Enumerates all of the documents in the QuerySnapshot
|
|
8542
|
+
*/
|
|
8543
|
+
forEach(callback, thisArg) {
|
|
8544
|
+
this._docs.forEach(callback, thisArg);
|
|
8545
|
+
}
|
|
8546
|
+
/**
|
|
8547
|
+
* Returns an array of the documents changes since the last snapshot
|
|
8548
|
+
*/
|
|
8549
|
+
docChanges() {
|
|
8550
|
+
return [];
|
|
8551
|
+
}
|
|
8552
|
+
/**
|
|
8553
|
+
* Returns true if the document data and path are equal to this QuerySnapshot
|
|
8554
|
+
*/
|
|
8555
|
+
isEqual(other) {
|
|
8556
|
+
if (this.size !== other.size) return false;
|
|
8557
|
+
return this.size === other.size && this.empty === other.empty;
|
|
8558
|
+
}
|
|
8559
|
+
};
|
|
8560
|
+
|
|
8561
|
+
//#endregion
|
|
8562
|
+
//#region src/instrumentation/libraries/firestore/mocks/TdFirestoreWriteResultMock.ts
|
|
8563
|
+
/**
|
|
8564
|
+
* Mock Firestore WriteResult for replay mode
|
|
8565
|
+
* Mimics the Firestore WriteResult API
|
|
8566
|
+
*/
|
|
8567
|
+
var TdFirestoreWriteResultMock = class {
|
|
8568
|
+
constructor(result) {
|
|
8569
|
+
this.result = result;
|
|
8570
|
+
}
|
|
8571
|
+
/**
|
|
8572
|
+
* The write time as reported by the server
|
|
8573
|
+
*/
|
|
8574
|
+
get writeTime() {
|
|
8575
|
+
return this.result.writeTime ? {
|
|
8576
|
+
seconds: this.result.writeTime.seconds,
|
|
8577
|
+
nanoseconds: this.result.writeTime.nanoseconds,
|
|
8578
|
+
toDate: () => /* @__PURE__ */ new Date(this.result.writeTime.seconds * 1e3 + this.result.writeTime.nanoseconds / 1e6)
|
|
8579
|
+
} : null;
|
|
8580
|
+
}
|
|
8581
|
+
/**
|
|
8582
|
+
* Returns true if this WriteResult is equal to the provided one
|
|
8583
|
+
*/
|
|
8584
|
+
isEqual(other) {
|
|
8585
|
+
if (!this.writeTime || !other.writeTime) return this.writeTime === other.writeTime;
|
|
8586
|
+
return this.writeTime.seconds === other.writeTime.seconds && this.writeTime.nanoseconds === other.writeTime.nanoseconds;
|
|
8587
|
+
}
|
|
8588
|
+
};
|
|
8589
|
+
|
|
8590
|
+
//#endregion
|
|
8591
|
+
//#region src/instrumentation/libraries/firestore/Instrumentation.ts
|
|
8592
|
+
const FIRESTORE_VERSION = "7.*";
|
|
8593
|
+
const PACKAGE_NAME = "@google-cloud/firestore";
|
|
8594
|
+
var FirestoreInstrumentation = class extends TdInstrumentationBase {
|
|
8595
|
+
constructor(config = {}) {
|
|
8596
|
+
super(PACKAGE_NAME, config);
|
|
8597
|
+
this.INSTRUMENTATION_NAME = "FirestoreInstrumentation";
|
|
8598
|
+
this.originalCollectionDocFn = null;
|
|
8599
|
+
this.mode = config.mode || TuskDriftMode.DISABLED;
|
|
8600
|
+
this.tuskDrift = TuskDriftCore.getInstance();
|
|
8601
|
+
}
|
|
8602
|
+
init() {
|
|
8603
|
+
return [new TdInstrumentationNodeModule({
|
|
8604
|
+
name: PACKAGE_NAME,
|
|
8605
|
+
supportedVersions: [FIRESTORE_VERSION],
|
|
8606
|
+
files: [
|
|
8607
|
+
new TdInstrumentationNodeModuleFile({
|
|
8608
|
+
name: "@google-cloud/firestore/build/src/reference/document-reference.js",
|
|
8609
|
+
supportedVersions: [FIRESTORE_VERSION],
|
|
8610
|
+
patch: (moduleExports) => this._patchDocumentReference(moduleExports)
|
|
8611
|
+
}),
|
|
8612
|
+
new TdInstrumentationNodeModuleFile({
|
|
8613
|
+
name: "@google-cloud/firestore/build/src/reference/collection-reference.js",
|
|
8614
|
+
supportedVersions: [FIRESTORE_VERSION],
|
|
8615
|
+
patch: (moduleExports) => this._patchCollectionReference(moduleExports)
|
|
8616
|
+
}),
|
|
8617
|
+
new TdInstrumentationNodeModuleFile({
|
|
8618
|
+
name: "@google-cloud/firestore/build/src/reference/query.js",
|
|
8619
|
+
supportedVersions: [FIRESTORE_VERSION],
|
|
8620
|
+
patch: (moduleExports) => this._patchQuery(moduleExports)
|
|
8621
|
+
})
|
|
8622
|
+
]
|
|
8623
|
+
})];
|
|
8624
|
+
}
|
|
8625
|
+
_patchDocumentReference(moduleExports) {
|
|
8626
|
+
logger.debug(`[FirestoreInstrumentation] Patching DocumentReference in ${this.mode} mode`);
|
|
8627
|
+
if (this.isModulePatched(moduleExports)) {
|
|
8628
|
+
logger.debug(`[FirestoreInstrumentation] DocumentReference already patched, skipping`);
|
|
8629
|
+
return moduleExports;
|
|
8630
|
+
}
|
|
8631
|
+
const DocumentReference = moduleExports.DocumentReference;
|
|
8632
|
+
if (!DocumentReference || !DocumentReference.prototype) {
|
|
8633
|
+
logger.warn(`[FirestoreInstrumentation] DocumentReference.prototype not found`);
|
|
8634
|
+
return moduleExports;
|
|
8635
|
+
}
|
|
8636
|
+
this._wrap(DocumentReference.prototype, "get", this._getDocumentGetPatchFn());
|
|
8637
|
+
this._wrap(DocumentReference.prototype, "create", this._getDocumentCreatePatchFn());
|
|
8638
|
+
this._wrap(DocumentReference.prototype, "set", this._getDocumentSetPatchFn());
|
|
8639
|
+
this._wrap(DocumentReference.prototype, "update", this._getDocumentUpdatePatchFn());
|
|
8640
|
+
this._wrap(DocumentReference.prototype, "delete", this._getDocumentDeletePatchFn());
|
|
8641
|
+
this.markModuleAsPatched(moduleExports);
|
|
8642
|
+
logger.debug(`[FirestoreInstrumentation] DocumentReference patching complete`);
|
|
8643
|
+
return moduleExports;
|
|
8644
|
+
}
|
|
8645
|
+
_patchCollectionReference(moduleExports) {
|
|
8646
|
+
logger.debug(`[FirestoreInstrumentation] Patching CollectionReference in ${this.mode} mode`);
|
|
8647
|
+
if (this.isModulePatched(moduleExports)) {
|
|
8648
|
+
logger.debug(`[FirestoreInstrumentation] CollectionReference already patched, skipping`);
|
|
8649
|
+
return moduleExports;
|
|
8650
|
+
}
|
|
8651
|
+
const CollectionReference = moduleExports.CollectionReference;
|
|
8652
|
+
if (!CollectionReference || !CollectionReference.prototype) {
|
|
8653
|
+
logger.warn(`[FirestoreInstrumentation] CollectionReference.prototype not found`);
|
|
8654
|
+
return moduleExports;
|
|
8655
|
+
}
|
|
8656
|
+
this.originalCollectionDocFn = CollectionReference.prototype.doc;
|
|
8657
|
+
this._wrap(CollectionReference.prototype, "add", this._getCollectionAddPatchFn());
|
|
8658
|
+
this._wrap(CollectionReference.prototype, "doc", this._getCollectionDocPatchFn());
|
|
8659
|
+
this.markModuleAsPatched(moduleExports);
|
|
8660
|
+
logger.debug(`[FirestoreInstrumentation] CollectionReference patching complete`);
|
|
8661
|
+
return moduleExports;
|
|
8662
|
+
}
|
|
8663
|
+
_patchQuery(moduleExports) {
|
|
8664
|
+
logger.debug(`[FirestoreInstrumentation] Patching Query in ${this.mode} mode`);
|
|
8665
|
+
if (this.isModulePatched(moduleExports)) {
|
|
8666
|
+
logger.debug(`[FirestoreInstrumentation] Query already patched, skipping`);
|
|
8667
|
+
return moduleExports;
|
|
8668
|
+
}
|
|
8669
|
+
const Query = moduleExports.Query;
|
|
8670
|
+
if (!Query || !Query.prototype) {
|
|
8671
|
+
logger.warn(`[FirestoreInstrumentation] Query.prototype not found`);
|
|
8672
|
+
return moduleExports;
|
|
8673
|
+
}
|
|
8674
|
+
this._wrap(Query.prototype, "get", this._getQueryGetPatchFn());
|
|
8675
|
+
this.markModuleAsPatched(moduleExports);
|
|
8676
|
+
logger.debug(`[FirestoreInstrumentation] Query patching complete`);
|
|
8677
|
+
return moduleExports;
|
|
8678
|
+
}
|
|
8679
|
+
_getDocumentGetPatchFn() {
|
|
8680
|
+
const self = this;
|
|
8681
|
+
return (originalGet) => {
|
|
8682
|
+
return function() {
|
|
8683
|
+
const inputValue = {
|
|
8684
|
+
operation: "document.get",
|
|
8685
|
+
path: this.path
|
|
8686
|
+
};
|
|
8687
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
8688
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
|
|
8689
|
+
name: "firestore.document.get",
|
|
8690
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8691
|
+
submodule: "document",
|
|
8692
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8693
|
+
packageName: PACKAGE_NAME,
|
|
8694
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8695
|
+
inputValue,
|
|
8696
|
+
isPreAppStart: false,
|
|
8697
|
+
stopRecordingChildSpans: true
|
|
8698
|
+
}, (spanInfo) => {
|
|
8699
|
+
return self._handleReplayDocumentGet(spanInfo, inputValue);
|
|
8700
|
+
});
|
|
8701
|
+
} });
|
|
8702
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
8703
|
+
originalFunctionCall: () => originalGet.call(this),
|
|
8704
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
8705
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
|
|
8706
|
+
name: "firestore.document.get",
|
|
8707
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8708
|
+
submodule: "document",
|
|
8709
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8710
|
+
packageName: PACKAGE_NAME,
|
|
8711
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8712
|
+
inputValue,
|
|
8713
|
+
isPreAppStart,
|
|
8714
|
+
stopRecordingChildSpans: true
|
|
8715
|
+
}, (spanInfo) => {
|
|
8716
|
+
return self._handleRecordDocumentGet(spanInfo, originalGet, this);
|
|
8717
|
+
});
|
|
8718
|
+
},
|
|
8719
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
8720
|
+
});
|
|
8721
|
+
else return originalGet.call(this);
|
|
8722
|
+
};
|
|
8723
|
+
};
|
|
8724
|
+
}
|
|
8725
|
+
async _handleRecordDocumentGet(spanInfo, originalGet, context$4) {
|
|
8726
|
+
const snapshot = await originalGet.call(context$4);
|
|
8727
|
+
const documentResult = {
|
|
8728
|
+
id: snapshot.id,
|
|
8729
|
+
path: snapshot.ref.path,
|
|
8730
|
+
exists: snapshot.exists,
|
|
8731
|
+
data: snapshot.exists ? snapshot.data() : void 0,
|
|
8732
|
+
createTime: snapshot.createTime ? {
|
|
8733
|
+
seconds: snapshot.createTime.seconds,
|
|
8734
|
+
nanoseconds: snapshot.createTime.nanoseconds
|
|
8735
|
+
} : void 0,
|
|
8736
|
+
updateTime: snapshot.updateTime ? {
|
|
8737
|
+
seconds: snapshot.updateTime.seconds,
|
|
8738
|
+
nanoseconds: snapshot.updateTime.nanoseconds
|
|
8739
|
+
} : void 0,
|
|
8740
|
+
readTime: snapshot.readTime ? {
|
|
8741
|
+
seconds: snapshot.readTime.seconds,
|
|
8742
|
+
nanoseconds: snapshot.readTime.nanoseconds
|
|
8743
|
+
} : void 0
|
|
8744
|
+
};
|
|
8745
|
+
try {
|
|
8746
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: documentResult });
|
|
8747
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
|
|
8748
|
+
} catch {
|
|
8749
|
+
logger.error(`[FirestoreInstrumentation] Error updating span attributes for document.get`);
|
|
8750
|
+
}
|
|
8751
|
+
return snapshot;
|
|
8752
|
+
}
|
|
8753
|
+
async _handleReplayDocumentGet(spanInfo, inputValue) {
|
|
8754
|
+
logger.debug(`[FirestoreInstrumentation] Replaying document.get`);
|
|
8755
|
+
const mockData = await findMockResponseAsync({
|
|
8756
|
+
mockRequestData: {
|
|
8757
|
+
traceId: spanInfo.traceId,
|
|
8758
|
+
spanId: spanInfo.spanId,
|
|
8759
|
+
name: "firestore.document.get",
|
|
8760
|
+
inputValue: createMockInputValue(inputValue),
|
|
8761
|
+
packageName: PACKAGE_NAME,
|
|
8762
|
+
instrumentationName: this.INSTRUMENTATION_NAME,
|
|
8763
|
+
submoduleName: "document",
|
|
8764
|
+
kind: __opentelemetry_api.SpanKind.CLIENT
|
|
8765
|
+
},
|
|
8766
|
+
tuskDrift: this.tuskDrift
|
|
8767
|
+
});
|
|
8768
|
+
if (!mockData) {
|
|
8769
|
+
logger.warn(`[FirestoreInstrumentation] No mock data found for document.get: ${inputValue.path}`);
|
|
8770
|
+
return Promise.reject(/* @__PURE__ */ new Error("No mock data found"));
|
|
8771
|
+
}
|
|
8772
|
+
const documentResult = mockData.result;
|
|
8773
|
+
return new TdFirestoreDocumentMock(documentResult);
|
|
8774
|
+
}
|
|
8775
|
+
_getDocumentCreatePatchFn() {
|
|
8776
|
+
const self = this;
|
|
8777
|
+
return (originalCreate) => {
|
|
8778
|
+
return function(data) {
|
|
8779
|
+
const inputValue = {
|
|
8780
|
+
operation: "document.create",
|
|
8781
|
+
path: this.path,
|
|
8782
|
+
data
|
|
8783
|
+
};
|
|
8784
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
8785
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalCreate.call(this, data), {
|
|
8786
|
+
name: "firestore.document.create",
|
|
8787
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8788
|
+
submodule: "document",
|
|
8789
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8790
|
+
packageName: PACKAGE_NAME,
|
|
8791
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8792
|
+
inputValue,
|
|
8793
|
+
isPreAppStart: false,
|
|
8794
|
+
stopRecordingChildSpans: true
|
|
8795
|
+
}, (spanInfo) => {
|
|
8796
|
+
return self._handleReplayDocumentWrite(spanInfo, inputValue);
|
|
8797
|
+
});
|
|
8798
|
+
} });
|
|
8799
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
8800
|
+
originalFunctionCall: () => originalCreate.call(this, data),
|
|
8801
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
8802
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalCreate.call(this, data), {
|
|
8803
|
+
name: "firestore.document.create",
|
|
8804
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8805
|
+
submodule: "document",
|
|
8806
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8807
|
+
packageName: PACKAGE_NAME,
|
|
8808
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8809
|
+
inputValue,
|
|
8810
|
+
isPreAppStart,
|
|
8811
|
+
stopRecordingChildSpans: true
|
|
8812
|
+
}, (spanInfo) => {
|
|
8813
|
+
return self._handleRecordDocumentWrite(spanInfo, originalCreate, this, data);
|
|
8814
|
+
});
|
|
8815
|
+
},
|
|
8816
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
8817
|
+
});
|
|
8818
|
+
else return originalCreate.call(this, data);
|
|
8819
|
+
};
|
|
8820
|
+
};
|
|
8821
|
+
}
|
|
8822
|
+
_getDocumentSetPatchFn() {
|
|
8823
|
+
const self = this;
|
|
8824
|
+
return (originalSet) => {
|
|
8825
|
+
return function(data, options) {
|
|
8826
|
+
const inputValue = {
|
|
8827
|
+
operation: "document.set",
|
|
8828
|
+
path: this.path,
|
|
8829
|
+
data,
|
|
8830
|
+
options
|
|
8831
|
+
};
|
|
8832
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
8833
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalSet.call(this, data, options), {
|
|
8834
|
+
name: "firestore.document.set",
|
|
8835
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8836
|
+
submodule: "document",
|
|
8837
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8838
|
+
packageName: PACKAGE_NAME,
|
|
8839
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8840
|
+
inputValue,
|
|
8841
|
+
isPreAppStart: false,
|
|
8842
|
+
stopRecordingChildSpans: true
|
|
8843
|
+
}, (spanInfo) => {
|
|
8844
|
+
return self._handleReplayDocumentWrite(spanInfo, inputValue);
|
|
8845
|
+
});
|
|
8846
|
+
} });
|
|
8847
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
8848
|
+
originalFunctionCall: () => originalSet.call(this, data, options),
|
|
8849
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
8850
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalSet.call(this, data, options), {
|
|
8851
|
+
name: "firestore.document.set",
|
|
8852
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8853
|
+
submodule: "document",
|
|
8854
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8855
|
+
packageName: PACKAGE_NAME,
|
|
8856
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8857
|
+
inputValue,
|
|
8858
|
+
isPreAppStart,
|
|
8859
|
+
stopRecordingChildSpans: true
|
|
8860
|
+
}, (spanInfo) => {
|
|
8861
|
+
return self._handleRecordDocumentWrite(spanInfo, originalSet, this, data, options);
|
|
8862
|
+
});
|
|
8863
|
+
},
|
|
8864
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
8865
|
+
});
|
|
8866
|
+
else return originalSet.call(this, data, options);
|
|
8867
|
+
};
|
|
8868
|
+
};
|
|
8869
|
+
}
|
|
8870
|
+
_getDocumentUpdatePatchFn() {
|
|
8871
|
+
const self = this;
|
|
8872
|
+
return (originalUpdate) => {
|
|
8873
|
+
return function(...args) {
|
|
8874
|
+
const inputValue = {
|
|
8875
|
+
operation: "document.update",
|
|
8876
|
+
path: this.path,
|
|
8877
|
+
data: args.length === 1 ? args[0] : args
|
|
8878
|
+
};
|
|
8879
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
8880
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalUpdate.apply(this, args), {
|
|
8881
|
+
name: "firestore.document.update",
|
|
8882
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8883
|
+
submodule: "document",
|
|
8884
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8885
|
+
packageName: PACKAGE_NAME,
|
|
8886
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8887
|
+
inputValue,
|
|
8888
|
+
isPreAppStart: false,
|
|
8889
|
+
stopRecordingChildSpans: true
|
|
8890
|
+
}, (spanInfo) => {
|
|
8891
|
+
return self._handleReplayDocumentWrite(spanInfo, inputValue);
|
|
8892
|
+
});
|
|
8893
|
+
} });
|
|
8894
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
8895
|
+
originalFunctionCall: () => originalUpdate.apply(this, args),
|
|
8896
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
8897
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalUpdate.apply(this, args), {
|
|
8898
|
+
name: "firestore.document.update",
|
|
8899
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8900
|
+
submodule: "document",
|
|
8901
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8902
|
+
packageName: PACKAGE_NAME,
|
|
8903
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8904
|
+
inputValue,
|
|
8905
|
+
isPreAppStart,
|
|
8906
|
+
stopRecordingChildSpans: true
|
|
8907
|
+
}, (spanInfo) => {
|
|
8908
|
+
return self._handleRecordDocumentWrite(spanInfo, originalUpdate, this, ...args);
|
|
8909
|
+
});
|
|
8910
|
+
},
|
|
8911
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
8912
|
+
});
|
|
8913
|
+
else return originalUpdate.apply(this, args);
|
|
8914
|
+
};
|
|
8915
|
+
};
|
|
8916
|
+
}
|
|
8917
|
+
_getDocumentDeletePatchFn() {
|
|
7927
8918
|
const self = this;
|
|
7928
|
-
return (
|
|
7929
|
-
return function
|
|
7930
|
-
|
|
7931
|
-
|
|
8919
|
+
return (originalDelete) => {
|
|
8920
|
+
return function(precondition) {
|
|
8921
|
+
const inputValue = {
|
|
8922
|
+
operation: "document.delete",
|
|
8923
|
+
path: this.path,
|
|
8924
|
+
options: precondition
|
|
8925
|
+
};
|
|
8926
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
8927
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalDelete.call(this, precondition), {
|
|
8928
|
+
name: "firestore.document.delete",
|
|
8929
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8930
|
+
submodule: "document",
|
|
8931
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8932
|
+
packageName: PACKAGE_NAME,
|
|
8933
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8934
|
+
inputValue,
|
|
8935
|
+
isPreAppStart: false,
|
|
8936
|
+
stopRecordingChildSpans: true
|
|
8937
|
+
}, (spanInfo) => {
|
|
8938
|
+
return self._handleReplayDocumentWrite(spanInfo, inputValue);
|
|
8939
|
+
});
|
|
8940
|
+
} });
|
|
8941
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
8942
|
+
originalFunctionCall: () => originalDelete.call(this, precondition),
|
|
8943
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
8944
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalDelete.call(this, precondition), {
|
|
8945
|
+
name: "firestore.document.delete",
|
|
8946
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
8947
|
+
submodule: "document",
|
|
8948
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
8949
|
+
packageName: PACKAGE_NAME,
|
|
8950
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8951
|
+
inputValue,
|
|
8952
|
+
isPreAppStart,
|
|
8953
|
+
stopRecordingChildSpans: true
|
|
8954
|
+
}, (spanInfo) => {
|
|
8955
|
+
return self._handleRecordDocumentWrite(spanInfo, originalDelete, this, precondition);
|
|
8956
|
+
});
|
|
8957
|
+
},
|
|
8958
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
8959
|
+
});
|
|
8960
|
+
else return originalDelete.call(this, precondition);
|
|
7932
8961
|
};
|
|
7933
8962
|
};
|
|
7934
8963
|
}
|
|
7935
|
-
|
|
8964
|
+
async _handleRecordDocumentWrite(spanInfo, originalWrite, context$4, ...args) {
|
|
8965
|
+
const writeResult = await originalWrite.apply(context$4, args);
|
|
8966
|
+
const result = { writeTime: writeResult.writeTime ? {
|
|
8967
|
+
seconds: writeResult.writeTime.seconds,
|
|
8968
|
+
nanoseconds: writeResult.writeTime.nanoseconds
|
|
8969
|
+
} : void 0 };
|
|
8970
|
+
try {
|
|
8971
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: result });
|
|
8972
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
|
|
8973
|
+
} catch {
|
|
8974
|
+
logger.error(`[FirestoreInstrumentation] Error updating span attributes for document.write`);
|
|
8975
|
+
}
|
|
8976
|
+
return writeResult;
|
|
8977
|
+
}
|
|
8978
|
+
async _handleReplayDocumentWrite(spanInfo, inputValue) {
|
|
8979
|
+
logger.debug(`[FirestoreInstrumentation] Replaying document write: ${inputValue.operation}`);
|
|
8980
|
+
const mockData = await findMockResponseAsync({
|
|
8981
|
+
mockRequestData: {
|
|
8982
|
+
traceId: spanInfo.traceId,
|
|
8983
|
+
spanId: spanInfo.spanId,
|
|
8984
|
+
name: `firestore.${inputValue.operation}`,
|
|
8985
|
+
inputValue: createMockInputValue(inputValue),
|
|
8986
|
+
packageName: PACKAGE_NAME,
|
|
8987
|
+
instrumentationName: this.INSTRUMENTATION_NAME,
|
|
8988
|
+
submoduleName: "document",
|
|
8989
|
+
kind: __opentelemetry_api.SpanKind.CLIENT
|
|
8990
|
+
},
|
|
8991
|
+
tuskDrift: this.tuskDrift
|
|
8992
|
+
});
|
|
8993
|
+
if (!mockData) {
|
|
8994
|
+
logger.warn(`[FirestoreInstrumentation] No mock data found for ${inputValue.operation}: ${inputValue.path}`);
|
|
8995
|
+
return Promise.reject(/* @__PURE__ */ new Error("No mock data found"));
|
|
8996
|
+
}
|
|
8997
|
+
const writeResult = mockData.result;
|
|
8998
|
+
return new TdFirestoreWriteResultMock(writeResult);
|
|
8999
|
+
}
|
|
9000
|
+
_getCollectionAddPatchFn() {
|
|
7936
9001
|
const self = this;
|
|
7937
|
-
return (
|
|
7938
|
-
return function
|
|
7939
|
-
|
|
7940
|
-
|
|
9002
|
+
return (originalAdd) => {
|
|
9003
|
+
return function(data) {
|
|
9004
|
+
const inputValue = {
|
|
9005
|
+
operation: "collection.add",
|
|
9006
|
+
path: this.path,
|
|
9007
|
+
data
|
|
9008
|
+
};
|
|
9009
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
9010
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalAdd.call(this, data), {
|
|
9011
|
+
name: "firestore.collection.add",
|
|
9012
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
9013
|
+
submodule: "collection",
|
|
9014
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
9015
|
+
packageName: PACKAGE_NAME,
|
|
9016
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
9017
|
+
inputValue,
|
|
9018
|
+
isPreAppStart: false,
|
|
9019
|
+
stopRecordingChildSpans: true
|
|
9020
|
+
}, (spanInfo) => {
|
|
9021
|
+
return self._handleReplayCollectionAdd(spanInfo, inputValue, this);
|
|
9022
|
+
});
|
|
9023
|
+
} });
|
|
9024
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
9025
|
+
originalFunctionCall: () => originalAdd.call(this, data),
|
|
9026
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
9027
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalAdd.call(this, data), {
|
|
9028
|
+
name: "firestore.collection.add",
|
|
9029
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
9030
|
+
submodule: "collection",
|
|
9031
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
9032
|
+
packageName: PACKAGE_NAME,
|
|
9033
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
9034
|
+
inputValue,
|
|
9035
|
+
isPreAppStart,
|
|
9036
|
+
stopRecordingChildSpans: true
|
|
9037
|
+
}, (spanInfo) => {
|
|
9038
|
+
return self._handleRecordCollectionAdd(spanInfo, originalAdd, this, data);
|
|
9039
|
+
});
|
|
9040
|
+
},
|
|
9041
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
9042
|
+
});
|
|
9043
|
+
else return originalAdd.call(this, data);
|
|
9044
|
+
};
|
|
9045
|
+
};
|
|
9046
|
+
}
|
|
9047
|
+
async _handleRecordCollectionAdd(spanInfo, originalAdd, context$4, data) {
|
|
9048
|
+
const docRef = await originalAdd.call(context$4, data);
|
|
9049
|
+
const result = {
|
|
9050
|
+
id: docRef.id,
|
|
9051
|
+
path: docRef.path
|
|
9052
|
+
};
|
|
9053
|
+
try {
|
|
9054
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: result });
|
|
9055
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
|
|
9056
|
+
} catch {
|
|
9057
|
+
logger.error(`[FirestoreInstrumentation] Error updating span attributes for collection.add`);
|
|
9058
|
+
}
|
|
9059
|
+
return docRef;
|
|
9060
|
+
}
|
|
9061
|
+
async _handleReplayCollectionAdd(spanInfo, inputValue, collectionRef) {
|
|
9062
|
+
logger.debug(`[FirestoreInstrumentation] Replaying collection.add`);
|
|
9063
|
+
const mockData = await findMockResponseAsync({
|
|
9064
|
+
mockRequestData: {
|
|
9065
|
+
traceId: spanInfo.traceId,
|
|
9066
|
+
spanId: spanInfo.spanId,
|
|
9067
|
+
name: "firestore.collection.add",
|
|
9068
|
+
inputValue: createMockInputValue(inputValue),
|
|
9069
|
+
packageName: PACKAGE_NAME,
|
|
9070
|
+
instrumentationName: this.INSTRUMENTATION_NAME,
|
|
9071
|
+
submoduleName: "collection",
|
|
9072
|
+
kind: __opentelemetry_api.SpanKind.CLIENT
|
|
9073
|
+
},
|
|
9074
|
+
tuskDrift: this.tuskDrift
|
|
9075
|
+
});
|
|
9076
|
+
if (!mockData) {
|
|
9077
|
+
logger.warn(`[FirestoreInstrumentation] No mock data found for collection.add: ${inputValue.path}`);
|
|
9078
|
+
return Promise.reject(/* @__PURE__ */ new Error("No mock data found"));
|
|
9079
|
+
}
|
|
9080
|
+
const recordedId = mockData.result.id;
|
|
9081
|
+
if (!this.originalCollectionDocFn) {
|
|
9082
|
+
logger.error(`[FirestoreInstrumentation] Original doc function not available`);
|
|
9083
|
+
return Promise.reject(/* @__PURE__ */ new Error("Original doc function not available"));
|
|
9084
|
+
}
|
|
9085
|
+
return this.originalCollectionDocFn.call(collectionRef, recordedId);
|
|
9086
|
+
}
|
|
9087
|
+
_getCollectionDocPatchFn() {
|
|
9088
|
+
const self = this;
|
|
9089
|
+
return (originalDoc) => {
|
|
9090
|
+
return function(documentPath) {
|
|
9091
|
+
const collectionPath = this.path;
|
|
9092
|
+
const inputValue = {
|
|
9093
|
+
operation: "collection.doc",
|
|
9094
|
+
path: collectionPath,
|
|
9095
|
+
documentId: documentPath
|
|
9096
|
+
};
|
|
9097
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
9098
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this), {
|
|
9099
|
+
name: "firestore.collection.doc",
|
|
9100
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
9101
|
+
submodule: "collection",
|
|
9102
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
9103
|
+
packageName: PACKAGE_NAME,
|
|
9104
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
9105
|
+
inputValue,
|
|
9106
|
+
isPreAppStart: false,
|
|
9107
|
+
stopRecordingChildSpans: true
|
|
9108
|
+
}, (spanInfo) => {
|
|
9109
|
+
const mockData = findMockResponseSync({
|
|
9110
|
+
mockRequestData: {
|
|
9111
|
+
traceId: spanInfo.traceId,
|
|
9112
|
+
spanId: spanInfo.spanId,
|
|
9113
|
+
name: "firestore.collection.doc",
|
|
9114
|
+
inputValue: createMockInputValue(inputValue),
|
|
9115
|
+
packageName: PACKAGE_NAME,
|
|
9116
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
9117
|
+
submoduleName: "collection",
|
|
9118
|
+
kind: __opentelemetry_api.SpanKind.CLIENT
|
|
9119
|
+
},
|
|
9120
|
+
tuskDrift: self.tuskDrift
|
|
9121
|
+
});
|
|
9122
|
+
if (!mockData) {
|
|
9123
|
+
logger.warn(`[FirestoreInstrumentation] No mock data found for collection.doc: ${collectionPath}`);
|
|
9124
|
+
throw new Error("No mock data found for collection.doc");
|
|
9125
|
+
}
|
|
9126
|
+
const recordedId = mockData.result.id;
|
|
9127
|
+
logger.debug(`[FirestoreInstrumentation] replaying doc call with recorded id: ${recordedId}`);
|
|
9128
|
+
const docRef = originalDoc.call(this, recordedId);
|
|
9129
|
+
logger.debug(`[FirestoreInstrumentation] doc ref, id`, docRef, recordedId);
|
|
9130
|
+
return docRef;
|
|
9131
|
+
});
|
|
9132
|
+
} });
|
|
9133
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
9134
|
+
originalFunctionCall: () => documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this),
|
|
9135
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
9136
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this), {
|
|
9137
|
+
name: "firestore.collection.doc",
|
|
9138
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
9139
|
+
submodule: "collection",
|
|
9140
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
9141
|
+
packageName: PACKAGE_NAME,
|
|
9142
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
9143
|
+
inputValue,
|
|
9144
|
+
isPreAppStart,
|
|
9145
|
+
stopRecordingChildSpans: true
|
|
9146
|
+
}, (spanInfo) => {
|
|
9147
|
+
const docRef = documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this);
|
|
9148
|
+
const result = {
|
|
9149
|
+
id: docRef.id,
|
|
9150
|
+
path: docRef.path
|
|
9151
|
+
};
|
|
9152
|
+
try {
|
|
9153
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: result });
|
|
9154
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
|
|
9155
|
+
} catch {
|
|
9156
|
+
logger.error(`[FirestoreInstrumentation] Error updating span attributes for collection.doc`);
|
|
9157
|
+
}
|
|
9158
|
+
return docRef;
|
|
9159
|
+
});
|
|
9160
|
+
},
|
|
9161
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
9162
|
+
});
|
|
9163
|
+
else return documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this);
|
|
9164
|
+
};
|
|
9165
|
+
};
|
|
9166
|
+
}
|
|
9167
|
+
_getQueryGetPatchFn() {
|
|
9168
|
+
const self = this;
|
|
9169
|
+
return (originalGet) => {
|
|
9170
|
+
return function() {
|
|
9171
|
+
const inputValue = {
|
|
9172
|
+
operation: "query.get",
|
|
9173
|
+
path: this._queryOptions?.parentPath?.formattedName || "unknown"
|
|
9174
|
+
};
|
|
9175
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
9176
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
|
|
9177
|
+
name: "firestore.query.get",
|
|
9178
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
9179
|
+
submodule: "query",
|
|
9180
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
9181
|
+
packageName: PACKAGE_NAME,
|
|
9182
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
9183
|
+
inputValue,
|
|
9184
|
+
isPreAppStart: false,
|
|
9185
|
+
stopRecordingChildSpans: true
|
|
9186
|
+
}, (spanInfo) => {
|
|
9187
|
+
return self._handleReplayQueryGet(spanInfo, inputValue);
|
|
9188
|
+
});
|
|
9189
|
+
} });
|
|
9190
|
+
else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
9191
|
+
originalFunctionCall: () => originalGet.call(this),
|
|
9192
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
9193
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
|
|
9194
|
+
name: "firestore.query.get",
|
|
9195
|
+
kind: __opentelemetry_api.SpanKind.CLIENT,
|
|
9196
|
+
submodule: "query",
|
|
9197
|
+
packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
|
|
9198
|
+
packageName: PACKAGE_NAME,
|
|
9199
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
9200
|
+
inputValue,
|
|
9201
|
+
isPreAppStart,
|
|
9202
|
+
stopRecordingChildSpans: true
|
|
9203
|
+
}, (spanInfo) => {
|
|
9204
|
+
return self._handleRecordQueryGet(spanInfo, originalGet, this);
|
|
9205
|
+
});
|
|
9206
|
+
},
|
|
9207
|
+
spanKind: __opentelemetry_api.SpanKind.CLIENT
|
|
9208
|
+
});
|
|
9209
|
+
else return originalGet.call(this);
|
|
7941
9210
|
};
|
|
7942
9211
|
};
|
|
7943
9212
|
}
|
|
9213
|
+
async _handleRecordQueryGet(spanInfo, originalGet, context$4) {
|
|
9214
|
+
const querySnapshot = await originalGet.call(context$4);
|
|
9215
|
+
const queryResult = {
|
|
9216
|
+
docs: querySnapshot.docs.map((doc) => ({
|
|
9217
|
+
id: doc.id,
|
|
9218
|
+
path: doc.ref.path,
|
|
9219
|
+
exists: doc.exists,
|
|
9220
|
+
data: doc.exists ? doc.data() : void 0,
|
|
9221
|
+
createTime: doc.createTime ? {
|
|
9222
|
+
seconds: doc.createTime.seconds,
|
|
9223
|
+
nanoseconds: doc.createTime.nanoseconds
|
|
9224
|
+
} : void 0,
|
|
9225
|
+
updateTime: doc.updateTime ? {
|
|
9226
|
+
seconds: doc.updateTime.seconds,
|
|
9227
|
+
nanoseconds: doc.updateTime.nanoseconds
|
|
9228
|
+
} : void 0,
|
|
9229
|
+
readTime: doc.readTime ? {
|
|
9230
|
+
seconds: doc.readTime.seconds,
|
|
9231
|
+
nanoseconds: doc.readTime.nanoseconds
|
|
9232
|
+
} : void 0
|
|
9233
|
+
})),
|
|
9234
|
+
size: querySnapshot.size,
|
|
9235
|
+
empty: querySnapshot.empty,
|
|
9236
|
+
readTime: querySnapshot.readTime ? {
|
|
9237
|
+
seconds: querySnapshot.readTime.seconds,
|
|
9238
|
+
nanoseconds: querySnapshot.readTime.nanoseconds
|
|
9239
|
+
} : void 0
|
|
9240
|
+
};
|
|
9241
|
+
try {
|
|
9242
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: queryResult });
|
|
9243
|
+
SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
|
|
9244
|
+
} catch {
|
|
9245
|
+
logger.error(`[FirestoreInstrumentation] Error updating span attributes for query.get`);
|
|
9246
|
+
}
|
|
9247
|
+
return querySnapshot;
|
|
9248
|
+
}
|
|
9249
|
+
async _handleReplayQueryGet(spanInfo, inputValue) {
|
|
9250
|
+
logger.debug(`[FirestoreInstrumentation] Replaying query.get`);
|
|
9251
|
+
const mockData = await findMockResponseAsync({
|
|
9252
|
+
mockRequestData: {
|
|
9253
|
+
traceId: spanInfo.traceId,
|
|
9254
|
+
spanId: spanInfo.spanId,
|
|
9255
|
+
name: "firestore.query.get",
|
|
9256
|
+
inputValue: createMockInputValue(inputValue),
|
|
9257
|
+
packageName: PACKAGE_NAME,
|
|
9258
|
+
instrumentationName: this.INSTRUMENTATION_NAME,
|
|
9259
|
+
submoduleName: "query",
|
|
9260
|
+
kind: __opentelemetry_api.SpanKind.CLIENT
|
|
9261
|
+
},
|
|
9262
|
+
tuskDrift: this.tuskDrift
|
|
9263
|
+
});
|
|
9264
|
+
if (!mockData) {
|
|
9265
|
+
logger.warn(`[FirestoreInstrumentation] No mock data found for query.get: ${inputValue.path}`);
|
|
9266
|
+
return Promise.reject(/* @__PURE__ */ new Error("No mock data found"));
|
|
9267
|
+
}
|
|
9268
|
+
const queryResult = mockData.result;
|
|
9269
|
+
return new TdFirestoreQueryMock(queryResult);
|
|
9270
|
+
}
|
|
7944
9271
|
_wrap(target, propertyName, wrapper) {
|
|
7945
|
-
|
|
9272
|
+
if (!target || typeof target[propertyName] !== "function") {
|
|
9273
|
+
logger.warn(`[FirestoreInstrumentation] Cannot wrap ${propertyName}: not a function or target is undefined`);
|
|
9274
|
+
return;
|
|
9275
|
+
}
|
|
9276
|
+
const original = target[propertyName];
|
|
9277
|
+
target[propertyName] = wrapper(original);
|
|
7946
9278
|
}
|
|
7947
9279
|
};
|
|
7948
|
-
GrpcInstrumentation.metadataStore = /* @__PURE__ */ new Map();
|
|
7949
9280
|
|
|
7950
9281
|
//#endregion
|
|
7951
9282
|
//#region src/instrumentation/libraries/nextjs/Instrumentation.ts
|
|
@@ -8005,6 +9336,12 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
|
8005
9336
|
const self = this;
|
|
8006
9337
|
return (originalHandleRequest) => {
|
|
8007
9338
|
return async function(req, res, parsedUrl) {
|
|
9339
|
+
if (self.mode === TuskDriftMode.RECORD) {
|
|
9340
|
+
if (!shouldSample({
|
|
9341
|
+
samplingRate: self.tuskDrift.getSamplingRate(),
|
|
9342
|
+
isAppReady: self.tuskDrift.isAppReady()
|
|
9343
|
+
})) return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
9344
|
+
}
|
|
8008
9345
|
const method = req.method || "GET";
|
|
8009
9346
|
const url = req.url || "/";
|
|
8010
9347
|
logger.debug(`[NextjsInstrumentation] Intercepted Next.js request: ${method} ${url}`);
|
|
@@ -8020,6 +9357,7 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
|
8020
9357
|
logger.debug(`[NextjsInstrumentation] No trace ID found, calling original handler`);
|
|
8021
9358
|
return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
8022
9359
|
}
|
|
9360
|
+
logger.debug(`[NextjsInstrumentation] Setting replay trace id`, replayTraceId);
|
|
8023
9361
|
const envVars = self.replayHooks.extractEnvVarsFromHeaders(req);
|
|
8024
9362
|
if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
|
|
8025
9363
|
const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
|
|
@@ -8050,13 +9388,6 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
|
8050
9388
|
} });
|
|
8051
9389
|
else if (self.mode === TuskDriftMode.RECORD) {
|
|
8052
9390
|
if (method.toUpperCase() === "OPTIONS" || !!req.headers["access-control-request-method"]) return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
8053
|
-
if (!shouldSample({
|
|
8054
|
-
samplingRate: self.tuskDrift.getSamplingRate(),
|
|
8055
|
-
isAppReady: self.tuskDrift.isAppReady()
|
|
8056
|
-
})) {
|
|
8057
|
-
logger.debug(`[NextjsInstrumentation] Skipping server span due to sampling rate: ${url}`);
|
|
8058
|
-
return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
8059
|
-
}
|
|
8060
9391
|
logger.debug(`[NextjsInstrumentation] Creating server span for ${method} ${url}`);
|
|
8061
9392
|
return handleRecordMode({
|
|
8062
9393
|
originalFunctionCall: () => originalHandleRequest.call(this, req, res, parsedUrl),
|
|
@@ -8135,6 +9466,19 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
|
8135
9466
|
};
|
|
8136
9467
|
try {
|
|
8137
9468
|
await originalHandleRequest.call(thisContext, req, res, parsedUrl);
|
|
9469
|
+
} catch (error) {
|
|
9470
|
+
logger.error(`[NextjsInstrumentation] Error in Next.js request: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
9471
|
+
try {
|
|
9472
|
+
SpanUtils.endSpan(spanInfo.span, {
|
|
9473
|
+
code: __opentelemetry_api.SpanStatusCode.ERROR,
|
|
9474
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
9475
|
+
});
|
|
9476
|
+
} catch (e) {
|
|
9477
|
+
logger.error(`[NextjsInstrumentation] Error ending span:`, e);
|
|
9478
|
+
}
|
|
9479
|
+
throw error;
|
|
9480
|
+
}
|
|
9481
|
+
try {
|
|
8138
9482
|
if (!capturedStatusCode) {
|
|
8139
9483
|
capturedStatusCode = res.statusCode;
|
|
8140
9484
|
capturedStatusMessage = res.statusMessage;
|
|
@@ -8159,7 +9503,6 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
|
8159
9503
|
outputValue.bodySize = responseBuffer.length;
|
|
8160
9504
|
} catch (error) {
|
|
8161
9505
|
logger.error(`[NextjsInstrumentation] Error processing response body:`, error);
|
|
8162
|
-
outputValue.bodyProcessingError = error instanceof Error ? error.message : String(error);
|
|
8163
9506
|
}
|
|
8164
9507
|
SpanUtils.addSpanAttributes(spanInfo.span, {
|
|
8165
9508
|
inputValue: completeInputValue,
|
|
@@ -8179,6 +9522,11 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
|
8179
9522
|
message: `HTTP ${capturedStatusCode}`
|
|
8180
9523
|
} : { code: __opentelemetry_api.SpanStatusCode.OK };
|
|
8181
9524
|
SpanUtils.setStatus(spanInfo.span, status);
|
|
9525
|
+
const decodedType = getDecodedType(outputValue.headers?.["content-type"] || "");
|
|
9526
|
+
if (decodedType && STATIC_ASSET_TYPES.has(decodedType)) {
|
|
9527
|
+
TraceBlockingManager.getInstance().blockTrace(spanInfo.traceId);
|
|
9528
|
+
logger.debug(`[NextjsInstrumentation] Blocking trace ${spanInfo.traceId} because it is an static asset response. Decoded type: ${decodedType}`);
|
|
9529
|
+
}
|
|
8182
9530
|
SpanUtils.endSpan(spanInfo.span);
|
|
8183
9531
|
if (self.mode === TuskDriftMode.REPLAY) try {
|
|
8184
9532
|
const now = OriginalGlobalUtils.getOriginalDate();
|
|
@@ -8236,12 +9584,15 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
|
8236
9584
|
logger.error("[NextjsInstrumentation] Failed to build/send inbound replay span:", e);
|
|
8237
9585
|
}
|
|
8238
9586
|
} catch (error) {
|
|
8239
|
-
logger.error(`[NextjsInstrumentation] Error in Next.js request: ${error instanceof Error ? error.message :
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
9587
|
+
logger.error(`[NextjsInstrumentation] Error in Next.js request: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
9588
|
+
try {
|
|
9589
|
+
SpanUtils.endSpan(spanInfo.span, {
|
|
9590
|
+
code: __opentelemetry_api.SpanStatusCode.ERROR,
|
|
9591
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
9592
|
+
});
|
|
9593
|
+
} catch (e) {
|
|
9594
|
+
logger.error(`[NextjsInstrumentation] Error ending span:`, e);
|
|
9595
|
+
}
|
|
8245
9596
|
}
|
|
8246
9597
|
}
|
|
8247
9598
|
/**
|
|
@@ -10468,20 +11819,21 @@ var SpanTransformer = class SpanTransformer {
|
|
|
10468
11819
|
const inputData = JSON.parse(inputValueString);
|
|
10469
11820
|
const inputSchemaMergesString = attributes[TdSpanAttributes.INPUT_SCHEMA_MERGES];
|
|
10470
11821
|
const inputSchemaMerges = inputSchemaMergesString ? JSON.parse(inputSchemaMergesString) : void 0;
|
|
10471
|
-
const { schema: inputSchema, decodedValueHash: inputValueHash } = JsonSchemaHelper.generateSchemaAndHash(inputData, inputSchemaMerges);
|
|
11822
|
+
const { schema: inputSchema, decodedValueHash: inputValueHash, decodedSchemaHash: inputSchemaHash } = JsonSchemaHelper.generateSchemaAndHash(inputData, inputSchemaMerges);
|
|
10472
11823
|
let outputData = {};
|
|
10473
11824
|
let outputSchema = {
|
|
10474
11825
|
type: __use_tusk_drift_schemas_core_json_schema.JsonSchemaType.OBJECT,
|
|
10475
11826
|
properties: {}
|
|
10476
11827
|
};
|
|
10477
11828
|
let outputValueHash = "";
|
|
11829
|
+
let outputSchemaHash = "";
|
|
10478
11830
|
if (attributes[TdSpanAttributes.OUTPUT_VALUE]) {
|
|
10479
11831
|
const outputValueString = attributes[TdSpanAttributes.OUTPUT_VALUE];
|
|
10480
11832
|
outputData = JSON.parse(outputValueString);
|
|
10481
11833
|
const outputSchemaMergesString = attributes[TdSpanAttributes.OUTPUT_SCHEMA_MERGES];
|
|
10482
11834
|
const outputSchemaMerges = outputSchemaMergesString ? JSON.parse(outputSchemaMergesString) : void 0;
|
|
10483
|
-
({schema: outputSchema, decodedValueHash: outputValueHash} = JsonSchemaHelper.generateSchemaAndHash(outputData, outputSchemaMerges));
|
|
10484
|
-
} else ({schema: outputSchema, decodedSchemaHash:
|
|
11835
|
+
({schema: outputSchema, decodedValueHash: outputValueHash, decodedSchemaHash: outputSchemaHash} = JsonSchemaHelper.generateSchemaAndHash(outputData, outputSchemaMerges));
|
|
11836
|
+
} else ({schema: outputSchema, decodedValueHash: outputValueHash, decodedSchemaHash: outputSchemaHash} = JsonSchemaHelper.generateSchemaAndHash(outputData));
|
|
10485
11837
|
let metadata = void 0;
|
|
10486
11838
|
if (attributes[TdSpanAttributes.METADATA]) metadata = JSON.parse(attributes[TdSpanAttributes.METADATA]);
|
|
10487
11839
|
let transformMetadata;
|
|
@@ -10505,8 +11857,8 @@ var SpanTransformer = class SpanTransformer {
|
|
|
10505
11857
|
outputValue: outputData,
|
|
10506
11858
|
inputSchema,
|
|
10507
11859
|
outputSchema,
|
|
10508
|
-
inputSchemaHash
|
|
10509
|
-
outputSchemaHash
|
|
11860
|
+
inputSchemaHash,
|
|
11861
|
+
outputSchemaHash,
|
|
10510
11862
|
inputValueHash,
|
|
10511
11863
|
outputValueHash,
|
|
10512
11864
|
kind: span.kind,
|
|
@@ -10749,18 +12101,35 @@ var TdSpanExporter = class {
|
|
|
10749
12101
|
*/
|
|
10750
12102
|
export(spans, resultCallback) {
|
|
10751
12103
|
logger.debug(`TdSpanExporter.export() called with ${spans.length} span(s)`);
|
|
10752
|
-
const
|
|
10753
|
-
|
|
12104
|
+
const traceBlockingManager = TraceBlockingManager.getInstance();
|
|
12105
|
+
const filteredSpansBasedOnLibraryName = spans.filter((span) => {
|
|
12106
|
+
if (span.instrumentationLibrary.name === TD_INSTRUMENTATION_LIBRARY_NAME) return true;
|
|
12107
|
+
return false;
|
|
12108
|
+
});
|
|
12109
|
+
logger.debug(`After filtering based on library name: ${filteredSpansBasedOnLibraryName.length} span(s) remaining`);
|
|
12110
|
+
const MAX_SPAN_SIZE_MB = 1;
|
|
12111
|
+
const MAX_SPAN_SIZE_BYTES = MAX_SPAN_SIZE_MB * 1024 * 1024;
|
|
12112
|
+
const filteredSpansBasedOnSize = filteredSpansBasedOnLibraryName.filter((span) => {
|
|
12113
|
+
const traceId = span.spanContext().traceId;
|
|
12114
|
+
if (traceBlockingManager.isTraceBlocked(traceId)) {
|
|
12115
|
+
logger.debug(`Skipping span '${span.name}' (${span.spanContext().spanId}) - trace ${traceId} is blocked`);
|
|
12116
|
+
return false;
|
|
12117
|
+
}
|
|
12118
|
+
const inputValueString = span.attributes[TdSpanAttributes.INPUT_VALUE] || "";
|
|
12119
|
+
const outputValueString = span.attributes[TdSpanAttributes.OUTPUT_VALUE] || "";
|
|
12120
|
+
const inputSize = Buffer.byteLength(inputValueString, "utf8");
|
|
12121
|
+
const outputSize = Buffer.byteLength(outputValueString, "utf8");
|
|
12122
|
+
const estimatedTotalSize = inputSize + outputSize + 5e4;
|
|
12123
|
+
const estimatedSizeMB = estimatedTotalSize / (1024 * 1024);
|
|
12124
|
+
if (estimatedTotalSize > MAX_SPAN_SIZE_BYTES) {
|
|
12125
|
+
traceBlockingManager.blockTrace(traceId);
|
|
12126
|
+
logger.warn(`Blocking trace ${traceId} - span '${span.name}' (${span.spanContext().spanId}) has estimated size ${estimatedSizeMB.toFixed(2)} MB exceeding limit of ${MAX_SPAN_SIZE_MB} MB. Future spans for this trace will be prevented.`);
|
|
12127
|
+
return false;
|
|
12128
|
+
}
|
|
10754
12129
|
return true;
|
|
10755
12130
|
});
|
|
10756
|
-
logger.debug(`
|
|
10757
|
-
|
|
10758
|
-
try {
|
|
10759
|
-
cleanSpans = filteredSpans.map((span) => SpanTransformer.transformSpanToCleanJSON(span));
|
|
10760
|
-
} catch (error) {
|
|
10761
|
-
logger.error("Error transforming spans to CleanSpanData", error);
|
|
10762
|
-
throw error;
|
|
10763
|
-
}
|
|
12131
|
+
logger.debug(`Filtered ${filteredSpansBasedOnLibraryName.length - filteredSpansBasedOnSize.length} oversized span(s), ${filteredSpansBasedOnSize.length} remaining`);
|
|
12132
|
+
const cleanSpans = filteredSpansBasedOnSize.map((span) => SpanTransformer.transformSpanToCleanJSON(span));
|
|
10764
12133
|
if (this.adapters.length === 0) {
|
|
10765
12134
|
logger.debug("No adapters configured");
|
|
10766
12135
|
resultCallback({ code: import_src.ExportResultCode.SUCCESS });
|
|
@@ -10895,15 +12264,12 @@ var ProtobufCommunicator = class {
|
|
|
10895
12264
|
});
|
|
10896
12265
|
}
|
|
10897
12266
|
/**
|
|
10898
|
-
* This function uses a Node.js
|
|
10899
|
-
* The
|
|
10900
|
-
*
|
|
10901
|
-
* Since this function blocks the main thread, there is a perfomance impact for using this. We should use requestMockAsync whenever possilbe and only use this function
|
|
10902
|
-
* for instrumentations that request fetching mocks synchronously.
|
|
12267
|
+
* This function uses a separate Node.js child process to communicate with the CLI over a socket.
|
|
12268
|
+
* The child process creates its own connection and event loop, allowing proper async socket handling.
|
|
12269
|
+
* The parent process blocks synchronously waiting for the child to complete.
|
|
10903
12270
|
*
|
|
10904
|
-
*
|
|
10905
|
-
*
|
|
10906
|
-
* Better approach is replacing nc command with pure Node.js implementation
|
|
12271
|
+
* Since this function blocks the main thread, there is a performance impact. We should use requestMockAsync whenever possible and only use this function
|
|
12272
|
+
* for instrumentations that require fetching mocks synchronously.
|
|
10907
12273
|
*/
|
|
10908
12274
|
requestMockSync(mockRequest) {
|
|
10909
12275
|
const requestId = this.generateRequestId();
|
|
@@ -10926,10 +12292,15 @@ var ProtobufCommunicator = class {
|
|
|
10926
12292
|
getMockRequest: protoMockRequest
|
|
10927
12293
|
}
|
|
10928
12294
|
});
|
|
12295
|
+
logger.debug("Sending protobuf request to CLI (sync)", {
|
|
12296
|
+
outboundSpan: mockRequest.outboundSpan,
|
|
12297
|
+
testId: mockRequest.testId
|
|
12298
|
+
});
|
|
10929
12299
|
const messageBytes = __use_tusk_drift_schemas_core_communication.SDKMessage.toBinary(sdkMessage);
|
|
10930
12300
|
const tempDir = os.default.tmpdir();
|
|
10931
|
-
const requestFile = path.default.join(tempDir, `tusk-request-${requestId}.bin`);
|
|
10932
|
-
const responseFile = path.default.join(tempDir, `tusk-response-${requestId}.bin`);
|
|
12301
|
+
const requestFile = path.default.join(tempDir, `tusk-sync-request-${requestId}.bin`);
|
|
12302
|
+
const responseFile = path.default.join(tempDir, `tusk-sync-response-${requestId}.bin`);
|
|
12303
|
+
const scriptFile = path.default.join(tempDir, `tusk-sync-script-${requestId}.js`);
|
|
10933
12304
|
try {
|
|
10934
12305
|
const lengthBuffer = Buffer.allocUnsafe(4);
|
|
10935
12306
|
lengthBuffer.writeUInt32BE(messageBytes.length, 0);
|
|
@@ -10938,19 +12309,112 @@ var ProtobufCommunicator = class {
|
|
|
10938
12309
|
const mockSocket = OriginalGlobalUtils.getOriginalProcessEnvVar("TUSK_MOCK_SOCKET");
|
|
10939
12310
|
const mockHost = OriginalGlobalUtils.getOriginalProcessEnvVar("TUSK_MOCK_HOST");
|
|
10940
12311
|
const mockPort = OriginalGlobalUtils.getOriginalProcessEnvVar("TUSK_MOCK_PORT");
|
|
10941
|
-
let
|
|
10942
|
-
if (mockSocket) {
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
}
|
|
10946
|
-
else {
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
}
|
|
12312
|
+
let connectionConfig;
|
|
12313
|
+
if (mockSocket) connectionConfig = {
|
|
12314
|
+
type: "unix",
|
|
12315
|
+
path: mockSocket
|
|
12316
|
+
};
|
|
12317
|
+
else if (mockHost && mockPort) connectionConfig = {
|
|
12318
|
+
type: "tcp",
|
|
12319
|
+
host: mockHost,
|
|
12320
|
+
port: parseInt(mockPort, 10)
|
|
12321
|
+
};
|
|
12322
|
+
else connectionConfig = {
|
|
12323
|
+
type: "unix",
|
|
12324
|
+
path: path.default.join(os.default.tmpdir(), "tusk-connect.sock")
|
|
12325
|
+
};
|
|
12326
|
+
fs.default.writeFileSync(scriptFile, `
|
|
12327
|
+
const net = require('net');
|
|
12328
|
+
const fs = require('fs');
|
|
12329
|
+
|
|
12330
|
+
const requestFile = process.argv[2];
|
|
12331
|
+
const responseFile = process.argv[3];
|
|
12332
|
+
const config = JSON.parse(process.argv[4]);
|
|
12333
|
+
|
|
12334
|
+
let responseReceived = false;
|
|
12335
|
+
let timeoutId;
|
|
12336
|
+
|
|
12337
|
+
function cleanup(exitCode) {
|
|
12338
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
12339
|
+
process.exit(exitCode);
|
|
12340
|
+
}
|
|
12341
|
+
|
|
12342
|
+
try {
|
|
12343
|
+
// Read the request data
|
|
12344
|
+
const requestData = fs.readFileSync(requestFile);
|
|
12345
|
+
|
|
12346
|
+
// Create connection based on config
|
|
12347
|
+
const client = config.type === 'unix'
|
|
12348
|
+
? net.createConnection({ path: config.path })
|
|
12349
|
+
: net.createConnection({ host: config.host, port: config.port });
|
|
12350
|
+
|
|
12351
|
+
const incomingChunks = [];
|
|
12352
|
+
let incomingBuffer = Buffer.alloc(0);
|
|
12353
|
+
|
|
12354
|
+
// Set timeout
|
|
12355
|
+
timeoutId = setTimeout(() => {
|
|
12356
|
+
if (!responseReceived) {
|
|
12357
|
+
console.error('Timeout waiting for response');
|
|
12358
|
+
client.destroy();
|
|
12359
|
+
cleanup(1);
|
|
12360
|
+
}
|
|
12361
|
+
}, 10000);
|
|
12362
|
+
|
|
12363
|
+
client.on('connect', () => {
|
|
12364
|
+
// Send the request
|
|
12365
|
+
client.write(requestData);
|
|
12366
|
+
});
|
|
12367
|
+
|
|
12368
|
+
client.on('data', (data) => {
|
|
12369
|
+
incomingBuffer = Buffer.concat([incomingBuffer, data]);
|
|
12370
|
+
|
|
12371
|
+
// Try to parse complete message (4 byte length prefix + message)
|
|
12372
|
+
while (incomingBuffer.length >= 4) {
|
|
12373
|
+
const messageLength = incomingBuffer.readUInt32BE(0);
|
|
12374
|
+
|
|
12375
|
+
if (incomingBuffer.length < 4 + messageLength) {
|
|
12376
|
+
// Incomplete message, wait for more data
|
|
12377
|
+
break;
|
|
12378
|
+
}
|
|
12379
|
+
|
|
12380
|
+
// We have a complete message
|
|
12381
|
+
const messageData = incomingBuffer.slice(4, 4 + messageLength);
|
|
12382
|
+
incomingBuffer = incomingBuffer.slice(4 + messageLength);
|
|
12383
|
+
|
|
12384
|
+
// Write the complete response (including length prefix)
|
|
12385
|
+
const lengthPrefix = Buffer.allocUnsafe(4);
|
|
12386
|
+
lengthPrefix.writeUInt32BE(messageLength, 0);
|
|
12387
|
+
fs.writeFileSync(responseFile, Buffer.concat([lengthPrefix, messageData]));
|
|
12388
|
+
|
|
12389
|
+
responseReceived = true;
|
|
12390
|
+
client.destroy();
|
|
12391
|
+
cleanup(0);
|
|
12392
|
+
break;
|
|
12393
|
+
}
|
|
12394
|
+
});
|
|
12395
|
+
|
|
12396
|
+
client.on('error', (err) => {
|
|
12397
|
+
if (!responseReceived) {
|
|
12398
|
+
console.error('Connection error:', err.message);
|
|
12399
|
+
cleanup(1);
|
|
12400
|
+
}
|
|
12401
|
+
});
|
|
12402
|
+
|
|
12403
|
+
client.on('close', () => {
|
|
12404
|
+
if (!responseReceived) {
|
|
12405
|
+
console.error('Connection closed without response');
|
|
12406
|
+
cleanup(1);
|
|
12407
|
+
}
|
|
12408
|
+
});
|
|
12409
|
+
|
|
12410
|
+
} catch (err) {
|
|
12411
|
+
console.error('Script error:', err.message);
|
|
12412
|
+
cleanup(1);
|
|
12413
|
+
}
|
|
12414
|
+
`);
|
|
10951
12415
|
try {
|
|
10952
|
-
(0, child_process.execSync)(
|
|
10953
|
-
timeout:
|
|
12416
|
+
(0, child_process.execSync)(`node "${scriptFile}" "${requestFile}" "${responseFile}" '${JSON.stringify(connectionConfig)}'`, {
|
|
12417
|
+
timeout: 12e3,
|
|
10954
12418
|
stdio: "pipe"
|
|
10955
12419
|
});
|
|
10956
12420
|
const responseBuffer = fs.default.readFileSync(responseFile);
|
|
@@ -10975,22 +12439,27 @@ var ProtobufCommunicator = class {
|
|
|
10975
12439
|
error: mockResponse.error || "Mock not found"
|
|
10976
12440
|
};
|
|
10977
12441
|
} catch (error) {
|
|
10978
|
-
logger.error("[ProtobufCommunicator] error
|
|
12442
|
+
logger.error("[ProtobufCommunicator] error in sync request child process:", error);
|
|
10979
12443
|
throw error;
|
|
10980
12444
|
}
|
|
10981
12445
|
} catch (error) {
|
|
10982
12446
|
throw new Error(`Sync request failed: ${error.message}`);
|
|
10983
12447
|
} finally {
|
|
10984
12448
|
try {
|
|
10985
|
-
fs.default.unlinkSync(requestFile);
|
|
12449
|
+
if (fs.default.existsSync(requestFile)) fs.default.unlinkSync(requestFile);
|
|
10986
12450
|
} catch (e) {
|
|
10987
12451
|
logger.error("[ProtobufCommunicator] error cleaning up request file:", e);
|
|
10988
12452
|
}
|
|
10989
12453
|
try {
|
|
10990
|
-
fs.default.unlinkSync(responseFile);
|
|
12454
|
+
if (fs.default.existsSync(responseFile)) fs.default.unlinkSync(responseFile);
|
|
10991
12455
|
} catch (e) {
|
|
10992
12456
|
logger.error("[ProtobufCommunicator] error cleaning up response file:", e);
|
|
10993
12457
|
}
|
|
12458
|
+
try {
|
|
12459
|
+
if (fs.default.existsSync(scriptFile)) fs.default.unlinkSync(scriptFile);
|
|
12460
|
+
} catch (e) {
|
|
12461
|
+
logger.error("[ProtobufCommunicator] error cleaning up script file:", e);
|
|
12462
|
+
}
|
|
10994
12463
|
}
|
|
10995
12464
|
}
|
|
10996
12465
|
async sendProtobufMessage(message) {
|
|
@@ -11158,7 +12627,8 @@ const TuskDriftInstrumentationModuleNames = [
|
|
|
11158
12627
|
"jwks-rsa",
|
|
11159
12628
|
"mysql2",
|
|
11160
12629
|
"ioredis",
|
|
11161
|
-
"@grpc/grpc-js"
|
|
12630
|
+
"@grpc/grpc-js",
|
|
12631
|
+
"@google-cloud/firestore"
|
|
11162
12632
|
];
|
|
11163
12633
|
|
|
11164
12634
|
//#endregion
|
|
@@ -11280,6 +12750,10 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
11280
12750
|
enabled: true,
|
|
11281
12751
|
mode: this.mode
|
|
11282
12752
|
});
|
|
12753
|
+
new FirestoreInstrumentation({
|
|
12754
|
+
enabled: true,
|
|
12755
|
+
mode: this.mode
|
|
12756
|
+
});
|
|
11283
12757
|
new NextjsInstrumentation({
|
|
11284
12758
|
enabled: true,
|
|
11285
12759
|
mode: this.mode
|
|
@@ -11452,6 +12926,10 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
11452
12926
|
}
|
|
11453
12927
|
}
|
|
11454
12928
|
requestMockSync(mockRequest) {
|
|
12929
|
+
if (!this.isConnectedWithCLI) {
|
|
12930
|
+
logger.error("Requesting sync mock but CLI is not ready yet");
|
|
12931
|
+
throw new Error("Requesting sync mock but CLI is not ready yet");
|
|
12932
|
+
}
|
|
11455
12933
|
const mockRequestCore = this.createMockRequestCore(mockRequest);
|
|
11456
12934
|
if (mockRequestCore) return mockRequestCore;
|
|
11457
12935
|
return this.requestMockFromCLISync(mockRequest);
|
|
@@ -11499,7 +12977,7 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
11499
12977
|
return this.initParams;
|
|
11500
12978
|
}
|
|
11501
12979
|
getTracer() {
|
|
11502
|
-
return __opentelemetry_api.trace.getTracer(
|
|
12980
|
+
return __opentelemetry_api.trace.getTracer(TD_INSTRUMENTATION_LIBRARY_NAME);
|
|
11503
12981
|
}
|
|
11504
12982
|
};
|
|
11505
12983
|
var TuskDriftSDK = class {
|