@sentry/node 10.51.0 → 10.52.0

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.
Files changed (69) hide show
  1. package/build/cjs/index.js +4 -4
  2. package/build/cjs/integrations/http.js +18 -145
  3. package/build/cjs/integrations/http.js.map +1 -1
  4. package/build/cjs/integrations/tracing/index.js +21 -22
  5. package/build/cjs/integrations/tracing/index.js.map +1 -1
  6. package/build/cjs/integrations/tracing/{redis.js → redis/index.js} +18 -10
  7. package/build/cjs/integrations/tracing/redis/index.js.map +1 -0
  8. package/build/cjs/integrations/tracing/redis/redis-dc-subscriber.js +186 -0
  9. package/build/cjs/integrations/tracing/redis/redis-dc-subscriber.js.map +1 -0
  10. package/build/cjs/integrations/tracing/redis/vendored/ioredis-instrumentation.js +255 -0
  11. package/build/cjs/integrations/tracing/redis/vendored/ioredis-instrumentation.js.map +1 -0
  12. package/build/cjs/integrations/tracing/redis/vendored/redis-common.js +74 -0
  13. package/build/cjs/integrations/tracing/redis/vendored/redis-common.js.map +1 -0
  14. package/build/cjs/integrations/tracing/redis/vendored/redis-instrumentation.js +685 -0
  15. package/build/cjs/integrations/tracing/redis/vendored/redis-instrumentation.js.map +1 -0
  16. package/build/cjs/integrations/tracing/redis/vendored/semconv.js +47 -0
  17. package/build/cjs/integrations/tracing/redis/vendored/semconv.js.map +1 -0
  18. package/build/cjs/utils/redisCache.js.map +1 -1
  19. package/build/esm/index.js +1 -1
  20. package/build/esm/integrations/http.js +21 -146
  21. package/build/esm/integrations/http.js.map +1 -1
  22. package/build/esm/integrations/tracing/index.js +2 -3
  23. package/build/esm/integrations/tracing/index.js.map +1 -1
  24. package/build/esm/integrations/tracing/{redis.js → redis/index.js} +17 -9
  25. package/build/esm/integrations/tracing/redis/index.js.map +1 -0
  26. package/build/esm/integrations/tracing/redis/redis-dc-subscriber.js +184 -0
  27. package/build/esm/integrations/tracing/redis/redis-dc-subscriber.js.map +1 -0
  28. package/build/esm/integrations/tracing/redis/vendored/ioredis-instrumentation.js +253 -0
  29. package/build/esm/integrations/tracing/redis/vendored/ioredis-instrumentation.js.map +1 -0
  30. package/build/esm/integrations/tracing/redis/vendored/redis-common.js +72 -0
  31. package/build/esm/integrations/tracing/redis/vendored/redis-common.js.map +1 -0
  32. package/build/esm/integrations/tracing/redis/vendored/redis-instrumentation.js +683 -0
  33. package/build/esm/integrations/tracing/redis/vendored/redis-instrumentation.js.map +1 -0
  34. package/build/esm/integrations/tracing/redis/vendored/semconv.js +39 -0
  35. package/build/esm/integrations/tracing/redis/vendored/semconv.js.map +1 -0
  36. package/build/esm/package.json +1 -1
  37. package/build/esm/utils/redisCache.js.map +1 -1
  38. package/build/types/integrations/http.d.ts +8 -15
  39. package/build/types/integrations/http.d.ts.map +1 -1
  40. package/build/types/integrations/tracing/index.d.ts.map +1 -1
  41. package/build/types/integrations/tracing/{redis.d.ts → redis/index.d.ts} +3 -3
  42. package/build/types/integrations/tracing/redis/index.d.ts.map +1 -0
  43. package/build/types/integrations/tracing/redis/redis-dc-subscriber.d.ts +17 -0
  44. package/build/types/integrations/tracing/redis/redis-dc-subscriber.d.ts.map +1 -0
  45. package/build/types/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts +15 -0
  46. package/build/types/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts.map +1 -0
  47. package/build/types/integrations/tracing/redis/vendored/redis-common.d.ts +6 -0
  48. package/build/types/integrations/tracing/redis/vendored/redis-common.d.ts.map +1 -0
  49. package/build/types/integrations/tracing/redis/vendored/redis-instrumentation.d.ts +16 -0
  50. package/build/types/integrations/tracing/redis/vendored/redis-instrumentation.d.ts.map +1 -0
  51. package/build/types/integrations/tracing/redis/vendored/semconv.d.ts +8 -0
  52. package/build/types/integrations/tracing/redis/vendored/semconv.d.ts.map +1 -0
  53. package/build/types/integrations/tracing/redis/vendored/types.d.ts +58 -0
  54. package/build/types/integrations/tracing/redis/vendored/types.d.ts.map +1 -0
  55. package/build/types/utils/redisCache.d.ts +1 -1
  56. package/build/types/utils/redisCache.d.ts.map +1 -1
  57. package/build/types-ts3.8/integrations/http.d.ts +8 -15
  58. package/build/types-ts3.8/integrations/tracing/{redis.d.ts → redis/index.d.ts} +3 -3
  59. package/build/types-ts3.8/integrations/tracing/redis/redis-dc-subscriber.d.ts +17 -0
  60. package/build/types-ts3.8/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts +15 -0
  61. package/build/types-ts3.8/integrations/tracing/redis/vendored/redis-common.d.ts +6 -0
  62. package/build/types-ts3.8/integrations/tracing/redis/vendored/redis-instrumentation.d.ts +16 -0
  63. package/build/types-ts3.8/integrations/tracing/redis/vendored/semconv.d.ts +8 -0
  64. package/build/types-ts3.8/integrations/tracing/redis/vendored/types.d.ts +58 -0
  65. package/build/types-ts3.8/utils/redisCache.d.ts +1 -1
  66. package/package.json +4 -6
  67. package/build/cjs/integrations/tracing/redis.js.map +0 -1
  68. package/build/esm/integrations/tracing/redis.js.map +0 -1
  69. package/build/types/integrations/tracing/redis.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-common.js","sources":["../../../../../../src/integrations/tracing/redis/vendored/redis-common.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTICE from the Sentry authors:\n * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/instrumentation-redis-v0.62.0/packages/redis-common\n * - Upstream version: @opentelemetry/redis-common@0.38.2\n * - Minor TypeScript adjustments for this repository's compiler settings\n */\n/* eslint-disable -- vendored @opentelemetry/redis-common */\n\n/**\n * List of regexes and the number of arguments that should be serialized for matching commands.\n * For example, HSET should serialize which key and field it's operating on, but not its value.\n * Setting the subset to -1 will serialize all arguments.\n * Commands without a match will have their first argument serialized.\n *\n * Refer to https://redis.io/commands/ for the full list.\n */\nconst serializationSubsets = [\n {\n regex: /^ECHO/i,\n args: 0,\n },\n {\n regex: /^(LPUSH|MSET|PFA|PUBLISH|RPUSH|SADD|SET|SPUBLISH|XADD|ZADD)/i,\n args: 1,\n },\n {\n regex: /^(HSET|HMSET|LSET|LINSERT)/i,\n args: 2,\n },\n {\n regex:\n /^(ACL|BIT|B[LRZ]|CLIENT|CLUSTER|CONFIG|COMMAND|DECR|DEL|EVAL|EX|FUNCTION|GEO|GET|HINCR|HMGET|HSCAN|INCR|L[TRLM]|MEMORY|P[EFISTU]|RPOP|S[CDIMORSU]|XACK|X[CDGILPRT]|Z[CDILMPRS])/i,\n args: -1,\n },\n];\n\n/**\n * Given the redis command name and arguments, return a combination of the\n * command name + the allowed arguments according to `serializationSubsets`.\n */\nexport const defaultDbStatementSerializer = (\n cmdName: string,\n cmdArgs: Array<string | Buffer | number | any[]>,\n): string => {\n if (Array.isArray(cmdArgs) && cmdArgs.length) {\n const nArgsToSerialize = serializationSubsets.find(({ regex }) => regex.test(cmdName))?.args ?? 0;\n const argsToSerialize: Array<string | Buffer | number | any[]> =\n nArgsToSerialize >= 0 ? cmdArgs.slice(0, nArgsToSerialize) : cmdArgs.slice();\n if (cmdArgs.length > argsToSerialize.length) {\n argsToSerialize.push(`[${cmdArgs.length - nArgsToSerialize} other arguments]`);\n }\n return `${cmdName} ${argsToSerialize.join(' ')}`;\n }\n return cmdName;\n};\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,uBAAuB;AAC7B,EAAE;AACF,IAAI,KAAK,EAAE,QAAQ;AACnB,IAAI,IAAI,EAAE,CAAC;AACX,GAAG;AACH,EAAE;AACF,IAAI,KAAK,EAAE,8DAA8D;AACzE,IAAI,IAAI,EAAE,CAAC;AACX,GAAG;AACH,EAAE;AACF,IAAI,KAAK,EAAE,6BAA6B;AACxC,IAAI,IAAI,EAAE,CAAC;AACX,GAAG;AACH,EAAE;AACF,IAAI,KAAK;AACT,MAAM,kLAAkL;AACxL,IAAI,IAAI,EAAE,EAAE;AACZ,GAAG;AACH,CAAC;;AAED;AACA;AACA;AACA;AACO,MAAM,+BAA+B;AAC5C,EAAE,OAAO;AACT,EAAE,OAAO;AACT,KAAa;AACb,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAA,IAAK,OAAO,CAAC,MAAM,EAAE;AAChD,IAAI,MAAM,mBAAmB,oBAAoB,CAAC,IAAI,CAAC,CAAC,EAAE,KAAA,EAAO,KAAK,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,IAAA,IAAQ,CAAC;AACrG,IAAI,MAAM,eAAe;AACzB,MAAM,oBAAoB,CAAA,GAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAA,GAAI,OAAO,CAAC,KAAK,EAAE;AAClF,IAAI,IAAI,OAAO,CAAC,SAAS,eAAe,CAAC,MAAM,EAAE;AACjD,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;AACpF,IAAI;AACJ,IAAI,OAAO,CAAC,EAAA,OAAA,CAAA,CAAA,EAAA,eAAA,CAAA,IAAA,CAAA,GAAA,CAAA,CAAA,CAAA;AACA,EAAA;AACA,EAAA,OAAA,OAAA;AACA;;;;"}
