@use-tusk/drift-node-sdk 0.1.5 → 0.1.6
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 -1
- package/dist/index.cjs +753 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -1
- package/dist/index.d.ts +81 -1
- package/dist/index.js +683 -50
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import * as fs$1 from "fs";
|
|
3
3
|
import fs from "fs";
|
|
4
|
-
import os from "os";
|
|
5
4
|
import * as path$1 from "path";
|
|
6
5
|
import path, { normalize } from "path";
|
|
7
|
-
import { satisfies } from "semver";
|
|
6
|
+
import { parse, satisfies } from "semver";
|
|
7
|
+
import os from "os";
|
|
8
8
|
import { Hook } from "require-in-the-middle";
|
|
9
9
|
import { Hook as Hook$1 } from "import-in-the-middle";
|
|
10
10
|
import { Struct, Value } from "@use-tusk/drift-schemas/google/protobuf/struct";
|
|
@@ -53,6 +53,182 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
53
53
|
}) : target, mod));
|
|
54
54
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
55
55
|
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/nextjs/utils.ts
|
|
58
|
+
/**
|
|
59
|
+
* Get the installed Next.js version by reading package.json from node_modules.
|
|
60
|
+
*
|
|
61
|
+
* @returns The Next.js version string, or undefined if not found
|
|
62
|
+
*/
|
|
63
|
+
function getNextjsVersion() {
|
|
64
|
+
try {
|
|
65
|
+
const nextPackageJsonPath = path$1.join(process.cwd(), "node_modules", "next", "package.json");
|
|
66
|
+
if (fs$1.existsSync(nextPackageJsonPath)) return JSON.parse(fs$1.readFileSync(nextPackageJsonPath, "utf-8")).version;
|
|
67
|
+
} catch (error) {}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Parse a semantic version string into its components.
|
|
71
|
+
*
|
|
72
|
+
* @param version - The version string to parse (e.g., "15.0.0-canary.124")
|
|
73
|
+
* @returns Parsed version object with major, minor, patch, and prerelease
|
|
74
|
+
*/
|
|
75
|
+
function parseVersion(version$1) {
|
|
76
|
+
try {
|
|
77
|
+
const parsed = parse(version$1);
|
|
78
|
+
if (!parsed) return {
|
|
79
|
+
major: void 0,
|
|
80
|
+
minor: void 0,
|
|
81
|
+
patch: void 0,
|
|
82
|
+
prerelease: void 0
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
major: parsed.major,
|
|
86
|
+
minor: parsed.minor,
|
|
87
|
+
patch: parsed.patch,
|
|
88
|
+
prerelease: parsed.prerelease.length > 0 ? parsed.prerelease.join(".") : void 0
|
|
89
|
+
};
|
|
90
|
+
} catch {
|
|
91
|
+
return {
|
|
92
|
+
major: void 0,
|
|
93
|
+
minor: void 0,
|
|
94
|
+
patch: void 0,
|
|
95
|
+
prerelease: void 0
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if the Next.js version requires the instrumentationHook to be set.
|
|
101
|
+
* From Next.js 15.0.0-rc.1 onwards, the instrumentationHook is no longer needed
|
|
102
|
+
* and Next.js will warn if it's set.
|
|
103
|
+
*
|
|
104
|
+
* @param version - The Next.js version string
|
|
105
|
+
* @returns true if instrumentationHook should be set, false otherwise
|
|
106
|
+
*/
|
|
107
|
+
function shouldSetInstrumentationHook(version$1) {
|
|
108
|
+
if (!version$1) return true;
|
|
109
|
+
const { major, minor, patch, prerelease } = parseVersion(version$1);
|
|
110
|
+
if (major === void 0 || minor === void 0 || patch === void 0) return true;
|
|
111
|
+
if (major >= 16) return false;
|
|
112
|
+
if (major < 15) return true;
|
|
113
|
+
if (major === 15) {
|
|
114
|
+
if (minor > 0 || patch > 0) return false;
|
|
115
|
+
if (minor === 0 && patch === 0 && prerelease === void 0) return false;
|
|
116
|
+
if (prerelease?.startsWith("rc.")) {
|
|
117
|
+
if (parseInt(prerelease.split(".")[1] || "0", 10) >= 1) return false;
|
|
118
|
+
}
|
|
119
|
+
if (prerelease?.startsWith("canary.")) {
|
|
120
|
+
if (parseInt(prerelease.split(".")[1] || "0", 10) >= 124) return false;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Log a message if debug mode is enabled.
|
|
128
|
+
*
|
|
129
|
+
* @param debug - Whether debug mode is enabled
|
|
130
|
+
* @param message - The message to log
|
|
131
|
+
*/
|
|
132
|
+
function debugLog(debug, message) {
|
|
133
|
+
if (debug) console.log(`[Tusk Drift] ${message}`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Log a warning message if warnings are not suppressed.
|
|
137
|
+
*
|
|
138
|
+
* @param suppress - Whether to suppress the warning
|
|
139
|
+
* @param message - The warning message to log
|
|
140
|
+
*/
|
|
141
|
+
function warn(suppress, message) {
|
|
142
|
+
if (!suppress) console.warn(`[Tusk Drift] ${message}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/nextjs/withTuskDrift.ts
|
|
147
|
+
/**
|
|
148
|
+
* Wraps your Next.js configuration with Tusk Drift instrumentation setup.
|
|
149
|
+
*
|
|
150
|
+
* This function automatically configures Next.js to work with Tusk Drift by:
|
|
151
|
+
* - Enabling the Next.js instrumentation hook (for Next.js < 15.0.0-rc.1)
|
|
152
|
+
* - Configuring webpack externals to prevent bundling of core instrumentation packages
|
|
153
|
+
* - Preserving your existing Next.js configuration and webpack customizations
|
|
154
|
+
*
|
|
155
|
+
* @param nextConfig - Your existing Next.js configuration object (optional)
|
|
156
|
+
* @param options - Additional options to configure Tusk Drift's behavior (optional)
|
|
157
|
+
* @returns The wrapped Next.js configuration with Tusk Drift instrumentation enabled
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* Basic usage:
|
|
161
|
+
* ```javascript
|
|
162
|
+
* // next.config.js
|
|
163
|
+
* const { withTuskDrift } = require('@use-tusk/drift-node-sdk');
|
|
164
|
+
*
|
|
165
|
+
* module.exports = withTuskDrift({
|
|
166
|
+
* // Your Next.js config
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* With debug logging:
|
|
172
|
+
* ```javascript
|
|
173
|
+
* // next.config.js
|
|
174
|
+
* const { withTuskDrift } = require('@use-tusk/drift-node-sdk');
|
|
175
|
+
*
|
|
176
|
+
* module.exports = withTuskDrift(
|
|
177
|
+
* {
|
|
178
|
+
* // Your Next.js config
|
|
179
|
+
* },
|
|
180
|
+
* {
|
|
181
|
+
* debug: true,
|
|
182
|
+
* }
|
|
183
|
+
* );
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @remarks
|
|
187
|
+
* The following webpack externals are added for server-side builds:
|
|
188
|
+
* - `require-in-the-middle` - Required for CommonJS module interception
|
|
189
|
+
* - `jsonpath` - Required for schema manipulation
|
|
190
|
+
*/
|
|
191
|
+
function withTuskDrift(nextConfig = {}, options = {}) {
|
|
192
|
+
const config = nextConfig;
|
|
193
|
+
const debug = options.debug || false;
|
|
194
|
+
const suppressAllWarnings = options.suppressWarnings || false;
|
|
195
|
+
const nextjsVersion = getNextjsVersion();
|
|
196
|
+
if (nextjsVersion) debugLog(debug, `Detected Next.js version: ${nextjsVersion}`);
|
|
197
|
+
else warn(suppressAllWarnings || false, "Could not detect Next.js version. Some features may not work correctly. If you encounter issues, please ensure Next.js is properly installed.");
|
|
198
|
+
const needsInstrumentationHook = !options.disableInstrumentationHook && shouldSetInstrumentationHook(nextjsVersion);
|
|
199
|
+
const wrappedConfig = {
|
|
200
|
+
...config,
|
|
201
|
+
...needsInstrumentationHook ? { experimental: {
|
|
202
|
+
...config.experimental,
|
|
203
|
+
instrumentationHook: true
|
|
204
|
+
} } : { experimental: config.experimental },
|
|
205
|
+
webpack: (webpackConfig, webpackOptions) => {
|
|
206
|
+
if (webpackOptions.isServer) {
|
|
207
|
+
const originalExternals = webpackConfig.externals;
|
|
208
|
+
const coreExternals = ["require-in-the-middle", "jsonpath"];
|
|
209
|
+
if (!originalExternals) {
|
|
210
|
+
webpackConfig.externals = coreExternals;
|
|
211
|
+
debugLog(debug, "Created new externals array with core packages");
|
|
212
|
+
} else if (Array.isArray(originalExternals)) {
|
|
213
|
+
for (const pkg of coreExternals) if (!originalExternals.includes(pkg)) {
|
|
214
|
+
originalExternals.push(pkg);
|
|
215
|
+
debugLog(debug, `Added ${pkg} to webpack externals`);
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
webpackConfig.externals = [originalExternals, ...coreExternals];
|
|
219
|
+
debugLog(debug, "Wrapped existing externals with core packages");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (typeof config.webpack === "function") return config.webpack(webpackConfig, webpackOptions);
|
|
223
|
+
return webpackConfig;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
if (needsInstrumentationHook) debugLog(debug, "Set experimental.instrumentationHook to true");
|
|
227
|
+
else debugLog(debug, "Skipped setting experimental.instrumentationHook (not needed for Next.js 15.0.0-rc.1+)");
|
|
228
|
+
if (options.disableInstrumentationHook && nextjsVersion && shouldSetInstrumentationHook(nextjsVersion)) warn(suppressAllWarnings || false, "You disabled instrumentationHook, but your Next.js version requires it. Tusk Drift may not initialize properly. Please remove the disableInstrumentationHook option.");
|
|
229
|
+
return wrappedConfig;
|
|
230
|
+
}
|
|
231
|
+
|
|
56
232
|
//#endregion
|
|
57
233
|
//#region src/instrumentation/core/baseClasses/TdInstrumentationAbstract.ts
|
|
58
234
|
var TdInstrumentationAbstract = class {
|
|
@@ -76,7 +252,7 @@ var TdInstrumentationAbstract = class {
|
|
|
76
252
|
|
|
77
253
|
//#endregion
|
|
78
254
|
//#region package.json
|
|
79
|
-
var version = "0.1.
|
|
255
|
+
var version = "0.1.6";
|
|
80
256
|
|
|
81
257
|
//#endregion
|
|
82
258
|
//#region src/version.ts
|
|
@@ -1172,7 +1348,7 @@ var JsonSchemaHelper = class JsonSchemaHelper {
|
|
|
1172
1348
|
}
|
|
1173
1349
|
/**
|
|
1174
1350
|
* Generate schema from data object using standardized types
|
|
1175
|
-
*
|
|
1351
|
+
*
|
|
1176
1352
|
* Note: We properties always exists on JsonSchema because proto3 maps cannot be marked optional.
|
|
1177
1353
|
* The JSON data is a bit inefficient because of this, but the easiest way to handle this is to keep it for now.
|
|
1178
1354
|
*/
|
|
@@ -2241,6 +2417,7 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
|
|
|
2241
2417
|
};
|
|
2242
2418
|
const replayTraceId = this.replayHooks.extractTraceIdFromHeaders(req);
|
|
2243
2419
|
if (!replayTraceId) return originalHandler.call(this);
|
|
2420
|
+
logger.debug(`[HttpInstrumentation] Setting replay trace id`, replayTraceId);
|
|
2244
2421
|
const envVars = this.replayHooks.extractEnvVarsFromHeaders(req);
|
|
2245
2422
|
if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
|
|
2246
2423
|
const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
|
|
@@ -4642,7 +4819,9 @@ var TdMysql2QueryMock = class {
|
|
|
4642
4819
|
|
|
4643
4820
|
//#endregion
|
|
4644
4821
|
//#region src/instrumentation/libraries/mysql2/Instrumentation.ts
|
|
4645
|
-
const
|
|
4822
|
+
const COMPLETE_SUPPORTED_VERSIONS = ">=2.3.3 <4.0.0";
|
|
4823
|
+
const V2_3_3_TO_3_11_4 = ">=2.3.3 <3.11.5";
|
|
4824
|
+
const V3_11_5_TO_4_0 = ">=3.11.5 <4.0.0";
|
|
4646
4825
|
var Mysql2Instrumentation = class extends TdInstrumentationBase {
|
|
4647
4826
|
constructor(config = {}) {
|
|
4648
4827
|
super("mysql2", config);
|
|
@@ -4653,42 +4832,112 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
|
|
|
4653
4832
|
init() {
|
|
4654
4833
|
return [new TdInstrumentationNodeModule({
|
|
4655
4834
|
name: "mysql2",
|
|
4656
|
-
supportedVersions:
|
|
4835
|
+
supportedVersions: [COMPLETE_SUPPORTED_VERSIONS],
|
|
4657
4836
|
files: [
|
|
4658
4837
|
new TdInstrumentationNodeModuleFile({
|
|
4659
4838
|
name: "mysql2/lib/connection.js",
|
|
4660
|
-
supportedVersions:
|
|
4661
|
-
patch: (moduleExports) => this.
|
|
4839
|
+
supportedVersions: [V2_3_3_TO_3_11_4],
|
|
4840
|
+
patch: (moduleExports) => this._patchConnectionV2(moduleExports)
|
|
4841
|
+
}),
|
|
4842
|
+
new TdInstrumentationNodeModuleFile({
|
|
4843
|
+
name: "mysql2/lib/base/connection.js",
|
|
4844
|
+
supportedVersions: [V3_11_5_TO_4_0],
|
|
4845
|
+
patch: (moduleExports) => this._patchBaseConnection(moduleExports)
|
|
4846
|
+
}),
|
|
4847
|
+
new TdInstrumentationNodeModuleFile({
|
|
4848
|
+
name: "mysql2/lib/connection.js",
|
|
4849
|
+
supportedVersions: [V3_11_5_TO_4_0],
|
|
4850
|
+
patch: (moduleExports) => this._patchConnectionV3(moduleExports)
|
|
4662
4851
|
}),
|
|
4663
4852
|
new TdInstrumentationNodeModuleFile({
|
|
4664
4853
|
name: "mysql2/lib/pool.js",
|
|
4665
|
-
supportedVersions:
|
|
4666
|
-
patch: (moduleExports) => this.
|
|
4854
|
+
supportedVersions: [V2_3_3_TO_3_11_4],
|
|
4855
|
+
patch: (moduleExports) => this._patchPoolV2(moduleExports)
|
|
4856
|
+
}),
|
|
4857
|
+
new TdInstrumentationNodeModuleFile({
|
|
4858
|
+
name: "mysql2/lib/pool.js",
|
|
4859
|
+
supportedVersions: [V3_11_5_TO_4_0],
|
|
4860
|
+
patch: (moduleExports) => this._patchPoolV3(moduleExports)
|
|
4861
|
+
}),
|
|
4862
|
+
new TdInstrumentationNodeModuleFile({
|
|
4863
|
+
name: "mysql2/lib/pool_connection.js",
|
|
4864
|
+
supportedVersions: [V2_3_3_TO_3_11_4],
|
|
4865
|
+
patch: (moduleExports) => this._patchPoolConnectionV2(moduleExports)
|
|
4667
4866
|
}),
|
|
4668
4867
|
new TdInstrumentationNodeModuleFile({
|
|
4669
4868
|
name: "mysql2/lib/pool_connection.js",
|
|
4670
|
-
supportedVersions:
|
|
4671
|
-
patch: (moduleExports) => this.
|
|
4869
|
+
supportedVersions: [V3_11_5_TO_4_0],
|
|
4870
|
+
patch: (moduleExports) => this._patchPoolConnectionV3(moduleExports)
|
|
4672
4871
|
}),
|
|
4673
4872
|
new TdInstrumentationNodeModuleFile({
|
|
4674
4873
|
name: "mysql2/lib/create_connection.js",
|
|
4675
|
-
supportedVersions:
|
|
4874
|
+
supportedVersions: [COMPLETE_SUPPORTED_VERSIONS],
|
|
4676
4875
|
patch: (moduleExports) => this._patchCreateConnectionFile(moduleExports)
|
|
4677
4876
|
}),
|
|
4678
4877
|
new TdInstrumentationNodeModuleFile({
|
|
4679
4878
|
name: "mysql2/lib/create_pool.js",
|
|
4680
|
-
supportedVersions:
|
|
4879
|
+
supportedVersions: [COMPLETE_SUPPORTED_VERSIONS],
|
|
4681
4880
|
patch: (moduleExports) => this._patchCreatePoolFile(moduleExports)
|
|
4682
4881
|
})
|
|
4683
4882
|
]
|
|
4684
4883
|
})];
|
|
4685
4884
|
}
|
|
4686
|
-
|
|
4687
|
-
logger.debug(`[Mysql2Instrumentation] Patching
|
|
4885
|
+
_patchBaseConnection(BaseConnectionClass) {
|
|
4886
|
+
logger.debug(`[Mysql2Instrumentation] Patching BaseConnection class`);
|
|
4887
|
+
if (this.isModulePatched(BaseConnectionClass)) {
|
|
4888
|
+
logger.debug(`[Mysql2Instrumentation] BaseConnection class already patched, skipping`);
|
|
4889
|
+
return BaseConnectionClass;
|
|
4890
|
+
}
|
|
4891
|
+
if (BaseConnectionClass.prototype && BaseConnectionClass.prototype.query) {
|
|
4892
|
+
if (!isWrapped$1(BaseConnectionClass.prototype.query)) {
|
|
4893
|
+
this._wrap(BaseConnectionClass.prototype, "query", this._getQueryPatchFn("connection"));
|
|
4894
|
+
logger.debug(`[Mysql2Instrumentation] Wrapped BaseConnection.prototype.query`);
|
|
4895
|
+
}
|
|
4896
|
+
}
|
|
4897
|
+
if (BaseConnectionClass.prototype && BaseConnectionClass.prototype.execute) {
|
|
4898
|
+
if (!isWrapped$1(BaseConnectionClass.prototype.execute)) {
|
|
4899
|
+
this._wrap(BaseConnectionClass.prototype, "execute", this._getExecutePatchFn("connection"));
|
|
4900
|
+
logger.debug(`[Mysql2Instrumentation] Wrapped BaseConnection.prototype.execute`);
|
|
4901
|
+
}
|
|
4902
|
+
}
|
|
4903
|
+
if (BaseConnectionClass.prototype && BaseConnectionClass.prototype.connect) {
|
|
4904
|
+
if (!isWrapped$1(BaseConnectionClass.prototype.connect)) {
|
|
4905
|
+
this._wrap(BaseConnectionClass.prototype, "connect", this._getConnectPatchFn("connection"));
|
|
4906
|
+
logger.debug(`[Mysql2Instrumentation] Wrapped BaseConnection.prototype.connect`);
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
if (BaseConnectionClass.prototype && BaseConnectionClass.prototype.ping) {
|
|
4910
|
+
if (!isWrapped$1(BaseConnectionClass.prototype.ping)) {
|
|
4911
|
+
this._wrap(BaseConnectionClass.prototype, "ping", this._getPingPatchFn("connection"));
|
|
4912
|
+
logger.debug(`[Mysql2Instrumentation] Wrapped BaseConnection.prototype.ping`);
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
if (BaseConnectionClass.prototype && BaseConnectionClass.prototype.end) {
|
|
4916
|
+
if (!isWrapped$1(BaseConnectionClass.prototype.end)) {
|
|
4917
|
+
this._wrap(BaseConnectionClass.prototype, "end", this._getEndPatchFn("connection"));
|
|
4918
|
+
logger.debug(`[Mysql2Instrumentation] Wrapped BaseConnection.prototype.end`);
|
|
4919
|
+
}
|
|
4920
|
+
}
|
|
4921
|
+
this.markModuleAsPatched(BaseConnectionClass);
|
|
4922
|
+
logger.debug(`[Mysql2Instrumentation] BaseConnection class patching complete`);
|
|
4923
|
+
return BaseConnectionClass;
|
|
4924
|
+
}
|
|
4925
|
+
_patchConnectionV2(ConnectionClass) {
|
|
4926
|
+
logger.debug(`[Mysql2Instrumentation] Patching Connection class (v2)`);
|
|
4688
4927
|
if (this.isModulePatched(ConnectionClass)) {
|
|
4689
4928
|
logger.debug(`[Mysql2Instrumentation] Connection class already patched, skipping`);
|
|
4690
4929
|
return ConnectionClass;
|
|
4691
4930
|
}
|
|
4931
|
+
this._patchConnectionPrototypes(ConnectionClass);
|
|
4932
|
+
this.markModuleAsPatched(ConnectionClass);
|
|
4933
|
+
logger.debug(`[Mysql2Instrumentation] Connection class (v2) patching complete`);
|
|
4934
|
+
return ConnectionClass;
|
|
4935
|
+
}
|
|
4936
|
+
_patchConnectionV3(ConnectionClass) {
|
|
4937
|
+
logger.debug(`[Mysql2Instrumentation] Connection class (v3) - skipping (base patched)`);
|
|
4938
|
+
return ConnectionClass;
|
|
4939
|
+
}
|
|
4940
|
+
_patchConnectionPrototypes(ConnectionClass) {
|
|
4692
4941
|
if (ConnectionClass.prototype && ConnectionClass.prototype.query) {
|
|
4693
4942
|
if (!isWrapped$1(ConnectionClass.prototype.query)) {
|
|
4694
4943
|
this._wrap(ConnectionClass.prototype, "query", this._getQueryPatchFn("connection"));
|
|
@@ -4719,16 +4968,30 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
|
|
|
4719
4968
|
logger.debug(`[Mysql2Instrumentation] Wrapped Connection.prototype.end`);
|
|
4720
4969
|
}
|
|
4721
4970
|
}
|
|
4722
|
-
this.markModuleAsPatched(ConnectionClass);
|
|
4723
|
-
logger.debug(`[Mysql2Instrumentation] Connection class patching complete`);
|
|
4724
|
-
return ConnectionClass;
|
|
4725
4971
|
}
|
|
4726
|
-
|
|
4727
|
-
logger.debug(`[Mysql2Instrumentation] Patching Pool class`);
|
|
4972
|
+
_patchPoolV2(PoolClass) {
|
|
4973
|
+
logger.debug(`[Mysql2Instrumentation] Patching Pool class (v2)`);
|
|
4728
4974
|
if (this.isModulePatched(PoolClass)) {
|
|
4729
4975
|
logger.debug(`[Mysql2Instrumentation] Pool class already patched, skipping`);
|
|
4730
4976
|
return PoolClass;
|
|
4731
4977
|
}
|
|
4978
|
+
this._patchPoolPrototypes(PoolClass);
|
|
4979
|
+
this.markModuleAsPatched(PoolClass);
|
|
4980
|
+
logger.debug(`[Mysql2Instrumentation] Pool class (v2) patching complete`);
|
|
4981
|
+
return PoolClass;
|
|
4982
|
+
}
|
|
4983
|
+
_patchPoolV3(PoolClass) {
|
|
4984
|
+
logger.debug(`[Mysql2Instrumentation] Patching Pool class (v3)`);
|
|
4985
|
+
if (this.isModulePatched(PoolClass)) {
|
|
4986
|
+
logger.debug(`[Mysql2Instrumentation] Pool class already patched, skipping`);
|
|
4987
|
+
return PoolClass;
|
|
4988
|
+
}
|
|
4989
|
+
this._patchPoolPrototypes(PoolClass);
|
|
4990
|
+
this.markModuleAsPatched(PoolClass);
|
|
4991
|
+
logger.debug(`[Mysql2Instrumentation] Pool class (v3) patching complete`);
|
|
4992
|
+
return PoolClass;
|
|
4993
|
+
}
|
|
4994
|
+
_patchPoolPrototypes(PoolClass) {
|
|
4732
4995
|
if (PoolClass.prototype && PoolClass.prototype.query) {
|
|
4733
4996
|
if (!isWrapped$1(PoolClass.prototype.query)) {
|
|
4734
4997
|
this._wrap(PoolClass.prototype, "query", this._getQueryPatchFn("pool"));
|
|
@@ -4747,30 +5010,19 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
|
|
|
4747
5010
|
logger.debug(`[Mysql2Instrumentation] Wrapped Pool.prototype.getConnection`);
|
|
4748
5011
|
}
|
|
4749
5012
|
}
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
_patchPoolConnection(PoolConnectionClass) {
|
|
4755
|
-
logger.debug(`[Mysql2Instrumentation] Patching PoolConnection class`);
|
|
4756
|
-
if (this.isModulePatched(PoolConnectionClass)) {
|
|
4757
|
-
logger.debug(`[Mysql2Instrumentation] PoolConnection class already patched, skipping`);
|
|
4758
|
-
return PoolConnectionClass;
|
|
4759
|
-
}
|
|
4760
|
-
if (PoolConnectionClass.prototype && PoolConnectionClass.prototype.query) {
|
|
4761
|
-
if (!isWrapped$1(PoolConnectionClass.prototype.query)) {
|
|
4762
|
-
this._wrap(PoolConnectionClass.prototype, "query", this._getQueryPatchFn("poolConnection"));
|
|
4763
|
-
logger.debug(`[Mysql2Instrumentation] Wrapped PoolConnection.prototype.query`);
|
|
4764
|
-
}
|
|
4765
|
-
}
|
|
4766
|
-
if (PoolConnectionClass.prototype && PoolConnectionClass.prototype.execute) {
|
|
4767
|
-
if (!isWrapped$1(PoolConnectionClass.prototype.execute)) {
|
|
4768
|
-
this._wrap(PoolConnectionClass.prototype, "execute", this._getExecutePatchFn("poolConnection"));
|
|
4769
|
-
logger.debug(`[Mysql2Instrumentation] Wrapped PoolConnection.prototype.execute`);
|
|
5013
|
+
if (PoolClass.prototype && PoolClass.prototype.end) {
|
|
5014
|
+
if (!isWrapped$1(PoolClass.prototype.end)) {
|
|
5015
|
+
this._wrap(PoolClass.prototype, "end", this._getEndPatchFn("pool"));
|
|
5016
|
+
logger.debug(`[Mysql2Instrumentation] Wrapped Pool.prototype.end`);
|
|
4770
5017
|
}
|
|
4771
5018
|
}
|
|
4772
|
-
|
|
4773
|
-
|
|
5019
|
+
}
|
|
5020
|
+
_patchPoolConnectionV2(PoolConnectionClass) {
|
|
5021
|
+
logger.debug(`[Mysql2Instrumentation] PoolConnection class (v2) - skipping (inherits from Connection)`);
|
|
5022
|
+
return PoolConnectionClass;
|
|
5023
|
+
}
|
|
5024
|
+
_patchPoolConnectionV3(PoolConnectionClass) {
|
|
5025
|
+
logger.debug(`[Mysql2Instrumentation] PoolConnection class (v3) - skipping (inherits from Connection)`);
|
|
4774
5026
|
return PoolConnectionClass;
|
|
4775
5027
|
}
|
|
4776
5028
|
_getQueryPatchFn(clientType) {
|
|
@@ -6602,7 +6854,7 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
|
|
|
6602
6854
|
}
|
|
6603
6855
|
const actualExports = moduleExports[Symbol.toStringTag] === "Module" ? moduleExports.default : moduleExports;
|
|
6604
6856
|
if (!actualExports || !actualExports.prototype) {
|
|
6605
|
-
logger.
|
|
6857
|
+
logger.debug(`[IORedisInstrumentation] Invalid Pipeline module exports, cannot patch`);
|
|
6606
6858
|
return moduleExports;
|
|
6607
6859
|
}
|
|
6608
6860
|
if (actualExports.prototype.exec) {
|
|
@@ -7521,6 +7773,372 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
|
|
|
7521
7773
|
};
|
|
7522
7774
|
GrpcInstrumentation.metadataStore = /* @__PURE__ */ new Map();
|
|
7523
7775
|
|
|
7776
|
+
//#endregion
|
|
7777
|
+
//#region src/instrumentation/libraries/nextjs/Instrumentation.ts
|
|
7778
|
+
var NextjsInstrumentation = class extends TdInstrumentationBase {
|
|
7779
|
+
constructor(config = {}) {
|
|
7780
|
+
super("nextjs", config);
|
|
7781
|
+
this.INSTRUMENTATION_NAME = "NextjsInstrumentation";
|
|
7782
|
+
this.mode = config.mode || TuskDriftMode.DISABLED;
|
|
7783
|
+
this.replayHooks = new HttpReplayHooks();
|
|
7784
|
+
this.tuskDrift = TuskDriftCore.getInstance();
|
|
7785
|
+
logger.debug(`[NextjsInstrumentation] Constructor called with mode: ${this.mode}`);
|
|
7786
|
+
this._patchLoadedModules();
|
|
7787
|
+
}
|
|
7788
|
+
init() {
|
|
7789
|
+
logger.debug(`[NextjsInstrumentation] Initializing in ${this.mode} mode`);
|
|
7790
|
+
return [new TdInstrumentationNodeModule({
|
|
7791
|
+
name: "next/dist/server/base-server",
|
|
7792
|
+
supportedVersions: ["*"],
|
|
7793
|
+
patch: (moduleExports) => {
|
|
7794
|
+
return this._patchBaseServer(moduleExports);
|
|
7795
|
+
}
|
|
7796
|
+
})];
|
|
7797
|
+
}
|
|
7798
|
+
_patchLoadedModules() {
|
|
7799
|
+
logger.debug(`[NextjsInstrumentation] Checking for already-loaded Next.js modules`);
|
|
7800
|
+
const pattern = "/next/dist/server/base-server.js";
|
|
7801
|
+
let patchedCount = 0;
|
|
7802
|
+
for (const [modulePath, cached] of Object.entries(__require.cache)) if (modulePath.includes(pattern) && cached && cached.exports) {
|
|
7803
|
+
logger.debug(`[NextjsInstrumentation] Found ${pattern} at ${modulePath}, patching now`);
|
|
7804
|
+
this._patchBaseServer(cached.exports);
|
|
7805
|
+
patchedCount++;
|
|
7806
|
+
break;
|
|
7807
|
+
}
|
|
7808
|
+
if (patchedCount === 0) {
|
|
7809
|
+
logger.debug(`[NextjsInstrumentation] No Next.js server modules found in require.cache yet`);
|
|
7810
|
+
logger.debug(`[NextjsInstrumentation] Will wait for require-in-the-middle hooks to catch them`);
|
|
7811
|
+
} else logger.debug(`[NextjsInstrumentation] Patched ${patchedCount} already-loaded Next.js modules`);
|
|
7812
|
+
}
|
|
7813
|
+
_patchBaseServer(baseServerModule) {
|
|
7814
|
+
logger.debug(`[NextjsInstrumentation] Patching Next.js BaseServer in ${this.mode} mode`);
|
|
7815
|
+
const BaseServer = baseServerModule.default || baseServerModule.BaseServer || baseServerModule;
|
|
7816
|
+
if (BaseServer && BaseServer.prototype) {
|
|
7817
|
+
if (this.isModulePatched(BaseServer.prototype)) {
|
|
7818
|
+
logger.debug(`[NextjsInstrumentation] BaseServer.prototype already patched, skipping`);
|
|
7819
|
+
return baseServerModule;
|
|
7820
|
+
}
|
|
7821
|
+
if (BaseServer.prototype.handleRequest) {
|
|
7822
|
+
this._wrap(BaseServer.prototype, "handleRequest", this._getHandleRequestPatchFn());
|
|
7823
|
+
logger.debug(`[NextjsInstrumentation] Wrapped BaseServer.prototype.handleRequest`);
|
|
7824
|
+
this.markModuleAsPatched(BaseServer.prototype);
|
|
7825
|
+
} else logger.warn(`[NextjsInstrumentation] Could not find BaseServer.prototype.handleRequest`);
|
|
7826
|
+
} else logger.warn(`[NextjsInstrumentation] Could not find BaseServer class`);
|
|
7827
|
+
logger.debug(`[NextjsInstrumentation] Next.js BaseServer patching complete`);
|
|
7828
|
+
return baseServerModule;
|
|
7829
|
+
}
|
|
7830
|
+
_getHandleRequestPatchFn() {
|
|
7831
|
+
const self = this;
|
|
7832
|
+
return (originalHandleRequest) => {
|
|
7833
|
+
return async function(req, res, parsedUrl) {
|
|
7834
|
+
const method = req.method || "GET";
|
|
7835
|
+
const url = req.url || "/";
|
|
7836
|
+
logger.debug(`[NextjsInstrumentation] Intercepted Next.js request: ${method} ${url}`);
|
|
7837
|
+
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
|
|
7838
|
+
const inputValue = {
|
|
7839
|
+
method,
|
|
7840
|
+
url,
|
|
7841
|
+
target: url,
|
|
7842
|
+
headers: self._normalizeHeaders(req.headers || {})
|
|
7843
|
+
};
|
|
7844
|
+
const replayTraceId = self.replayHooks.extractTraceIdFromHeaders(req);
|
|
7845
|
+
if (!replayTraceId) {
|
|
7846
|
+
logger.debug(`[NextjsInstrumentation] No trace ID found, calling original handler`);
|
|
7847
|
+
return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
7848
|
+
}
|
|
7849
|
+
const envVars = self.replayHooks.extractEnvVarsFromHeaders(req);
|
|
7850
|
+
if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
|
|
7851
|
+
const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
|
|
7852
|
+
if (!ctxWithReplayTraceId) throw new Error("Error setting current replay trace id");
|
|
7853
|
+
return context.with(ctxWithReplayTraceId, () => {
|
|
7854
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalHandleRequest.call(this, req, res, parsedUrl), {
|
|
7855
|
+
name: url,
|
|
7856
|
+
kind: SpanKind.SERVER,
|
|
7857
|
+
packageName: "nextjs",
|
|
7858
|
+
submodule: method,
|
|
7859
|
+
packageType: PackageType.HTTP,
|
|
7860
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
7861
|
+
inputValue,
|
|
7862
|
+
inputSchemaMerges: { headers: { matchImportance: 0 } },
|
|
7863
|
+
isPreAppStart: false
|
|
7864
|
+
}, (spanInfo) => {
|
|
7865
|
+
return self._handleNextjsRequestInSpan({
|
|
7866
|
+
req,
|
|
7867
|
+
res,
|
|
7868
|
+
parsedUrl,
|
|
7869
|
+
originalHandleRequest,
|
|
7870
|
+
spanInfo,
|
|
7871
|
+
inputValue,
|
|
7872
|
+
thisContext: this
|
|
7873
|
+
});
|
|
7874
|
+
});
|
|
7875
|
+
});
|
|
7876
|
+
} });
|
|
7877
|
+
else if (self.mode === TuskDriftMode.RECORD) {
|
|
7878
|
+
if (method.toUpperCase() === "OPTIONS" || !!req.headers["access-control-request-method"]) return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
7879
|
+
if (!shouldSample({
|
|
7880
|
+
samplingRate: self.tuskDrift.getSamplingRate(),
|
|
7881
|
+
isAppReady: self.tuskDrift.isAppReady()
|
|
7882
|
+
})) {
|
|
7883
|
+
logger.debug(`[NextjsInstrumentation] Skipping server span due to sampling rate: ${url}`);
|
|
7884
|
+
return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
7885
|
+
}
|
|
7886
|
+
logger.debug(`[NextjsInstrumentation] Creating server span for ${method} ${url}`);
|
|
7887
|
+
return handleRecordMode({
|
|
7888
|
+
originalFunctionCall: () => originalHandleRequest.call(this, req, res, parsedUrl),
|
|
7889
|
+
recordModeHandler: ({ isPreAppStart }) => {
|
|
7890
|
+
const inputValue = {
|
|
7891
|
+
method,
|
|
7892
|
+
url,
|
|
7893
|
+
target: url,
|
|
7894
|
+
headers: self._normalizeHeaders(req.headers || {})
|
|
7895
|
+
};
|
|
7896
|
+
return SpanUtils.createAndExecuteSpan(self.mode, () => originalHandleRequest.call(this, req, res, parsedUrl), {
|
|
7897
|
+
name: url,
|
|
7898
|
+
kind: SpanKind.SERVER,
|
|
7899
|
+
packageName: "nextjs",
|
|
7900
|
+
packageType: PackageType.HTTP,
|
|
7901
|
+
submodule: method,
|
|
7902
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
7903
|
+
inputValue,
|
|
7904
|
+
inputSchemaMerges: { headers: { matchImportance: 0 } },
|
|
7905
|
+
isPreAppStart
|
|
7906
|
+
}, (spanInfo) => {
|
|
7907
|
+
return self._handleNextjsRequestInSpan({
|
|
7908
|
+
req,
|
|
7909
|
+
res,
|
|
7910
|
+
parsedUrl,
|
|
7911
|
+
originalHandleRequest,
|
|
7912
|
+
spanInfo,
|
|
7913
|
+
inputValue,
|
|
7914
|
+
thisContext: this
|
|
7915
|
+
});
|
|
7916
|
+
});
|
|
7917
|
+
},
|
|
7918
|
+
spanKind: SpanKind.SERVER
|
|
7919
|
+
});
|
|
7920
|
+
} else return originalHandleRequest.call(this, req, res, parsedUrl);
|
|
7921
|
+
};
|
|
7922
|
+
};
|
|
7923
|
+
}
|
|
7924
|
+
async _handleNextjsRequestInSpan({ req, res, parsedUrl, originalHandleRequest, spanInfo, inputValue, thisContext }) {
|
|
7925
|
+
const self = this;
|
|
7926
|
+
context.bind(spanInfo.context, req);
|
|
7927
|
+
context.bind(spanInfo.context, res);
|
|
7928
|
+
let completeInputValue = inputValue;
|
|
7929
|
+
this._captureRequestBody(req, spanInfo, inputValue, (updatedInputValue) => {
|
|
7930
|
+
completeInputValue = updatedInputValue;
|
|
7931
|
+
});
|
|
7932
|
+
let capturedStatusCode;
|
|
7933
|
+
let capturedStatusMessage;
|
|
7934
|
+
let capturedHeaders = {};
|
|
7935
|
+
const responseChunks = [];
|
|
7936
|
+
const actualRes = res.originalResponse || res;
|
|
7937
|
+
const originalWriteHead = actualRes.writeHead?.bind(actualRes);
|
|
7938
|
+
if (originalWriteHead) actualRes.writeHead = function(statusCode, statusMessage, headers) {
|
|
7939
|
+
capturedStatusCode = statusCode;
|
|
7940
|
+
if (typeof statusMessage === "object") capturedHeaders = self._normalizeHeaders(statusMessage);
|
|
7941
|
+
else {
|
|
7942
|
+
capturedStatusMessage = statusMessage;
|
|
7943
|
+
if (headers) capturedHeaders = self._normalizeHeaders(headers);
|
|
7944
|
+
}
|
|
7945
|
+
return originalWriteHead.call(this, statusCode, statusMessage, headers);
|
|
7946
|
+
};
|
|
7947
|
+
const originalSetHeader = actualRes.setHeader?.bind(actualRes);
|
|
7948
|
+
if (originalSetHeader) actualRes.setHeader = function(name, value) {
|
|
7949
|
+
capturedHeaders[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
|
|
7950
|
+
return originalSetHeader.call(this, name, value);
|
|
7951
|
+
};
|
|
7952
|
+
const originalWrite = actualRes.write?.bind(actualRes);
|
|
7953
|
+
if (originalWrite) actualRes.write = function(chunk, encoding, callback) {
|
|
7954
|
+
if (chunk) responseChunks.push(chunk);
|
|
7955
|
+
return originalWrite.call(this, chunk, encoding, callback);
|
|
7956
|
+
};
|
|
7957
|
+
const originalEnd = actualRes.end?.bind(actualRes);
|
|
7958
|
+
if (originalEnd) actualRes.end = function(chunk, encoding, callback) {
|
|
7959
|
+
if (chunk) responseChunks.push(chunk);
|
|
7960
|
+
return originalEnd.call(this, chunk, encoding, callback);
|
|
7961
|
+
};
|
|
7962
|
+
try {
|
|
7963
|
+
await originalHandleRequest.call(thisContext, req, res, parsedUrl);
|
|
7964
|
+
if (!capturedStatusCode) {
|
|
7965
|
+
capturedStatusCode = res.statusCode;
|
|
7966
|
+
capturedStatusMessage = res.statusMessage;
|
|
7967
|
+
}
|
|
7968
|
+
if (Object.keys(capturedHeaders).length === 0 && res.getHeaders) {
|
|
7969
|
+
const rawHeaders = res.getHeaders();
|
|
7970
|
+
capturedHeaders = self._normalizeHeaders(rawHeaders);
|
|
7971
|
+
}
|
|
7972
|
+
logger.debug(`[NextjsInstrumentation] Next.js request completed: ${capturedStatusCode} (${SpanUtils.getTraceInfo()})`);
|
|
7973
|
+
const outputValue = {
|
|
7974
|
+
statusCode: capturedStatusCode,
|
|
7975
|
+
statusMessage: capturedStatusMessage,
|
|
7976
|
+
headers: capturedHeaders
|
|
7977
|
+
};
|
|
7978
|
+
if (responseChunks.length > 0) try {
|
|
7979
|
+
const responseBuffer = combineChunks(responseChunks);
|
|
7980
|
+
const contentEncoding = outputValue.headers?.["content-encoding"];
|
|
7981
|
+
outputValue.body = await httpBodyEncoder({
|
|
7982
|
+
bodyBuffer: responseBuffer,
|
|
7983
|
+
contentEncoding
|
|
7984
|
+
});
|
|
7985
|
+
outputValue.bodySize = responseBuffer.length;
|
|
7986
|
+
} catch (error) {
|
|
7987
|
+
logger.error(`[NextjsInstrumentation] Error processing response body:`, error);
|
|
7988
|
+
outputValue.bodyProcessingError = error instanceof Error ? error.message : String(error);
|
|
7989
|
+
}
|
|
7990
|
+
SpanUtils.addSpanAttributes(spanInfo.span, {
|
|
7991
|
+
inputValue: completeInputValue,
|
|
7992
|
+
outputValue,
|
|
7993
|
+
outputSchemaMerges: {
|
|
7994
|
+
body: {
|
|
7995
|
+
encoding: EncodingType.BASE64,
|
|
7996
|
+
decodedType: getDecodedType(outputValue.headers?.["content-type"] || "")
|
|
7997
|
+
},
|
|
7998
|
+
headers: { matchImportance: 0 }
|
|
7999
|
+
},
|
|
8000
|
+
metadata: { ENV_VARS: EnvVarTracker.getEnvVars(spanInfo.traceId) }
|
|
8001
|
+
});
|
|
8002
|
+
EnvVarTracker.clearEnvVars(spanInfo.traceId);
|
|
8003
|
+
const status = (capturedStatusCode || 200) >= 400 ? {
|
|
8004
|
+
code: SpanStatusCode.ERROR,
|
|
8005
|
+
message: `HTTP ${capturedStatusCode}`
|
|
8006
|
+
} : { code: SpanStatusCode.OK };
|
|
8007
|
+
SpanUtils.setStatus(spanInfo.span, status);
|
|
8008
|
+
SpanUtils.endSpan(spanInfo.span);
|
|
8009
|
+
if (self.mode === TuskDriftMode.REPLAY) try {
|
|
8010
|
+
const now = OriginalGlobalUtils.getOriginalDate();
|
|
8011
|
+
const replayTraceId = SpanUtils.getCurrentReplayTraceId() || spanInfo.traceId;
|
|
8012
|
+
const { schema: inputSchema, decodedValueHash: inputValueHash } = JsonSchemaHelper.generateSchemaAndHash(completeInputValue, {
|
|
8013
|
+
body: {
|
|
8014
|
+
encoding: EncodingType.BASE64,
|
|
8015
|
+
decodedType: getDecodedType(completeInputValue.headers && completeInputValue.headers["content-type"] || "")
|
|
8016
|
+
},
|
|
8017
|
+
headers: { matchImportance: 0 }
|
|
8018
|
+
});
|
|
8019
|
+
const { schema: outputSchema, decodedValueHash: outputValueHash } = JsonSchemaHelper.generateSchemaAndHash(outputValue, {
|
|
8020
|
+
body: {
|
|
8021
|
+
encoding: EncodingType.BASE64,
|
|
8022
|
+
decodedType: getDecodedType(outputValue.headers["content-type"] || "")
|
|
8023
|
+
},
|
|
8024
|
+
headers: { matchImportance: 0 }
|
|
8025
|
+
});
|
|
8026
|
+
const cleanSpan = {
|
|
8027
|
+
traceId: replayTraceId,
|
|
8028
|
+
spanId: spanInfo.spanId,
|
|
8029
|
+
parentSpanId: "",
|
|
8030
|
+
name: completeInputValue.url,
|
|
8031
|
+
packageName: "nextjs",
|
|
8032
|
+
instrumentationName: self.INSTRUMENTATION_NAME,
|
|
8033
|
+
submoduleName: completeInputValue.method,
|
|
8034
|
+
inputValue: completeInputValue,
|
|
8035
|
+
outputValue,
|
|
8036
|
+
inputSchema,
|
|
8037
|
+
outputSchema,
|
|
8038
|
+
inputSchemaHash: JsonSchemaHelper.generateDeterministicHash(inputSchema),
|
|
8039
|
+
outputSchemaHash: JsonSchemaHelper.generateDeterministicHash(outputSchema),
|
|
8040
|
+
inputValueHash,
|
|
8041
|
+
outputValueHash,
|
|
8042
|
+
kind: SpanKind.SERVER,
|
|
8043
|
+
packageType: PackageType.HTTP,
|
|
8044
|
+
status: {
|
|
8045
|
+
code: (capturedStatusCode || 200) >= 400 ? StatusCode.ERROR : StatusCode.OK,
|
|
8046
|
+
message: (capturedStatusCode || 200) >= 400 ? `HTTP ${capturedStatusCode}` : ""
|
|
8047
|
+
},
|
|
8048
|
+
timestamp: {
|
|
8049
|
+
seconds: Math.floor(now.getTime() / 1e3),
|
|
8050
|
+
nanos: now.getTime() % 1e3 * 1e6
|
|
8051
|
+
},
|
|
8052
|
+
duration: {
|
|
8053
|
+
seconds: 0,
|
|
8054
|
+
nanos: 0
|
|
8055
|
+
},
|
|
8056
|
+
isRootSpan: true,
|
|
8057
|
+
isPreAppStart: false,
|
|
8058
|
+
metadata: void 0
|
|
8059
|
+
};
|
|
8060
|
+
await self.tuskDrift.sendInboundSpanForReplay(cleanSpan);
|
|
8061
|
+
} catch (e) {
|
|
8062
|
+
logger.error("[NextjsInstrumentation] Failed to build/send inbound replay span:", e);
|
|
8063
|
+
}
|
|
8064
|
+
} catch (error) {
|
|
8065
|
+
logger.error(`[NextjsInstrumentation] Error in Next.js request: ${error instanceof Error ? error.message : String(error)}`);
|
|
8066
|
+
SpanUtils.endSpan(spanInfo.span, {
|
|
8067
|
+
code: SpanStatusCode.ERROR,
|
|
8068
|
+
message: error instanceof Error ? error.message : String(error)
|
|
8069
|
+
});
|
|
8070
|
+
throw error;
|
|
8071
|
+
}
|
|
8072
|
+
}
|
|
8073
|
+
/**
|
|
8074
|
+
* Captures the request body from an IncomingMessage stream by patching req.read() and listening for data events.
|
|
8075
|
+
* Similar to HTTP instrumentation's request body capture, but adapted for Next.js.
|
|
8076
|
+
*/
|
|
8077
|
+
_captureRequestBody(req, spanInfo, inputValue, onBodyCaptured) {
|
|
8078
|
+
const actualReq = req.originalRequest || req._req || req;
|
|
8079
|
+
const requestBodyChunks = [];
|
|
8080
|
+
let streamConsumptionMode = "NOT_CONSUMING";
|
|
8081
|
+
const originalRead = actualReq.read?.bind(actualReq);
|
|
8082
|
+
if (originalRead) actualReq.read = function read(size) {
|
|
8083
|
+
const chunk = originalRead(size);
|
|
8084
|
+
if (chunk && (streamConsumptionMode === "READ" || streamConsumptionMode === "NOT_CONSUMING")) {
|
|
8085
|
+
streamConsumptionMode = "READ";
|
|
8086
|
+
requestBodyChunks.push(Buffer.from(chunk));
|
|
8087
|
+
}
|
|
8088
|
+
return chunk;
|
|
8089
|
+
};
|
|
8090
|
+
if (typeof actualReq.once !== "function" || typeof actualReq.addListener !== "function") {
|
|
8091
|
+
logger.debug(`[NextjsInstrumentation] Request object doesn't have event emitter methods, skipping body capture`);
|
|
8092
|
+
return;
|
|
8093
|
+
}
|
|
8094
|
+
actualReq.once("resume", () => {
|
|
8095
|
+
actualReq.addListener("data", (chunk) => {
|
|
8096
|
+
if (chunk && (streamConsumptionMode === "PIPE" || streamConsumptionMode === "NOT_CONSUMING")) {
|
|
8097
|
+
streamConsumptionMode = "PIPE";
|
|
8098
|
+
requestBodyChunks.push(Buffer.from(chunk));
|
|
8099
|
+
}
|
|
8100
|
+
});
|
|
8101
|
+
});
|
|
8102
|
+
actualReq.addListener("end", async (chunk) => {
|
|
8103
|
+
if (chunk) requestBodyChunks.push(Buffer.from(chunk));
|
|
8104
|
+
if (requestBodyChunks.length > 0) try {
|
|
8105
|
+
const bodyBuffer = Buffer.concat(requestBodyChunks);
|
|
8106
|
+
const encodedBody = await httpBodyEncoder({
|
|
8107
|
+
bodyBuffer,
|
|
8108
|
+
contentEncoding: actualReq.headers["content-encoding"]
|
|
8109
|
+
});
|
|
8110
|
+
const updatedInputValue = {
|
|
8111
|
+
...inputValue,
|
|
8112
|
+
body: encodedBody,
|
|
8113
|
+
bodySize: bodyBuffer.length
|
|
8114
|
+
};
|
|
8115
|
+
if (onBodyCaptured) onBodyCaptured(updatedInputValue);
|
|
8116
|
+
SpanUtils.addSpanAttributes(spanInfo.span, {
|
|
8117
|
+
inputValue: updatedInputValue,
|
|
8118
|
+
inputSchemaMerges: {
|
|
8119
|
+
body: {
|
|
8120
|
+
encoding: EncodingType.BASE64,
|
|
8121
|
+
decodedType: getDecodedType(actualReq.headers["content-type"] || "")
|
|
8122
|
+
},
|
|
8123
|
+
headers: { matchImportance: 0 }
|
|
8124
|
+
}
|
|
8125
|
+
});
|
|
8126
|
+
logger.debug(`[NextjsInstrumentation] Captured request body for ${actualReq.method} ${actualReq.url}: ${bodyBuffer.length} bytes`);
|
|
8127
|
+
} catch (error) {
|
|
8128
|
+
logger.error(`[NextjsInstrumentation] Error processing request body:`, error);
|
|
8129
|
+
}
|
|
8130
|
+
});
|
|
8131
|
+
}
|
|
8132
|
+
_normalizeHeaders(headers) {
|
|
8133
|
+
const normalized = {};
|
|
8134
|
+
for (const [key, value] of Object.entries(headers)) if (value !== void 0) normalized[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
8135
|
+
return normalized;
|
|
8136
|
+
}
|
|
8137
|
+
_wrap(target, propertyName, wrapper) {
|
|
8138
|
+
wrap(target, propertyName, wrapper);
|
|
8139
|
+
}
|
|
8140
|
+
};
|
|
8141
|
+
|
|
7524
8142
|
//#endregion
|
|
7525
8143
|
//#region node_modules/@opentelemetry/core/build/src/trace/suppress-tracing.js
|
|
7526
8144
|
var require_suppress_tracing = /* @__PURE__ */ __commonJS({ "node_modules/@opentelemetry/core/build/src/trace/suppress-tracing.js": ((exports) => {
|
|
@@ -9957,7 +10575,18 @@ var TdSpanExporter = class {
|
|
|
9957
10575
|
*/
|
|
9958
10576
|
export(spans, resultCallback) {
|
|
9959
10577
|
logger.debug(`TdSpanExporter.export() called with ${spans.length} span(s)`);
|
|
9960
|
-
const
|
|
10578
|
+
const filteredSpans = spans.filter((span) => {
|
|
10579
|
+
if (span.instrumentationLibrary?.name === "next.js") return false;
|
|
10580
|
+
return true;
|
|
10581
|
+
});
|
|
10582
|
+
logger.debug(`After filtering: ${filteredSpans.length} span(s) remaining`);
|
|
10583
|
+
let cleanSpans;
|
|
10584
|
+
try {
|
|
10585
|
+
cleanSpans = filteredSpans.map((span) => SpanTransformer.transformSpanToCleanJSON(span));
|
|
10586
|
+
} catch (error) {
|
|
10587
|
+
logger.error("Error transforming spans to CleanSpanData", error);
|
|
10588
|
+
throw error;
|
|
10589
|
+
}
|
|
9961
10590
|
if (this.adapters.length === 0) {
|
|
9962
10591
|
logger.debug("No adapters configured");
|
|
9963
10592
|
resultCallback({ code: import_src.ExportResultCode.SUCCESS });
|
|
@@ -10477,6 +11106,10 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
10477
11106
|
enabled: true,
|
|
10478
11107
|
mode: this.mode
|
|
10479
11108
|
});
|
|
11109
|
+
new NextjsInstrumentation({
|
|
11110
|
+
enabled: true,
|
|
11111
|
+
mode: this.mode
|
|
11112
|
+
});
|
|
10480
11113
|
}
|
|
10481
11114
|
initializeTracing({ baseDirectory }) {
|
|
10482
11115
|
const serviceName = this.config.service?.name || "unknown";
|
|
@@ -10506,6 +11139,10 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
10506
11139
|
return `sdk-${OriginalGlobalUtils.getOriginalDate().getTime()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
10507
11140
|
}
|
|
10508
11141
|
initialize(initParams) {
|
|
11142
|
+
initializeGlobalLogger({
|
|
11143
|
+
logLevel: initParams.logLevel || "silent",
|
|
11144
|
+
prefix: "TuskDrift"
|
|
11145
|
+
});
|
|
10509
11146
|
this.samplingRate = this.config.recording?.sampling_rate ?? 1;
|
|
10510
11147
|
this.initParams = initParams;
|
|
10511
11148
|
if (!this.initParams.env) {
|
|
@@ -10513,10 +11150,6 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
10513
11150
|
logger.warn(`Environment not provided in initialization parameters. Using '${nodeEnv}' as the environment.`);
|
|
10514
11151
|
this.initParams.env = nodeEnv;
|
|
10515
11152
|
}
|
|
10516
|
-
initializeGlobalLogger({
|
|
10517
|
-
logLevel: initParams.logLevel || "silent",
|
|
10518
|
-
prefix: "TuskDrift"
|
|
10519
|
-
});
|
|
10520
11153
|
if (this.initialized) {
|
|
10521
11154
|
logger.debug("Already initialized, skipping...");
|
|
10522
11155
|
return;
|
|
@@ -10712,5 +11345,5 @@ var TuskDriftSDK = class {
|
|
|
10712
11345
|
const TuskDrift = new TuskDriftSDK();
|
|
10713
11346
|
|
|
10714
11347
|
//#endregion
|
|
10715
|
-
export { TuskDrift };
|
|
11348
|
+
export { TuskDrift, withTuskDrift };
|
|
10716
11349
|
//# sourceMappingURL=index.js.map
|