@@ -0,0 +1,683 @@
1
+ import { trace, context, SpanKind, SpanStatusCode } from '@opentelemetry/api';
2
+ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
3
+ import { InstrumentationBase, semconvStabilityFromStr, InstrumentationNodeModuleDefinition, isWrapped, SemconvStability, safeExecuteInTheMiddle, InstrumentationNodeModuleFile } from '@opentelemetry/instrumentation';
4
+ import { ATTR_DB_QUERY_TEXT, ATTR_DB_OPERATION_NAME, ATTR_DB_SYSTEM_NAME, ATTR_SERVER_PORT, ATTR_SERVER_ADDRESS } from '@opentelemetry/semantic-conventions';
5
+ import { defaultDbStatementSerializer } from './redis-common.js';
6
+ import { DB_SYSTEM_VALUE_REDIS, ATTR_DB_STATEMENT, ATTR_DB_SYSTEM, DB_SYSTEM_NAME_VALUE_REDIS, ATTR_NET_PEER_PORT, ATTR_NET_PEER_NAME, ATTR_DB_CONNECTION_STRING } from './semconv.js';
7
+
8
+ /*
9
+ * Copyright The OpenTelemetry Authors
10
+ *
11
+ * Licensed under the Apache License, Version 2.0 (the "License");
12
+ * you may not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at
14
+ *
15
+ * https://www.apache.org/licenses/LICENSE-2.0
16
+ *
17
+ * Unless required by applicable law or agreed to in writing, software
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ * See the License for the specific language governing permissions and
21
+ * limitations under the License.
22
+ *
23
+ * NOTICE from the Sentry authors:
24
+ * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/instrumentation-redis-v0.62.0/packages/instrumentation-redis
25
+ * - Upstream version: @opentelemetry/instrumentation-redis@0.62.0
26
+ * - Minor TypeScript adjustments for this repository's compiler settings
27
+ */
28
+ /* eslint-disable -- vendored @opentelemetry/instrumentation-redis */
29
+
30
+
31
+ const PACKAGE_NAME = '@opentelemetry/instrumentation-redis';
32
+ const PACKAGE_VERSION = '0.62.0';
33
+
34
+ // ---- Internal types ----
35
+
36
+ const OTEL_OPEN_SPANS = Symbol('opentelemetry.instrumentation.redis.open_spans');
37
+ const MULTI_COMMAND_OPTIONS = Symbol('opentelemetry.instrumentation.redis.multi_command_options');
38
+
39
+ // ---- v4-v5 utils ----
40
+
41
+ function removeCredentialsFromDBConnectionStringAttribute(
42
+ diagLogger,
43
+ url,
44
+ ) {
45
+ if (typeof url !== 'string' || !url) {
46
+ return undefined;
47
+ }
48
+ try {
49
+ const u = new URL(url);
50
+ u.searchParams.delete('user_pwd');
51
+ u.username = '';
52
+ u.password = '';
53
+ return u.href;
54
+ } catch (err) {
55
+ diagLogger.error('failed to sanitize redis connection url', err);
56
+ }
57
+ return undefined;
58
+ }
59
+
60
+ function getClientAttributes(
61
+ diagLogger,
62
+ options,
63
+ semconvStability,
64
+ ) {
65
+ const attributes = {};
66
+ if (semconvStability & SemconvStability.OLD) {
67
+ Object.assign(attributes, {
68
+ [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,
69
+ [ATTR_NET_PEER_NAME]: options?.socket?.host,
70
+ [ATTR_NET_PEER_PORT]: options?.socket?.port,
71
+ [ATTR_DB_CONNECTION_STRING]: removeCredentialsFromDBConnectionStringAttribute(diagLogger, options?.url),
72
+ });
73
+ }
74
+ if (semconvStability & SemconvStability.STABLE) {
75
+ Object.assign(attributes, {
76
+ [ATTR_DB_SYSTEM_NAME]: DB_SYSTEM_NAME_VALUE_REDIS,
77
+ [ATTR_SERVER_ADDRESS]: options?.socket?.host,
78
+ [ATTR_SERVER_PORT]: options?.socket?.port,
79
+ });
80
+ }
81
+ return attributes;
82
+ }
83
+
84
+ // ---- v2-v3 utils ----
85
+
86
+ function endSpanV2(span, err) {
87
+ if (err) {
88
+ span.setStatus({
89
+ code: SpanStatusCode.ERROR,
90
+ message: err.message,
91
+ });
92
+ }
93
+ span.end();
94
+ }
95
+
96
+ function getTracedCreateClient(original) {
97
+ return function createClientTrace() {
98
+ const client = original.apply(this, arguments);
99
+ return context.bind(context.active(), client);
100
+ };
101
+ }
102
+
103
+ function getTracedCreateStreamTrace(original) {
104
+ return function create_stream_trace() {
105
+ if (!Object.prototype.hasOwnProperty.call(this, 'stream')) {
106
+ Object.defineProperty(this, 'stream', {
107
+ get() {
108
+ return this._patched_redis_stream;
109
+ },
110
+ set(val) {
111
+ context.bind(context.active(), val);
112
+ this._patched_redis_stream = val;
113
+ },
114
+ });
115
+ }
116
+ return original.apply(this, arguments);
117
+ };
118
+ }
119
+
120
+ // ---- RedisInstrumentationV2_V3 ----
121
+
122
+ class RedisInstrumentationV2_V3 extends InstrumentationBase {
123
+ static __initStatic() {this.COMPONENT = 'redis';}
124
+
125
+ constructor(config = {}) {
126
+ super(PACKAGE_NAME, PACKAGE_VERSION, config);
127
+ this._semconvStability = config.semconvStability
128
+ ? config.semconvStability
129
+ : semconvStabilityFromStr('database', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);
130
+ }
131
+
132
+ setConfig(config = {}) {
133
+ super.setConfig(config);
134
+ this._semconvStability = config.semconvStability
135
+ ? config.semconvStability
136
+ : semconvStabilityFromStr('database', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);
137
+ }
138
+
139
+ init() {
140
+ return [
141
+ new InstrumentationNodeModuleDefinition(
142
+ 'redis',
143
+ ['>=2.6.0 <4'],
144
+ (moduleExports) => {
145
+ if (isWrapped(moduleExports.RedisClient.prototype['internal_send_command'])) {
146
+ this._unwrap(moduleExports.RedisClient.prototype, 'internal_send_command');
147
+ }
148
+ this._wrap(moduleExports.RedisClient.prototype, 'internal_send_command', this._getPatchInternalSendCommand());
149
+ if (isWrapped(moduleExports.RedisClient.prototype['create_stream'])) {
150
+ this._unwrap(moduleExports.RedisClient.prototype, 'create_stream');
151
+ }
152
+ this._wrap(moduleExports.RedisClient.prototype, 'create_stream', this._getPatchCreateStream());
153
+ if (isWrapped(moduleExports.createClient)) {
154
+ this._unwrap(moduleExports, 'createClient');
155
+ }
156
+ this._wrap(moduleExports, 'createClient', this._getPatchCreateClient());
157
+ return moduleExports;
158
+ },
159
+ (moduleExports) => {
160
+ if (moduleExports === undefined) return;
161
+ this._unwrap(moduleExports.RedisClient.prototype, 'internal_send_command');
162
+ this._unwrap(moduleExports.RedisClient.prototype, 'create_stream');
163
+ this._unwrap(moduleExports, 'createClient');
164
+ },
165
+ ),
166
+ ];
167
+ }
168
+
169
+ _getPatchInternalSendCommand() {
170
+ const instrumentation = this;
171
+ return function internal_send_command(original) {
172
+ return function internal_send_command_trace( cmd) {
173
+ if (arguments.length !== 1 || typeof cmd !== 'object') {
174
+ return original.apply(this, arguments);
175
+ }
176
+ const config = instrumentation.getConfig();
177
+ const hasNoParentSpan = trace.getSpan(context.active()) === undefined;
178
+ if (config.requireParentSpan === true && hasNoParentSpan) {
179
+ return original.apply(this, arguments);
180
+ }
181
+ const dbStatementSerializer = config?.dbStatementSerializer || defaultDbStatementSerializer;
182
+ const attributes = {};
183
+ if (instrumentation._semconvStability & SemconvStability.OLD) {
184
+ Object.assign(attributes, {
185
+ [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,
186
+ [ATTR_DB_STATEMENT]: dbStatementSerializer(cmd.command, cmd.args),
187
+ });
188
+ }
189
+ if (instrumentation._semconvStability & SemconvStability.STABLE) {
190
+ Object.assign(attributes, {
191
+ [ATTR_DB_SYSTEM_NAME]: DB_SYSTEM_NAME_VALUE_REDIS,
192
+ [ATTR_DB_OPERATION_NAME]: cmd.command,
193
+ [ATTR_DB_QUERY_TEXT]: dbStatementSerializer(cmd.command, cmd.args),
194
+ });
195
+ }
196
+ attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis';
197
+ const span = instrumentation.tracer.startSpan(`${RedisInstrumentationV2_V3.COMPONENT}-${cmd.command}`, {
198
+ kind: SpanKind.CLIENT,
199
+ attributes,
200
+ });
201
+ if (this.connection_options) {
202
+ const connectionAttributes = {};
203
+ if (instrumentation._semconvStability & SemconvStability.OLD) {
204
+ Object.assign(connectionAttributes, {
205
+ [ATTR_NET_PEER_NAME]: this.connection_options.host,
206
+ [ATTR_NET_PEER_PORT]: this.connection_options.port,
207
+ });
208
+ }
209
+ if (instrumentation._semconvStability & SemconvStability.STABLE) {
210
+ Object.assign(connectionAttributes, {
211
+ [ATTR_SERVER_ADDRESS]: this.connection_options.host,
212
+ [ATTR_SERVER_PORT]: this.connection_options.port,
213
+ });
214
+ }
215
+ span.setAttributes(connectionAttributes);
216
+ }
217
+ if (this.address && instrumentation._semconvStability & SemconvStability.OLD) {
218
+ span.setAttribute(ATTR_DB_CONNECTION_STRING, `redis://${this.address}`);
219
+ }
220
+ const originalCallback = arguments[0].callback;
221
+ if (originalCallback) {
222
+ const originalContext = context.active();
223
+ arguments[0].callback = function callback( err, reply) {
224
+ if (config?.responseHook) {
225
+ const responseHook = config.responseHook;
226
+ safeExecuteInTheMiddle(
227
+ () => {
228
+ responseHook(span, cmd.command, cmd.args, reply);
229
+ },
230
+ (e) => {
231
+ if (e) {
232
+ instrumentation._diag.error('Error executing responseHook', e);
233
+ }
234
+ },
235
+ true,
236
+ );
237
+ }
238
+ endSpanV2(span, err);
239
+ return context.with(originalContext, originalCallback, this, ...arguments);
240
+ };
241
+ }
242
+ try {
243
+ return original.apply(this, arguments);
244
+ } catch (rethrow) {
245
+ endSpanV2(span, rethrow );
246
+ throw rethrow;
247
+ }
248
+ };
249
+ };
250
+ }
251
+
252
+ _getPatchCreateClient() {
253
+ return function createClient(original) {
254
+ return getTracedCreateClient(original);
255
+ };
256
+ }
257
+
258
+ _getPatchCreateStream() {
259
+ return function createReadStream(original) {
260
+ return getTracedCreateStreamTrace(original);
261
+ };
262
+ }
263
+ } RedisInstrumentationV2_V3.__initStatic();
264
+
265
+ // ---- RedisInstrumentationV4_V5 ----
266
+
267
+ class RedisInstrumentationV4_V5 extends InstrumentationBase {
268
+ static __initStatic2() {this.COMPONENT = 'redis';}
269
+
270
+ constructor(config = {}) {
271
+ super(PACKAGE_NAME, PACKAGE_VERSION, config);
272
+ this._semconvStability = config.semconvStability
273
+ ? config.semconvStability
274
+ : semconvStabilityFromStr('database', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);
275
+ }
276
+
277
+ setConfig(config = {}) {
278
+ super.setConfig(config);
279
+ this._semconvStability = config.semconvStability
280
+ ? config.semconvStability
281
+ : semconvStabilityFromStr('database', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);
282
+ }
283
+
284
+ init() {
285
+ return [
286
+ this._getInstrumentationNodeModuleDefinition('@redis/client'),
287
+ this._getInstrumentationNodeModuleDefinition('@node-redis/client'),
288
+ ];
289
+ }
290
+
291
+ _getInstrumentationNodeModuleDefinition(basePackageName) {
292
+ const commanderModuleFile = new InstrumentationNodeModuleFile(
293
+ `${basePackageName}/dist/lib/commander.js`,
294
+ ['^1.0.0'],
295
+ (moduleExports, moduleVersion) => {
296
+ const transformCommandArguments = moduleExports.transformCommandArguments;
297
+ if (!transformCommandArguments) {
298
+ this._diag.error('internal instrumentation error, missing transformCommandArguments function');
299
+ return moduleExports;
300
+ }
301
+ const functionToPatch = moduleVersion?.startsWith('1.0.') ? 'extendWithCommands' : 'attachCommands';
302
+ if (isWrapped(moduleExports?.[functionToPatch])) {
303
+ this._unwrap(moduleExports, functionToPatch);
304
+ }
305
+ this._wrap(moduleExports, functionToPatch, this._getPatchExtendWithCommands(transformCommandArguments));
306
+ return moduleExports;
307
+ },
308
+ (moduleExports) => {
309
+ if (isWrapped(moduleExports?.extendWithCommands)) {
310
+ this._unwrap(moduleExports, 'extendWithCommands');
311
+ }
312
+ if (isWrapped(moduleExports?.attachCommands)) {
313
+ this._unwrap(moduleExports, 'attachCommands');
314
+ }
315
+ },
316
+ );
317
+
318
+ const multiCommanderModule = new InstrumentationNodeModuleFile(
319
+ `${basePackageName}/dist/lib/client/multi-command.js`,
320
+ ['^1.0.0', '>=5.0.0 <5.12.0'],
321
+ (moduleExports) => {
322
+ const redisClientMultiCommandPrototype = moduleExports?.default?.prototype;
323
+ if (isWrapped(redisClientMultiCommandPrototype?.exec)) {
324
+ this._unwrap(redisClientMultiCommandPrototype, 'exec');
325
+ }
326
+ this._wrap(redisClientMultiCommandPrototype, 'exec', this._getPatchMultiCommandsExec(false));
327
+ if (isWrapped(redisClientMultiCommandPrototype?.execAsPipeline)) {
328
+ this._unwrap(redisClientMultiCommandPrototype, 'execAsPipeline');
329
+ }
330
+ this._wrap(redisClientMultiCommandPrototype, 'execAsPipeline', this._getPatchMultiCommandsExec(true));
331
+ if (isWrapped(redisClientMultiCommandPrototype?.addCommand)) {
332
+ this._unwrap(redisClientMultiCommandPrototype, 'addCommand');
333
+ }
334
+ this._wrap(redisClientMultiCommandPrototype, 'addCommand', this._getPatchMultiCommandsAddCommand());
335
+ return moduleExports;
336
+ },
337
+ (moduleExports) => {
338
+ const redisClientMultiCommandPrototype = moduleExports?.default?.prototype;
339
+ if (isWrapped(redisClientMultiCommandPrototype?.exec)) {
340
+ this._unwrap(redisClientMultiCommandPrototype, 'exec');
341
+ }
342
+ if (isWrapped(redisClientMultiCommandPrototype?.execAsPipeline)) {
343
+ this._unwrap(redisClientMultiCommandPrototype, 'execAsPipeline');
344
+ }
345
+ if (isWrapped(redisClientMultiCommandPrototype?.addCommand)) {
346
+ this._unwrap(redisClientMultiCommandPrototype, 'addCommand');
347
+ }
348
+ },
349
+ );
350
+
351
+ const clientIndexModule = new InstrumentationNodeModuleFile(
352
+ `${basePackageName}/dist/lib/client/index.js`,
353
+ ['^1.0.0', '>=5.0.0 <5.12.0'],
354
+ (moduleExports) => {
355
+ const redisClientPrototype = moduleExports?.default?.prototype;
356
+ if (redisClientPrototype?.multi) {
357
+ if (isWrapped(redisClientPrototype?.multi)) {
358
+ this._unwrap(redisClientPrototype, 'multi');
359
+ }
360
+ this._wrap(redisClientPrototype, 'multi', this._getPatchRedisClientMulti());
361
+ }
362
+ if (redisClientPrototype?.MULTI) {
363
+ if (isWrapped(redisClientPrototype?.MULTI)) {
364
+ this._unwrap(redisClientPrototype, 'MULTI');
365
+ }
366
+ this._wrap(redisClientPrototype, 'MULTI', this._getPatchRedisClientMulti());
367
+ }
368
+ if (isWrapped(redisClientPrototype?.sendCommand)) {
369
+ this._unwrap(redisClientPrototype, 'sendCommand');
370
+ }
371
+ this._wrap(redisClientPrototype, 'sendCommand', this._getPatchRedisClientSendCommand());
372
+ if (isWrapped(redisClientPrototype?.connect)) {
373
+ this._unwrap(redisClientPrototype, 'connect');
374
+ }
375
+ this._wrap(redisClientPrototype, 'connect', this._getPatchedClientConnect());
376
+ return moduleExports;
377
+ },
378
+ (moduleExports) => {
379
+ const redisClientPrototype = moduleExports?.default?.prototype;
380
+ if (isWrapped(redisClientPrototype?.multi)) {
381
+ this._unwrap(redisClientPrototype, 'multi');
382
+ }
383
+ if (isWrapped(redisClientPrototype?.MULTI)) {
384
+ this._unwrap(redisClientPrototype, 'MULTI');
385
+ }
386
+ if (isWrapped(redisClientPrototype?.sendCommand)) {
387
+ this._unwrap(redisClientPrototype, 'sendCommand');
388
+ }
389
+ if (isWrapped(redisClientPrototype?.connect)) {
390
+ this._unwrap(redisClientPrototype, 'connect');
391
+ }
392
+ },
393
+ );
394
+
395
+ return new InstrumentationNodeModuleDefinition(
396
+ basePackageName,
397
+ ['^1.0.0', '>=5.0.0 <5.12.0'],
398
+ (moduleExports) => moduleExports,
399
+ () => {},
400
+ [commanderModuleFile, multiCommanderModule, clientIndexModule],
401
+ );
402
+ }
403
+
404
+ _getPatchExtendWithCommands(transformCommandArguments) {
405
+ const plugin = this;
406
+ return function extendWithCommandsPatchWrapper(original) {
407
+ return function extendWithCommandsPatch( config) {
408
+ if (config?.BaseClass?.name !== 'RedisClient') {
409
+ return original.apply(this, arguments);
410
+ }
411
+ const origExecutor = config.executor;
412
+ config.executor = function ( command, args) {
413
+ const redisCommandArguments = transformCommandArguments(command, args).args;
414
+ return plugin._traceClientCommand(origExecutor, this, arguments, redisCommandArguments);
415
+ };
416
+ return original.apply(this, arguments);
417
+ };
418
+ };
419
+ }
420
+
421
+ _getPatchMultiCommandsExec(isPipeline) {
422
+ const plugin = this;
423
+ return function execPatchWrapper(original) {
424
+ return function execPatch() {
425
+ const execRes = original.apply(this, arguments);
426
+ if (typeof execRes?.then !== 'function') {
427
+ plugin._diag.error('non-promise result when patching exec/execAsPipeline');
428
+ return execRes;
429
+ }
430
+ return execRes
431
+ .then((redisRes) => {
432
+ const openSpans = this[OTEL_OPEN_SPANS];
433
+ plugin._endSpansWithRedisReplies(openSpans, redisRes, isPipeline);
434
+ return redisRes;
435
+ })
436
+ .catch((err) => {
437
+ const openSpans = this[OTEL_OPEN_SPANS];
438
+ if (!openSpans) {
439
+ plugin._diag.error('cannot find open spans to end for multi/pipeline');
440
+ } else {
441
+ const replies =
442
+ err.constructor.name === 'MultiErrorReply'
443
+ ? (err ).replies
444
+ : new Array(openSpans.length).fill(err);
445
+ plugin._endSpansWithRedisReplies(openSpans, replies, isPipeline);
446
+ }
447
+ return Promise.reject(err);
448
+ });
449
+ };
450
+ };
451
+ }
452
+
453
+ _getPatchMultiCommandsAddCommand() {
454
+ const plugin = this;
455
+ return function addCommandWrapper(original) {
456
+ return function addCommandPatch( args) {
457
+ return plugin._traceClientCommand(original, this, arguments, args);
458
+ };
459
+ };
460
+ }
461
+
462
+ _getPatchRedisClientMulti() {
463
+ return function multiPatchWrapper(original) {
464
+ return function multiPatch() {
465
+ const multiRes = original.apply(this, arguments);
466
+ multiRes[MULTI_COMMAND_OPTIONS] = this.options;
467
+ return multiRes;
468
+ };
469
+ };
470
+ }
471
+
472
+ _getPatchRedisClientSendCommand() {
473
+ const plugin = this;
474
+ return function sendCommandWrapper(original) {
475
+ return function sendCommandPatch( args) {
476
+ return plugin._traceClientCommand(original, this, arguments, args);
477
+ };
478
+ };
479
+ }
480
+
481
+ _getPatchedClientConnect() {
482
+ const plugin = this;
483
+ return function connectWrapper(original) {
484
+ return function patchedConnect() {
485
+ const options = this.options;
486
+ const attributes = getClientAttributes(plugin._diag, options, plugin._semconvStability);
487
+ attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis';
488
+ const span = plugin.tracer.startSpan(`${RedisInstrumentationV4_V5.COMPONENT}-connect`, {
489
+ kind: SpanKind.CLIENT,
490
+ attributes,
491
+ });
492
+ const res = context.with(trace.setSpan(context.active(), span), () => {
493
+ return original.apply(this);
494
+ });
495
+ return res
496
+ .then((result) => {
497
+ span.end();
498
+ return result;
499
+ })
500
+ .catch((error) => {
501
+ span.recordException(error);
502
+ span.setStatus({
503
+ code: SpanStatusCode.ERROR,
504
+ message: error.message,
505
+ });
506
+ span.end();
507
+ return Promise.reject(error);
508
+ });
509
+ };
510
+ };
511
+ }
512
+
513
+ _traceClientCommand(
514
+ origFunction,
515
+ origThis,
516
+ origArguments,
517
+ redisCommandArguments,
518
+ ) {
519
+ const hasNoParentSpan = trace.getSpan(context.active()) === undefined;
520
+ if (hasNoParentSpan && this.getConfig().requireParentSpan) {
521
+ return origFunction.apply(origThis, origArguments);
522
+ }
523
+ const clientOptions = origThis.options || origThis[MULTI_COMMAND_OPTIONS];
524
+ const commandName = redisCommandArguments[0] ;
525
+ const commandArgs = redisCommandArguments.slice(1);
526
+ const dbStatementSerializer = this.getConfig().dbStatementSerializer || defaultDbStatementSerializer;
527
+ const attributes = getClientAttributes(this._diag, clientOptions, this._semconvStability);
528
+ if (this._semconvStability & SemconvStability.STABLE) {
529
+ attributes[ATTR_DB_OPERATION_NAME] = commandName;
530
+ }
531
+ try {
532
+ const dbStatement = dbStatementSerializer(commandName, commandArgs);
533
+ if (dbStatement != null) {
534
+ if (this._semconvStability & SemconvStability.OLD) {
535
+ attributes[ATTR_DB_STATEMENT] = dbStatement;
536
+ }
537
+ if (this._semconvStability & SemconvStability.STABLE) {
538
+ attributes[ATTR_DB_QUERY_TEXT] = dbStatement;
539
+ }
540
+ }
541
+ } catch (e) {
542
+ this._diag.error('dbStatementSerializer throw an exception', e, { commandName });
543
+ }
544
+ attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis';
545
+ const span = this.tracer.startSpan(`${RedisInstrumentationV4_V5.COMPONENT}-${commandName}`, {
546
+ kind: SpanKind.CLIENT,
547
+ attributes,
548
+ });
549
+ const res = context.with(trace.setSpan(context.active(), span), () => {
550
+ return origFunction.apply(origThis, origArguments);
551
+ });
552
+ if (typeof res?.then === 'function') {
553
+ res.then(
554
+ (redisRes) => {
555
+ this._endSpanWithResponse(span, commandName, commandArgs, redisRes, undefined);
556
+ },
557
+ (err) => {
558
+ this._endSpanWithResponse(span, commandName, commandArgs, null, err);
559
+ },
560
+ );
561
+ } else {
562
+ const redisClientMultiCommand = res;
563
+ redisClientMultiCommand[OTEL_OPEN_SPANS] = redisClientMultiCommand[OTEL_OPEN_SPANS] || [];
564
+ redisClientMultiCommand[OTEL_OPEN_SPANS].push({
565
+ span,
566
+ commandName,
567
+ commandArgs,
568
+ });
569
+ }
570
+ return res;
571
+ }
572
+
573
+ _endSpansWithRedisReplies(openSpans, replies, isPipeline = false) {
574
+ if (!openSpans) {
575
+ return this._diag.error('cannot find open spans to end for redis multi/pipeline');
576
+ }
577
+ if (replies.length !== openSpans.length) {
578
+ return this._diag.error('number of multi command spans does not match response from redis');
579
+ }
580
+ const allCommands = openSpans.map(s => s.commandName);
581
+ const allSameCommand = allCommands.every(cmd => cmd === allCommands[0]);
582
+ const operationName = allSameCommand
583
+ ? (isPipeline ? 'PIPELINE ' : 'MULTI ') + allCommands[0]
584
+ : isPipeline
585
+ ? 'PIPELINE'
586
+ : 'MULTI';
587
+ for (let i = 0; i < openSpans.length; i++) {
588
+ const { span, commandArgs } = openSpans[i];
589
+ const currCommandRes = replies[i];
590
+ const [res, err] = currCommandRes instanceof Error ? [null, currCommandRes] : [currCommandRes, undefined];
591
+ if (this._semconvStability & SemconvStability.STABLE) {
592
+ span.setAttribute(ATTR_DB_OPERATION_NAME, operationName);
593
+ }
594
+ this._endSpanWithResponse(span, allCommands[i], commandArgs, res, err);
595
+ }
596
+ }
597
+
598
+ _endSpanWithResponse(
599
+ span,
600
+ commandName,
601
+ commandArgs,
602
+ response,
603
+ error,
604
+ ) {
605
+ const { responseHook } = this.getConfig();
606
+ if (!error && responseHook) {
607
+ try {
608
+ responseHook(span, commandName, commandArgs, response);
609
+ } catch (err) {
610
+ this._diag.error('responseHook throw an exception', err);
611
+ }
612
+ }
613
+ if (error) {
614
+ span.recordException(error);
615
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error?.message });
616
+ }
617
+ span.end();
618
+ }
619
+ } RedisInstrumentationV4_V5.__initStatic2();
620
+
621
+ // ---- RedisInstrumentation (wrapper) ----
622
+
623
+ const DEFAULT_CONFIG = {
624
+ requireParentSpan: false,
625
+ };
626
+
627
+ class RedisInstrumentation extends InstrumentationBase {
628
+
629
+ __init() {this.initialized = false;}
630
+
631
+ constructor(config = {}) {
632
+ const resolvedConfig = { ...DEFAULT_CONFIG, ...config };
633
+ super(PACKAGE_NAME, PACKAGE_VERSION, resolvedConfig);RedisInstrumentation.prototype.__init.call(this); this.instrumentationV2_V3 = new RedisInstrumentationV2_V3(this.getConfig());
634
+ this.instrumentationV4_V5 = new RedisInstrumentationV4_V5(this.getConfig());
635
+ this.initialized = true;
636
+ }
637
+
638
+ setConfig(config = {}) {
639
+ const newConfig = { ...DEFAULT_CONFIG, ...config };
640
+ super.setConfig(newConfig);
641
+ if (!this.initialized) {
642
+ return;
643
+ }
644
+ this.instrumentationV2_V3.setConfig(newConfig);
645
+ this.instrumentationV4_V5.setConfig(newConfig);
646
+ }
647
+
648
+ init() {}
649
+
650
+ getModuleDefinitions() {
651
+ return [...this.instrumentationV2_V3.getModuleDefinitions(), ...this.instrumentationV4_V5.getModuleDefinitions()];
652
+ }
653
+
654
+ setTracerProvider(tracerProvider) {
655
+ super.setTracerProvider(tracerProvider);
656
+ if (!this.initialized) {
657
+ return;
658
+ }
659
+ this.instrumentationV2_V3.setTracerProvider(tracerProvider);
660
+ this.instrumentationV4_V5.setTracerProvider(tracerProvider);
661
+ }
662
+
663
+ enable() {
664
+ super.enable();
665
+ if (!this.initialized) {
666
+ return;
667
+ }
668
+ this.instrumentationV2_V3.enable();
669
+ this.instrumentationV4_V5.enable();
670
+ }
671
+
672
+ disable() {
673
+ super.disable();
674
+ if (!this.initialized) {
675
+ return;
676
+ }
677
+ this.instrumentationV2_V3.disable();
678
+ this.instrumentationV4_V5.disable();
679
+ }
680
+ }
681
+
682
+ export { RedisInstrumentation };
683
+ //# sourceMappingURL=redis-instrumentation.js.map