@sentry/node 10.51.0 → 10.53.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.
- package/build/cjs/index.js +4 -4
- package/build/cjs/integrations/http.js +18 -145
- package/build/cjs/integrations/http.js.map +1 -1
- package/build/cjs/integrations/tracing/anthropic-ai/instrumentation.js +8 -8
- package/build/cjs/integrations/tracing/anthropic-ai/instrumentation.js.map +1 -1
- package/build/cjs/integrations/tracing/google-genai/instrumentation.js +9 -9
- package/build/cjs/integrations/tracing/google-genai/instrumentation.js.map +1 -1
- package/build/cjs/integrations/tracing/index.js +21 -22
- package/build/cjs/integrations/tracing/index.js.map +1 -1
- package/build/cjs/integrations/tracing/langchain/instrumentation.js +12 -12
- package/build/cjs/integrations/tracing/langchain/instrumentation.js.map +1 -1
- package/build/cjs/integrations/tracing/langgraph/instrumentation.js +12 -12
- package/build/cjs/integrations/tracing/langgraph/instrumentation.js.map +1 -1
- package/build/cjs/integrations/tracing/openai/instrumentation.js +11 -11
- package/build/cjs/integrations/tracing/openai/instrumentation.js.map +1 -1
- package/build/cjs/integrations/tracing/postgresjs.js +10 -10
- package/build/cjs/integrations/tracing/postgresjs.js.map +1 -1
- package/build/cjs/integrations/tracing/{redis.js → redis/index.js} +18 -10
- package/build/cjs/integrations/tracing/redis/index.js.map +1 -0
- package/build/cjs/integrations/tracing/redis/redis-dc-subscriber.js +186 -0
- package/build/cjs/integrations/tracing/redis/redis-dc-subscriber.js.map +1 -0
- package/build/cjs/integrations/tracing/redis/vendored/ioredis-instrumentation.js +255 -0
- package/build/cjs/integrations/tracing/redis/vendored/ioredis-instrumentation.js.map +1 -0
- package/build/cjs/integrations/tracing/redis/vendored/redis-common.js +74 -0
- package/build/cjs/integrations/tracing/redis/vendored/redis-common.js.map +1 -0
- package/build/cjs/integrations/tracing/redis/vendored/redis-instrumentation.js +685 -0
- package/build/cjs/integrations/tracing/redis/vendored/redis-instrumentation.js.map +1 -0
- package/build/cjs/integrations/tracing/redis/vendored/semconv.js +47 -0
- package/build/cjs/integrations/tracing/redis/vendored/semconv.js.map +1 -0
- package/build/cjs/utils/redisCache.js.map +1 -1
- package/build/esm/index.js +1 -1
- package/build/esm/integrations/http.js +21 -146
- package/build/esm/integrations/http.js.map +1 -1
- package/build/esm/integrations/tracing/anthropic-ai/instrumentation.js +8 -8
- package/build/esm/integrations/tracing/anthropic-ai/instrumentation.js.map +1 -1
- package/build/esm/integrations/tracing/google-genai/instrumentation.js +9 -9
- package/build/esm/integrations/tracing/google-genai/instrumentation.js.map +1 -1
- package/build/esm/integrations/tracing/index.js +2 -3
- package/build/esm/integrations/tracing/index.js.map +1 -1
- package/build/esm/integrations/tracing/langchain/instrumentation.js +12 -12
- package/build/esm/integrations/tracing/langchain/instrumentation.js.map +1 -1
- package/build/esm/integrations/tracing/langgraph/instrumentation.js +12 -12
- package/build/esm/integrations/tracing/langgraph/instrumentation.js.map +1 -1
- package/build/esm/integrations/tracing/openai/instrumentation.js +11 -11
- package/build/esm/integrations/tracing/openai/instrumentation.js.map +1 -1
- package/build/esm/integrations/tracing/postgresjs.js +10 -10
- package/build/esm/integrations/tracing/postgresjs.js.map +1 -1
- package/build/esm/integrations/tracing/{redis.js → redis/index.js} +17 -9
- package/build/esm/integrations/tracing/redis/index.js.map +1 -0
- package/build/esm/integrations/tracing/redis/redis-dc-subscriber.js +184 -0
- package/build/esm/integrations/tracing/redis/redis-dc-subscriber.js.map +1 -0
- package/build/esm/integrations/tracing/redis/vendored/ioredis-instrumentation.js +253 -0
- package/build/esm/integrations/tracing/redis/vendored/ioredis-instrumentation.js.map +1 -0
- package/build/esm/integrations/tracing/redis/vendored/redis-common.js +72 -0
- package/build/esm/integrations/tracing/redis/vendored/redis-common.js.map +1 -0
- package/build/esm/integrations/tracing/redis/vendored/redis-instrumentation.js +683 -0
- package/build/esm/integrations/tracing/redis/vendored/redis-instrumentation.js.map +1 -0
- package/build/esm/integrations/tracing/redis/vendored/semconv.js +39 -0
- package/build/esm/integrations/tracing/redis/vendored/semconv.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/utils/redisCache.js.map +1 -1
- package/build/types/integrations/http.d.ts +8 -15
- package/build/types/integrations/http.d.ts.map +1 -1
- package/build/types/integrations/tracing/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/{redis.d.ts → redis/index.d.ts} +3 -3
- package/build/types/integrations/tracing/redis/index.d.ts.map +1 -0
- package/build/types/integrations/tracing/redis/redis-dc-subscriber.d.ts +17 -0
- package/build/types/integrations/tracing/redis/redis-dc-subscriber.d.ts.map +1 -0
- package/build/types/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts +15 -0
- package/build/types/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts.map +1 -0
- package/build/types/integrations/tracing/redis/vendored/redis-common.d.ts +6 -0
- package/build/types/integrations/tracing/redis/vendored/redis-common.d.ts.map +1 -0
- package/build/types/integrations/tracing/redis/vendored/redis-instrumentation.d.ts +16 -0
- package/build/types/integrations/tracing/redis/vendored/redis-instrumentation.d.ts.map +1 -0
- package/build/types/integrations/tracing/redis/vendored/semconv.d.ts +8 -0
- package/build/types/integrations/tracing/redis/vendored/semconv.d.ts.map +1 -0
- package/build/types/integrations/tracing/redis/vendored/types.d.ts +58 -0
- package/build/types/integrations/tracing/redis/vendored/types.d.ts.map +1 -0
- package/build/types/utils/redisCache.d.ts +1 -1
- package/build/types/utils/redisCache.d.ts.map +1 -1
- package/build/types-ts3.8/integrations/http.d.ts +8 -15
- package/build/types-ts3.8/integrations/tracing/{redis.d.ts → redis/index.d.ts} +3 -3
- package/build/types-ts3.8/integrations/tracing/redis/redis-dc-subscriber.d.ts +17 -0
- package/build/types-ts3.8/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts +15 -0
- package/build/types-ts3.8/integrations/tracing/redis/vendored/redis-common.d.ts +6 -0
- package/build/types-ts3.8/integrations/tracing/redis/vendored/redis-instrumentation.d.ts +16 -0
- package/build/types-ts3.8/integrations/tracing/redis/vendored/semconv.d.ts +8 -0
- package/build/types-ts3.8/integrations/tracing/redis/vendored/types.d.ts +58 -0
- package/build/types-ts3.8/utils/redisCache.d.ts +1 -1
- package/package.json +4 -6
- package/build/cjs/integrations/tracing/redis.js.map +0 -1
- package/build/esm/integrations/tracing/redis.js.map +0 -1
- package/build/types/integrations/tracing/redis.d.ts.map +0 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
|
-
const instrumentationIoredis = require('@opentelemetry/instrumentation-ioredis');
|
|
4
|
-
const instrumentationRedis = require('@opentelemetry/instrumentation-redis');
|
|
5
3
|
const core = require('@sentry/core');
|
|
6
4
|
const nodeCore = require('@sentry/node-core');
|
|
7
|
-
const redisCache = require('
|
|
5
|
+
const redisCache = require('../../../utils/redisCache.js');
|
|
6
|
+
const ioredisInstrumentation = require('./vendored/ioredis-instrumentation.js');
|
|
7
|
+
const redisInstrumentation = require('./vendored/redis-instrumentation.js');
|
|
8
|
+
const redisDcSubscriber = require('./redis-dc-subscriber.js');
|
|
8
9
|
|
|
9
10
|
const INTEGRATION_NAME = 'Redis';
|
|
10
11
|
|
|
@@ -18,8 +19,6 @@ const cacheResponseHook = (
|
|
|
18
19
|
cmdArgs,
|
|
19
20
|
response,
|
|
20
21
|
) => {
|
|
21
|
-
span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.redis');
|
|
22
|
-
|
|
23
22
|
const safeKey = redisCache.getCacheKeySafely(redisCommand, cmdArgs);
|
|
24
23
|
const cacheOperation = redisCache.getCacheOperation(redisCommand);
|
|
25
24
|
|
|
@@ -35,8 +34,12 @@ const cacheResponseHook = (
|
|
|
35
34
|
|
|
36
35
|
// otel/ioredis seems to be using the old standard, as there was a change to those params: https://github.com/open-telemetry/opentelemetry-specification/issues/3199
|
|
37
36
|
// We are using params based on the docs: https://opentelemetry.io/docs/specs/semconv/attributes-registry/network/
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
// Fall back to stable semconv attributes (server.address/server.port) when
|
|
38
|
+
// old-semconv ones are absent, eg OTEL_SEMCONV_STABILITY_OPT_IN=database
|
|
39
|
+
// set for node-redis v4/v5.
|
|
40
|
+
const spanData = core.spanToJSON(span).data;
|
|
41
|
+
const networkPeerAddress = spanData['net.peer.name'] ?? spanData['server.address'];
|
|
42
|
+
const networkPeerPort = spanData['net.peer.port'] ?? spanData['server.port'];
|
|
40
43
|
if (networkPeerPort && networkPeerAddress) {
|
|
41
44
|
span.setAttributes({ 'network.peer.address': networkPeerAddress, 'network.peer.port': networkPeerPort });
|
|
42
45
|
}
|
|
@@ -65,13 +68,13 @@ const cacheResponseHook = (
|
|
|
65
68
|
};
|
|
66
69
|
|
|
67
70
|
const instrumentIORedis = nodeCore.generateInstrumentOnce(`${INTEGRATION_NAME}.IORedis`, () => {
|
|
68
|
-
return new
|
|
71
|
+
return new ioredisInstrumentation.IORedisInstrumentation({
|
|
69
72
|
responseHook: cacheResponseHook,
|
|
70
73
|
});
|
|
71
74
|
});
|
|
72
75
|
|
|
73
76
|
const instrumentRedisModule = nodeCore.generateInstrumentOnce(`${INTEGRATION_NAME}.Redis`, () => {
|
|
74
|
-
return new
|
|
77
|
+
return new redisInstrumentation.RedisInstrumentation({
|
|
75
78
|
responseHook: cacheResponseHook,
|
|
76
79
|
});
|
|
77
80
|
});
|
|
@@ -81,6 +84,11 @@ const instrumentRedis = Object.assign(
|
|
|
81
84
|
() => {
|
|
82
85
|
instrumentIORedis();
|
|
83
86
|
instrumentRedisModule();
|
|
87
|
+
// node-redis >= 5.12.0 publishes via diagnostics_channel. The subscriber uses
|
|
88
|
+
// `@sentry/opentelemetry/tracing-channel`, which needs the Sentry OTel context manager
|
|
89
|
+
// to be registered before it can `bindStore`. `initOpenTelemetry()` runs after integration
|
|
90
|
+
// `setupOnce`, so defer to the next tick.
|
|
91
|
+
void Promise.resolve().then(() => redisDcSubscriber.subscribeRedisDiagnosticChannels(cacheResponseHook));
|
|
84
92
|
|
|
85
93
|
// todo: implement them gradually
|
|
86
94
|
// new LegacyRedisInstrumentation({}),
|
|
@@ -118,4 +126,4 @@ const redisIntegration = core.defineIntegration(_redisIntegration);
|
|
|
118
126
|
exports.cacheResponseHook = cacheResponseHook;
|
|
119
127
|
exports.instrumentRedis = instrumentRedis;
|
|
120
128
|
exports.redisIntegration = redisIntegration;
|
|
121
|
-
//# sourceMappingURL=
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing/redis/index.ts"],"sourcesContent":["import type { Span } from '@opentelemetry/api';\nimport type { IntegrationFn } from '@sentry/core';\nimport {\n defineIntegration,\n SEMANTIC_ATTRIBUTE_CACHE_HIT,\n SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE,\n SEMANTIC_ATTRIBUTE_CACHE_KEY,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n truncate,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node-core';\nimport type { IORedisCommandArgs } from '../../../utils/redisCache';\nimport {\n calculateCacheItemSize,\n GET_COMMANDS,\n getCacheKeySafely,\n getCacheOperation,\n isInCommands,\n shouldConsiderForCache,\n} from '../../../utils/redisCache';\nimport type { IORedisResponseCustomAttributeFunction } from './vendored/types';\nimport { IORedisInstrumentation } from './vendored/ioredis-instrumentation';\nimport { RedisInstrumentation } from './vendored/redis-instrumentation';\nimport { subscribeRedisDiagnosticChannels } from './redis-dc-subscriber';\n\ninterface RedisOptions {\n /**\n * Define cache prefixes for cache keys that should be captured as a cache span.\n *\n * Setting this to, for example, `['user:']` will capture cache keys that start with `user:`.\n */\n cachePrefixes?: string[];\n /**\n * Maximum length of the cache key added to the span description. If the key exceeds this length, it will be truncated.\n *\n * Passing `0` will use the full cache key without truncation.\n *\n * By default, the full cache key is used.\n */\n maxCacheKeyLength?: number;\n}\n\nconst INTEGRATION_NAME = 'Redis';\n\n/* Only exported for testing purposes */\nexport let _redisOptions: RedisOptions = {};\n\n/* Only exported for testing purposes */\nexport const cacheResponseHook: IORedisResponseCustomAttributeFunction = (\n span: Span,\n redisCommand: string,\n cmdArgs: IORedisCommandArgs,\n response: unknown,\n) => {\n const safeKey = getCacheKeySafely(redisCommand, cmdArgs);\n const cacheOperation = getCacheOperation(redisCommand);\n\n if (\n !safeKey ||\n !cacheOperation ||\n !_redisOptions.cachePrefixes ||\n !shouldConsiderForCache(redisCommand, safeKey, _redisOptions.cachePrefixes)\n ) {\n // not relevant for cache\n return;\n }\n\n // otel/ioredis seems to be using the old standard, as there was a change to those params: https://github.com/open-telemetry/opentelemetry-specification/issues/3199\n // We are using params based on the docs: https://opentelemetry.io/docs/specs/semconv/attributes-registry/network/\n // Fall back to stable semconv attributes (server.address/server.port) when\n // old-semconv ones are absent, eg OTEL_SEMCONV_STABILITY_OPT_IN=database\n // set for node-redis v4/v5.\n const spanData = spanToJSON(span).data;\n const networkPeerAddress = spanData['net.peer.name'] ?? spanData['server.address'];\n const networkPeerPort = spanData['net.peer.port'] ?? spanData['server.port'];\n if (networkPeerPort && networkPeerAddress) {\n span.setAttributes({ 'network.peer.address': networkPeerAddress, 'network.peer.port': networkPeerPort });\n }\n\n const cacheItemSize = calculateCacheItemSize(response);\n\n if (cacheItemSize) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE, cacheItemSize);\n }\n\n if (isInCommands(GET_COMMANDS, redisCommand) && cacheItemSize !== undefined) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, cacheItemSize > 0);\n }\n\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: cacheOperation,\n [SEMANTIC_ATTRIBUTE_CACHE_KEY]: safeKey,\n });\n\n // todo: change to string[] once EAP supports it\n const spanDescription = safeKey.join(', ');\n\n span.updateName(\n _redisOptions.maxCacheKeyLength ? truncate(spanDescription, _redisOptions.maxCacheKeyLength) : spanDescription,\n );\n};\n\nconst instrumentIORedis = generateInstrumentOnce(`${INTEGRATION_NAME}.IORedis`, () => {\n return new IORedisInstrumentation({\n responseHook: cacheResponseHook,\n });\n});\n\nconst instrumentRedisModule = generateInstrumentOnce(`${INTEGRATION_NAME}.Redis`, () => {\n return new RedisInstrumentation({\n responseHook: cacheResponseHook,\n });\n});\n\n/** To be able to preload all Redis OTel instrumentations with just one ID (\"Redis\"), all the instrumentations are generated in this one function */\nexport const instrumentRedis = Object.assign(\n (): void => {\n instrumentIORedis();\n instrumentRedisModule();\n // node-redis >= 5.12.0 publishes via diagnostics_channel. The subscriber uses\n // `@sentry/opentelemetry/tracing-channel`, which needs the Sentry OTel context manager\n // to be registered before it can `bindStore`. `initOpenTelemetry()` runs after integration\n // `setupOnce`, so defer to the next tick.\n void Promise.resolve().then(() => subscribeRedisDiagnosticChannels(cacheResponseHook));\n\n // todo: implement them gradually\n // new LegacyRedisInstrumentation({}),\n },\n { id: INTEGRATION_NAME },\n);\n\nconst _redisIntegration = ((options: RedisOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n _redisOptions = options;\n instrumentRedis();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [redis](https://www.npmjs.com/package/redis) and\n * [ioredis](https://www.npmjs.com/package/ioredis) libraries.\n *\n * For more information, see the [`redisIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/redis/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.redisIntegration()],\n * });\n * ```\n */\nexport const redisIntegration = defineIntegration(_redisIntegration);\n"],"names":["_redisOptions","getCacheKeySafely","getCacheOperation","shouldConsiderForCache","spanToJSON","calculateCacheItemSize","SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE","isInCommands","GET_COMMANDS","SEMANTIC_ATTRIBUTE_CACHE_HIT","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_CACHE_KEY","truncate","generateInstrumentOnce","IORedisInstrumentation","RedisInstrumentation","subscribeRedisDiagnosticChannels","defineIntegration"],"mappings":"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"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const tracingChannel = require('@sentry/opentelemetry/tracing-channel');
|
|
5
|
+
const redisCommon = require('./vendored/redis-common.js');
|
|
6
|
+
const semconv = require('./vendored/semconv.js');
|
|
7
|
+
|
|
8
|
+
// Channel names as published by node-redis >= 5.12.0.
|
|
9
|
+
// Hardcoded so we don't import `redis` at module-load time.
|
|
10
|
+
const CHANNEL_COMMAND = 'node-redis:command';
|
|
11
|
+
const CHANNEL_BATCH = 'node-redis:batch';
|
|
12
|
+
const CHANNEL_CONNECT = 'node-redis:connect';
|
|
13
|
+
|
|
14
|
+
const ORIGIN = 'auto.db.redis.diagnostic_channel';
|
|
15
|
+
|
|
16
|
+
const NOOP = () => {};
|
|
17
|
+
|
|
18
|
+
let subscribed = false;
|
|
19
|
+
let currentResponseHook;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Subscribe Sentry handlers to node-redis diagnostics_channel events (>= 5.12.0).
|
|
23
|
+
*
|
|
24
|
+
* Uses `@sentry/opentelemetry/tracing-channel` so OTel AsyncLocalStorage context propagates
|
|
25
|
+
* automatically via `bindStore` — without it, spans created in `start` would not become
|
|
26
|
+
* the active context for subsequent operations.
|
|
27
|
+
*
|
|
28
|
+
* Safe on every runtime that exposes `node:diagnostics_channel` (Node, Bun, Deno, Workers).
|
|
29
|
+
* In node-redis < 5.12.0 the channels are never published to, so subscribers are inert and
|
|
30
|
+
* there is no double-instrumentation against the IITM-based patcher (gated to < 5.12.0).
|
|
31
|
+
*/
|
|
32
|
+
function subscribeRedisDiagnosticChannels(responseHook) {
|
|
33
|
+
currentResponseHook = responseHook;
|
|
34
|
+
if (subscribed) return;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
setupCommandChannel();
|
|
38
|
+
setupBatchChannel();
|
|
39
|
+
setupConnectChannel();
|
|
40
|
+
subscribed = true;
|
|
41
|
+
} catch {
|
|
42
|
+
// tracingChannel from @sentry/opentelemetry requires `node:diagnostics_channel`.
|
|
43
|
+
// On runtimes where it isn't available, fail closed.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function setupCommandChannel() {
|
|
48
|
+
const channel = tracingChannel.tracingChannel(CHANNEL_COMMAND, data => {
|
|
49
|
+
// node-redis >= 5.12.0 includes the command name as args[0] in the DC payload.
|
|
50
|
+
// Strip it so serialization and cache key extraction see only the actual arguments.
|
|
51
|
+
const actualArgs = data.args.slice(1);
|
|
52
|
+
const statement = safeSerialize(data.command, actualArgs);
|
|
53
|
+
return core.startSpanManual(
|
|
54
|
+
{
|
|
55
|
+
name: `redis-${data.command}`,
|
|
56
|
+
attributes: {
|
|
57
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
|
|
58
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',
|
|
59
|
+
[semconv.ATTR_DB_SYSTEM]: semconv.DB_SYSTEM_VALUE_REDIS,
|
|
60
|
+
...(statement != null ? { [semconv.ATTR_DB_STATEMENT]: statement } : {}),
|
|
61
|
+
...(data.serverAddress != null ? { [semconv.ATTR_NET_PEER_NAME]: data.serverAddress } : {}),
|
|
62
|
+
...(data.serverPort != null ? { [semconv.ATTR_NET_PEER_PORT]: data.serverPort } : {}),
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
span => span,
|
|
66
|
+
) ;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
channel.subscribe({
|
|
70
|
+
start: NOOP,
|
|
71
|
+
asyncStart: NOOP,
|
|
72
|
+
end: NOOP,
|
|
73
|
+
asyncEnd: data => {
|
|
74
|
+
const span = data._sentrySpan;
|
|
75
|
+
// only end if error handler isn't going to
|
|
76
|
+
if (!span || data.error) return;
|
|
77
|
+
// Same slice: strip command name from args before passing to the response hook.
|
|
78
|
+
runResponseHook(span, data.command, data.args.slice(1), data.result);
|
|
79
|
+
span.end();
|
|
80
|
+
},
|
|
81
|
+
error: data => {
|
|
82
|
+
const span = data._sentrySpan;
|
|
83
|
+
if (!span) return;
|
|
84
|
+
if (data.error) {
|
|
85
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: data.error.message });
|
|
86
|
+
}
|
|
87
|
+
span.end();
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function setupBatchChannel() {
|
|
93
|
+
const channel = tracingChannel.tracingChannel(CHANNEL_BATCH, data => {
|
|
94
|
+
const operationName = data.batchMode === 'PIPELINE' ? 'PIPELINE' : 'MULTI';
|
|
95
|
+
|
|
96
|
+
return core.startSpanManual(
|
|
97
|
+
{
|
|
98
|
+
name: operationName,
|
|
99
|
+
attributes: {
|
|
100
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
|
|
101
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',
|
|
102
|
+
[semconv.ATTR_DB_SYSTEM]: semconv.DB_SYSTEM_VALUE_REDIS,
|
|
103
|
+
...(data.batchSize != null ? { 'db.redis.batch_size': data.batchSize } : {}),
|
|
104
|
+
...(data.serverAddress != null ? { [semconv.ATTR_NET_PEER_NAME]: data.serverAddress } : {}),
|
|
105
|
+
...(data.serverPort != null ? { [semconv.ATTR_NET_PEER_PORT]: data.serverPort } : {}),
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
span => span,
|
|
109
|
+
) ;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
channel.subscribe({
|
|
113
|
+
start: NOOP,
|
|
114
|
+
asyncStart: NOOP,
|
|
115
|
+
end: NOOP,
|
|
116
|
+
asyncEnd: data => {
|
|
117
|
+
// only end if the error handler isn't going to
|
|
118
|
+
if (!data.error) data._sentrySpan?.end();
|
|
119
|
+
},
|
|
120
|
+
error: data => {
|
|
121
|
+
const span = data._sentrySpan;
|
|
122
|
+
if (!span) return;
|
|
123
|
+
if (data.error) {
|
|
124
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: data.error.message });
|
|
125
|
+
}
|
|
126
|
+
span.end();
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function setupConnectChannel() {
|
|
132
|
+
const channel = tracingChannel.tracingChannel(CHANNEL_CONNECT, data => {
|
|
133
|
+
return core.startSpanManual(
|
|
134
|
+
{
|
|
135
|
+
name: 'redis-connect',
|
|
136
|
+
attributes: {
|
|
137
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
|
|
138
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis.connect',
|
|
139
|
+
[semconv.ATTR_DB_SYSTEM]: semconv.DB_SYSTEM_VALUE_REDIS,
|
|
140
|
+
...(data.serverAddress != null ? { [semconv.ATTR_NET_PEER_NAME]: data.serverAddress } : {}),
|
|
141
|
+
...(data.serverPort != null ? { [semconv.ATTR_NET_PEER_PORT]: data.serverPort } : {}),
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
span => span,
|
|
145
|
+
) ;
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
channel.subscribe({
|
|
149
|
+
start: NOOP,
|
|
150
|
+
asyncStart: NOOP,
|
|
151
|
+
end: NOOP,
|
|
152
|
+
asyncEnd: data => {
|
|
153
|
+
// only end if the error handler isn't going to
|
|
154
|
+
if (!data.error) data._sentrySpan?.end();
|
|
155
|
+
},
|
|
156
|
+
error: data => {
|
|
157
|
+
const span = data._sentrySpan;
|
|
158
|
+
if (!span) return;
|
|
159
|
+
if (data.error) {
|
|
160
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: data.error.message });
|
|
161
|
+
}
|
|
162
|
+
span.end();
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function runResponseHook(span, command, args, result) {
|
|
168
|
+
const hook = currentResponseHook;
|
|
169
|
+
if (!hook) return;
|
|
170
|
+
try {
|
|
171
|
+
hook(span, command, args , result);
|
|
172
|
+
} catch {
|
|
173
|
+
// never let user hooks break instrumentation
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function safeSerialize(command, args) {
|
|
178
|
+
try {
|
|
179
|
+
return redisCommon.defaultDbStatementSerializer(command, args);
|
|
180
|
+
} catch {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
exports.subscribeRedisDiagnosticChannels = subscribeRedisDiagnosticChannels;
|
|
186
|
+
//# sourceMappingURL=redis-dc-subscriber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-dc-subscriber.js","sources":["../../../../../src/integrations/tracing/redis/redis-dc-subscriber.ts"],"sourcesContent":["import type { Span } from '@opentelemetry/api';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startSpanManual,\n} from '@sentry/core';\nimport { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel';\nimport { defaultDbStatementSerializer } from './vendored/redis-common';\nimport {\n ATTR_DB_STATEMENT,\n ATTR_DB_SYSTEM,\n ATTR_NET_PEER_NAME,\n ATTR_NET_PEER_PORT,\n DB_SYSTEM_VALUE_REDIS,\n} from './vendored/semconv';\nimport type { IORedisInstrumentationConfig } from './vendored/types';\n\n// Channel names as published by node-redis >= 5.12.0.\n// Hardcoded so we don't import `redis` at module-load time.\nconst CHANNEL_COMMAND = 'node-redis:command';\nconst CHANNEL_BATCH = 'node-redis:batch';\nconst CHANNEL_CONNECT = 'node-redis:connect';\n\nconst ORIGIN = 'auto.db.redis.diagnostic_channel';\n\ninterface CommandData {\n command: string;\n args: Array<string | Buffer>;\n database?: number;\n serverAddress?: string;\n serverPort?: number;\n result?: unknown;\n error?: Error;\n}\n\ninterface BatchData {\n batchMode?: 'MULTI' | 'PIPELINE';\n batchSize?: number;\n database?: number;\n clientId?: string | number;\n serverAddress?: string;\n serverPort?: number;\n result?: unknown[];\n error?: Error;\n}\n\ninterface ConnectData {\n serverAddress?: string;\n serverPort?: number;\n url?: string;\n error?: Error;\n}\n\nconst NOOP = (): void => {};\n\nlet subscribed = false;\nlet currentResponseHook: IORedisInstrumentationConfig['responseHook'] | undefined;\n\n/**\n * Subscribe Sentry handlers to node-redis diagnostics_channel events (>= 5.12.0).\n *\n * Uses `@sentry/opentelemetry/tracing-channel` so OTel AsyncLocalStorage context propagates\n * automatically via `bindStore` — without it, spans created in `start` would not become\n * the active context for subsequent operations.\n *\n * Safe on every runtime that exposes `node:diagnostics_channel` (Node, Bun, Deno, Workers).\n * In node-redis < 5.12.0 the channels are never published to, so subscribers are inert and\n * there is no double-instrumentation against the IITM-based patcher (gated to < 5.12.0).\n */\nexport function subscribeRedisDiagnosticChannels(responseHook?: IORedisInstrumentationConfig['responseHook']): void {\n currentResponseHook = responseHook;\n if (subscribed) return;\n\n try {\n setupCommandChannel();\n setupBatchChannel();\n setupConnectChannel();\n subscribed = true;\n } catch {\n // tracingChannel from @sentry/opentelemetry requires `node:diagnostics_channel`.\n // On runtimes where it isn't available, fail closed.\n }\n}\n\nfunction setupCommandChannel(): void {\n const channel = tracingChannel<CommandData>(CHANNEL_COMMAND, data => {\n // node-redis >= 5.12.0 includes the command name as args[0] in the DC payload.\n // Strip it so serialization and cache key extraction see only the actual arguments.\n const actualArgs = data.args.slice(1);\n const statement = safeSerialize(data.command, actualArgs);\n return startSpanManual(\n {\n name: `redis-${data.command}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',\n [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,\n ...(statement != null ? { [ATTR_DB_STATEMENT]: statement } : {}),\n ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),\n ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),\n },\n },\n span => span,\n ) as Span;\n });\n\n channel.subscribe({\n start: NOOP,\n asyncStart: NOOP,\n end: NOOP,\n asyncEnd: data => {\n const span = data._sentrySpan;\n // only end if error handler isn't going to\n if (!span || data.error) return;\n // Same slice: strip command name from args before passing to the response hook.\n runResponseHook(span, data.command, data.args.slice(1), data.result);\n span.end();\n },\n error: data => {\n const span = data._sentrySpan;\n if (!span) return;\n if (data.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });\n }\n span.end();\n },\n });\n}\n\nfunction setupBatchChannel(): void {\n const channel = tracingChannel<BatchData>(CHANNEL_BATCH, data => {\n const operationName = data.batchMode === 'PIPELINE' ? 'PIPELINE' : 'MULTI';\n\n return startSpanManual(\n {\n name: operationName,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',\n [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,\n ...(data.batchSize != null ? { 'db.redis.batch_size': data.batchSize } : {}),\n ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),\n ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),\n },\n },\n span => span,\n ) as Span;\n });\n\n channel.subscribe({\n start: NOOP,\n asyncStart: NOOP,\n end: NOOP,\n asyncEnd: data => {\n // only end if the error handler isn't going to\n if (!data.error) data._sentrySpan?.end();\n },\n error: data => {\n const span = data._sentrySpan;\n if (!span) return;\n if (data.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });\n }\n span.end();\n },\n });\n}\n\nfunction setupConnectChannel(): void {\n const channel = tracingChannel<ConnectData>(CHANNEL_CONNECT, data => {\n return startSpanManual(\n {\n name: 'redis-connect',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis.connect',\n [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,\n ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),\n ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),\n },\n },\n span => span,\n ) as Span;\n });\n\n channel.subscribe({\n start: NOOP,\n asyncStart: NOOP,\n end: NOOP,\n asyncEnd: data => {\n // only end if the error handler isn't going to\n if (!data.error) data._sentrySpan?.end();\n },\n error: data => {\n const span = data._sentrySpan;\n if (!span) return;\n if (data.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });\n }\n span.end();\n },\n });\n}\n\nfunction runResponseHook(span: Span, command: string, args: Array<string | Buffer>, result: unknown): void {\n const hook = currentResponseHook;\n if (!hook) return;\n try {\n hook(span, command, args as unknown as Parameters<typeof hook>[2], result);\n } catch {\n // never let user hooks break instrumentation\n }\n}\n\nfunction safeSerialize(command: string, args: Array<string | Buffer>): string | undefined {\n try {\n return defaultDbStatementSerializer(command, args);\n } catch {\n return undefined;\n }\n}\n\n// Test-only helper.\nexport function _resetRedisDiagnosticChannelsForTesting(): void {\n subscribed = false;\n currentResponseHook = undefined;\n}\n\n// Suppress unused-import lint when only used in types.\nexport type { TracingChannelContextWithSpan };\n"],"names":["tracingChannel","startSpanManual","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","ATTR_DB_SYSTEM","DB_SYSTEM_VALUE_REDIS","ATTR_DB_STATEMENT","ATTR_NET_PEER_NAME","ATTR_NET_PEER_PORT","SPAN_STATUS_ERROR","defaultDbStatementSerializer"],"mappings":"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"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const api = require('@opentelemetry/api');
|
|
4
|
+
const core = require('@sentry/core');
|
|
5
|
+
const instrumentation = require('@opentelemetry/instrumentation');
|
|
6
|
+
const semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
7
|
+
const redisCommon = require('./redis-common.js');
|
|
8
|
+
const semconv = require('./semconv.js');
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Copyright The OpenTelemetry Authors
|
|
12
|
+
*
|
|
13
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
* you may not use this file except in compliance with the License.
|
|
15
|
+
* You may obtain a copy of the License at
|
|
16
|
+
*
|
|
17
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
+
*
|
|
19
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
* See the License for the specific language governing permissions and
|
|
23
|
+
* limitations under the License.
|
|
24
|
+
*
|
|
25
|
+
* NOTICE from the Sentry authors:
|
|
26
|
+
* - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/instrumentation-ioredis-v0.62.0/packages/instrumentation-ioredis
|
|
27
|
+
* - Upstream version: @opentelemetry/instrumentation-ioredis@0.62.0
|
|
28
|
+
* - Minor TypeScript adjustments for this repository's compiler settings
|
|
29
|
+
*/
|
|
30
|
+
/* eslint-disable -- vendored @opentelemetry/instrumentation-ioredis */
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
const PACKAGE_NAME = '@opentelemetry/instrumentation-ioredis';
|
|
34
|
+
const PACKAGE_VERSION = '0.62.0';
|
|
35
|
+
|
|
36
|
+
// ---- utils ----
|
|
37
|
+
|
|
38
|
+
function endSpan(span, err) {
|
|
39
|
+
if (err) {
|
|
40
|
+
span.recordException(err);
|
|
41
|
+
span.setStatus({
|
|
42
|
+
code: api.SpanStatusCode.ERROR,
|
|
43
|
+
message: err.message,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
span.end();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ---- IORedisInstrumentation ----
|
|
50
|
+
|
|
51
|
+
const DEFAULT_CONFIG = {
|
|
52
|
+
requireParentSpan: true,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
class IORedisInstrumentation extends instrumentation.InstrumentationBase {
|
|
56
|
+
|
|
57
|
+
constructor(config = {}) {
|
|
58
|
+
super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config });
|
|
59
|
+
this._setSemconvStabilityFromEnv();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_setSemconvStabilityFromEnv() {
|
|
63
|
+
this._netSemconvStability = instrumentation.semconvStabilityFromStr('http', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);
|
|
64
|
+
this._dbSemconvStability = instrumentation.semconvStabilityFromStr('database', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setConfig(config = {}) {
|
|
68
|
+
super.setConfig({ ...DEFAULT_CONFIG, ...config });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
init() {
|
|
72
|
+
return [
|
|
73
|
+
new instrumentation.InstrumentationNodeModuleDefinition(
|
|
74
|
+
'ioredis',
|
|
75
|
+
['>=2.0.0 <6'],
|
|
76
|
+
(module, moduleVersion) => {
|
|
77
|
+
const moduleExports =
|
|
78
|
+
module[Symbol.toStringTag] === 'Module'
|
|
79
|
+
? module.default // ESM
|
|
80
|
+
: module; // CommonJS
|
|
81
|
+
if (instrumentation.isWrapped(moduleExports.prototype.sendCommand)) {
|
|
82
|
+
this._unwrap(moduleExports.prototype, 'sendCommand');
|
|
83
|
+
}
|
|
84
|
+
this._wrap(moduleExports.prototype, 'sendCommand', this._patchSendCommand(moduleVersion));
|
|
85
|
+
if (instrumentation.isWrapped(moduleExports.prototype.connect)) {
|
|
86
|
+
this._unwrap(moduleExports.prototype, 'connect');
|
|
87
|
+
}
|
|
88
|
+
this._wrap(moduleExports.prototype, 'connect', this._patchConnection());
|
|
89
|
+
return module;
|
|
90
|
+
},
|
|
91
|
+
(module) => {
|
|
92
|
+
if (module === undefined) return;
|
|
93
|
+
const moduleExports =
|
|
94
|
+
module[Symbol.toStringTag] === 'Module'
|
|
95
|
+
? module.default // ESM
|
|
96
|
+
: module; // CommonJS
|
|
97
|
+
this._unwrap(moduleExports.prototype, 'sendCommand');
|
|
98
|
+
this._unwrap(moduleExports.prototype, 'connect');
|
|
99
|
+
},
|
|
100
|
+
),
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_patchSendCommand(moduleVersion) {
|
|
105
|
+
return (original) => {
|
|
106
|
+
return this._traceSendCommand(original, moduleVersion);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_patchConnection() {
|
|
111
|
+
return (original) => {
|
|
112
|
+
return this._traceConnection(original);
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_traceSendCommand(original, moduleVersion) {
|
|
117
|
+
const instrumentation$1 = this;
|
|
118
|
+
return function ( cmd) {
|
|
119
|
+
if (arguments.length < 1 || typeof cmd !== 'object') {
|
|
120
|
+
return original.apply(this, arguments);
|
|
121
|
+
}
|
|
122
|
+
const config = instrumentation$1.getConfig();
|
|
123
|
+
const dbStatementSerializer = config.dbStatementSerializer || redisCommon.defaultDbStatementSerializer;
|
|
124
|
+
const hasNoParentSpan = api.trace.getSpan(api.context.active()) === undefined;
|
|
125
|
+
if (config.requireParentSpan === true && hasNoParentSpan) {
|
|
126
|
+
return original.apply(this, arguments);
|
|
127
|
+
}
|
|
128
|
+
const attributes = {};
|
|
129
|
+
const { host, port } = this.options;
|
|
130
|
+
const dbQueryText = dbStatementSerializer(cmd.name, cmd.args);
|
|
131
|
+
if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.OLD) {
|
|
132
|
+
attributes[semconv.ATTR_DB_SYSTEM] = semconv.DB_SYSTEM_VALUE_REDIS;
|
|
133
|
+
attributes[semconv.ATTR_DB_STATEMENT] = dbQueryText;
|
|
134
|
+
attributes[semconv.ATTR_DB_CONNECTION_STRING] = `redis://${host}:${port}`;
|
|
135
|
+
}
|
|
136
|
+
if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.STABLE) {
|
|
137
|
+
attributes[semanticConventions.ATTR_DB_SYSTEM_NAME] = semconv.DB_SYSTEM_NAME_VALUE_REDIS;
|
|
138
|
+
attributes[semanticConventions.ATTR_DB_QUERY_TEXT] = dbQueryText;
|
|
139
|
+
}
|
|
140
|
+
if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.OLD) {
|
|
141
|
+
attributes[semconv.ATTR_NET_PEER_NAME] = host;
|
|
142
|
+
attributes[semconv.ATTR_NET_PEER_PORT] = port;
|
|
143
|
+
}
|
|
144
|
+
if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.STABLE) {
|
|
145
|
+
attributes[semanticConventions.ATTR_SERVER_ADDRESS] = host;
|
|
146
|
+
attributes[semanticConventions.ATTR_SERVER_PORT] = port;
|
|
147
|
+
}
|
|
148
|
+
attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis';
|
|
149
|
+
const span = instrumentation$1.tracer.startSpan(cmd.name, {
|
|
150
|
+
kind: api.SpanKind.CLIENT,
|
|
151
|
+
attributes,
|
|
152
|
+
});
|
|
153
|
+
const { requestHook } = config;
|
|
154
|
+
if (requestHook) {
|
|
155
|
+
instrumentation.safeExecuteInTheMiddle(
|
|
156
|
+
() =>
|
|
157
|
+
requestHook(span, {
|
|
158
|
+
moduleVersion,
|
|
159
|
+
cmdName: cmd.name,
|
|
160
|
+
cmdArgs: cmd.args,
|
|
161
|
+
}),
|
|
162
|
+
(e) => {
|
|
163
|
+
if (e) {
|
|
164
|
+
api.diag.error('ioredis instrumentation: request hook failed', e);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
true,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const result = original.apply(this, arguments);
|
|
172
|
+
const origResolve = cmd.resolve;
|
|
173
|
+
cmd.resolve = function (result) {
|
|
174
|
+
instrumentation.safeExecuteInTheMiddle(
|
|
175
|
+
() => config.responseHook?.(span, cmd.name, cmd.args, result),
|
|
176
|
+
(e) => {
|
|
177
|
+
if (e) {
|
|
178
|
+
api.diag.error('ioredis instrumentation: response hook failed', e);
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
true,
|
|
182
|
+
);
|
|
183
|
+
endSpan(span, null);
|
|
184
|
+
origResolve(result);
|
|
185
|
+
};
|
|
186
|
+
const origReject = cmd.reject;
|
|
187
|
+
cmd.reject = function (err) {
|
|
188
|
+
endSpan(span, err);
|
|
189
|
+
origReject(err);
|
|
190
|
+
};
|
|
191
|
+
return result;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
endSpan(span, error );
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
_traceConnection(original) {
|
|
200
|
+
const instrumentation$1 = this;
|
|
201
|
+
return function () {
|
|
202
|
+
const hasNoParentSpan = api.trace.getSpan(api.context.active()) === undefined;
|
|
203
|
+
if (instrumentation$1.getConfig().requireParentSpan === true && hasNoParentSpan) {
|
|
204
|
+
return original.apply(this, arguments);
|
|
205
|
+
}
|
|
206
|
+
const attributes = {};
|
|
207
|
+
const { host, port } = this.options;
|
|
208
|
+
if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.OLD) {
|
|
209
|
+
attributes[semconv.ATTR_DB_SYSTEM] = semconv.DB_SYSTEM_VALUE_REDIS;
|
|
210
|
+
attributes[semconv.ATTR_DB_STATEMENT] = 'connect';
|
|
211
|
+
attributes[semconv.ATTR_DB_CONNECTION_STRING] = `redis://${host}:${port}`;
|
|
212
|
+
}
|
|
213
|
+
if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.STABLE) {
|
|
214
|
+
attributes[semanticConventions.ATTR_DB_SYSTEM_NAME] = semconv.DB_SYSTEM_NAME_VALUE_REDIS;
|
|
215
|
+
attributes[semanticConventions.ATTR_DB_QUERY_TEXT] = 'connect';
|
|
216
|
+
}
|
|
217
|
+
if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.OLD) {
|
|
218
|
+
attributes[semconv.ATTR_NET_PEER_NAME] = host;
|
|
219
|
+
attributes[semconv.ATTR_NET_PEER_PORT] = port;
|
|
220
|
+
}
|
|
221
|
+
if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.STABLE) {
|
|
222
|
+
attributes[semanticConventions.ATTR_SERVER_ADDRESS] = host;
|
|
223
|
+
attributes[semanticConventions.ATTR_SERVER_PORT] = port;
|
|
224
|
+
}
|
|
225
|
+
attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis';
|
|
226
|
+
const span = instrumentation$1.tracer.startSpan('connect', {
|
|
227
|
+
kind: api.SpanKind.CLIENT,
|
|
228
|
+
attributes,
|
|
229
|
+
});
|
|
230
|
+
try {
|
|
231
|
+
const result = original.apply(this, arguments);
|
|
232
|
+
if (typeof result?.then === 'function') {
|
|
233
|
+
return result.then(
|
|
234
|
+
(value) => {
|
|
235
|
+
endSpan(span, null);
|
|
236
|
+
return value;
|
|
237
|
+
},
|
|
238
|
+
(error) => {
|
|
239
|
+
endSpan(span, error);
|
|
240
|
+
return Promise.reject(error);
|
|
241
|
+
},
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
endSpan(span, null);
|
|
245
|
+
return result;
|
|
246
|
+
} catch (error) {
|
|
247
|
+
endSpan(span, error );
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
exports.IORedisInstrumentation = IORedisInstrumentation;
|
|
255
|
+
//# sourceMappingURL=ioredis-instrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ioredis-instrumentation.js","sources":["../../../../../../src/integrations/tracing/redis/vendored/ioredis-instrumentation.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-ioredis-v0.62.0/packages/instrumentation-ioredis\n * - Upstream version: @opentelemetry/instrumentation-ioredis@0.62.0\n * - Minor TypeScript adjustments for this repository's compiler settings\n */\n/* eslint-disable -- vendored @opentelemetry/instrumentation-ioredis */\n\nimport { context, diag, SpanKind, SpanStatusCode, trace } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/api';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n isWrapped,\n safeExecuteInTheMiddle,\n SemconvStability,\n semconvStabilityFromStr,\n} from '@opentelemetry/instrumentation';\nimport {\n ATTR_DB_QUERY_TEXT,\n ATTR_DB_SYSTEM_NAME,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n} from '@opentelemetry/semantic-conventions';\n\nimport { defaultDbStatementSerializer } from './redis-common';\nimport {\n ATTR_DB_CONNECTION_STRING,\n ATTR_DB_STATEMENT,\n ATTR_DB_SYSTEM,\n ATTR_NET_PEER_NAME,\n ATTR_NET_PEER_PORT,\n DB_SYSTEM_NAME_VALUE_REDIS,\n DB_SYSTEM_VALUE_REDIS,\n} from './semconv';\nimport type { IORedisInstrumentationConfig } from './types';\n\nconst PACKAGE_NAME = '@opentelemetry/instrumentation-ioredis';\nconst PACKAGE_VERSION = '0.62.0';\n\n// ---- utils ----\n\nfunction endSpan(span: Span, err: Error | null | undefined): void {\n if (err) {\n span.recordException(err);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err.message,\n });\n }\n span.end();\n}\n\n// ---- IORedisInstrumentation ----\n\nconst DEFAULT_CONFIG: IORedisInstrumentationConfig = {\n requireParentSpan: true,\n};\n\nexport class IORedisInstrumentation extends InstrumentationBase<IORedisInstrumentationConfig> {\n _netSemconvStability!: SemconvStability;\n _dbSemconvStability!: SemconvStability;\n\n constructor(config: IORedisInstrumentationConfig = {}) {\n super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config });\n this._setSemconvStabilityFromEnv();\n }\n\n _setSemconvStabilityFromEnv(): void {\n this._netSemconvStability = semconvStabilityFromStr('http', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);\n this._dbSemconvStability = semconvStabilityFromStr('database', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']);\n }\n\n override setConfig(config: IORedisInstrumentationConfig = {}): void {\n super.setConfig({ ...DEFAULT_CONFIG, ...config });\n }\n\n init() {\n return [\n new InstrumentationNodeModuleDefinition(\n 'ioredis',\n ['>=2.0.0 <6'],\n (module: any, moduleVersion?: string) => {\n const moduleExports =\n module[Symbol.toStringTag] === 'Module'\n ? module.default // ESM\n : module; // CommonJS\n if (isWrapped(moduleExports.prototype.sendCommand)) {\n this._unwrap(moduleExports.prototype, 'sendCommand');\n }\n this._wrap(moduleExports.prototype, 'sendCommand', this._patchSendCommand(moduleVersion));\n if (isWrapped(moduleExports.prototype.connect)) {\n this._unwrap(moduleExports.prototype, 'connect');\n }\n this._wrap(moduleExports.prototype, 'connect', this._patchConnection());\n return module;\n },\n (module: any) => {\n if (module === undefined) return;\n const moduleExports =\n module[Symbol.toStringTag] === 'Module'\n ? module.default // ESM\n : module; // CommonJS\n this._unwrap(moduleExports.prototype, 'sendCommand');\n this._unwrap(moduleExports.prototype, 'connect');\n },\n ),\n ];\n }\n\n private _patchSendCommand(moduleVersion?: string) {\n return (original: Function) => {\n return this._traceSendCommand(original, moduleVersion);\n };\n }\n\n private _patchConnection() {\n return (original: Function) => {\n return this._traceConnection(original);\n };\n }\n\n private _traceSendCommand(original: Function, moduleVersion?: string) {\n const instrumentation = this;\n return function (this: any, cmd: any) {\n if (arguments.length < 1 || typeof cmd !== 'object') {\n return original.apply(this, arguments);\n }\n const config = instrumentation.getConfig();\n const dbStatementSerializer = config.dbStatementSerializer || defaultDbStatementSerializer;\n const hasNoParentSpan = trace.getSpan(context.active()) === undefined;\n if (config.requireParentSpan === true && hasNoParentSpan) {\n return original.apply(this, arguments);\n }\n const attributes: Record<string, any> = {};\n const { host, port } = this.options;\n const dbQueryText = dbStatementSerializer(cmd.name, cmd.args);\n if (instrumentation._dbSemconvStability & SemconvStability.OLD) {\n attributes[ATTR_DB_SYSTEM] = DB_SYSTEM_VALUE_REDIS;\n attributes[ATTR_DB_STATEMENT] = dbQueryText;\n attributes[ATTR_DB_CONNECTION_STRING] = `redis://${host}:${port}`;\n }\n if (instrumentation._dbSemconvStability & SemconvStability.STABLE) {\n attributes[ATTR_DB_SYSTEM_NAME] = DB_SYSTEM_NAME_VALUE_REDIS;\n attributes[ATTR_DB_QUERY_TEXT] = dbQueryText;\n }\n if (instrumentation._netSemconvStability & SemconvStability.OLD) {\n attributes[ATTR_NET_PEER_NAME] = host;\n attributes[ATTR_NET_PEER_PORT] = port;\n }\n if (instrumentation._netSemconvStability & SemconvStability.STABLE) {\n attributes[ATTR_SERVER_ADDRESS] = host;\n attributes[ATTR_SERVER_PORT] = port;\n }\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis';\n const span = instrumentation.tracer.startSpan(cmd.name, {\n kind: SpanKind.CLIENT,\n attributes,\n });\n const { requestHook } = config;\n if (requestHook) {\n safeExecuteInTheMiddle(\n () =>\n requestHook(span, {\n moduleVersion,\n cmdName: cmd.name,\n cmdArgs: cmd.args,\n }),\n (e: Error | undefined) => {\n if (e) {\n diag.error('ioredis instrumentation: request hook failed', e);\n }\n },\n true,\n );\n }\n try {\n const result = original.apply(this, arguments);\n const origResolve = cmd.resolve;\n cmd.resolve = function (result: unknown) {\n safeExecuteInTheMiddle(\n () => config.responseHook?.(span, cmd.name, cmd.args, result),\n (e: Error | undefined) => {\n if (e) {\n diag.error('ioredis instrumentation: response hook failed', e);\n }\n },\n true,\n );\n endSpan(span, null);\n origResolve(result);\n };\n const origReject = cmd.reject;\n cmd.reject = function (err: Error) {\n endSpan(span, err);\n origReject(err);\n };\n return result;\n } catch (error) {\n endSpan(span, error as Error);\n throw error;\n }\n };\n }\n\n private _traceConnection(original: Function) {\n const instrumentation = this;\n return function (this: any) {\n const hasNoParentSpan = trace.getSpan(context.active()) === undefined;\n if (instrumentation.getConfig().requireParentSpan === true && hasNoParentSpan) {\n return original.apply(this, arguments);\n }\n const attributes: Record<string, any> = {};\n const { host, port } = this.options;\n if (instrumentation._dbSemconvStability & SemconvStability.OLD) {\n attributes[ATTR_DB_SYSTEM] = DB_SYSTEM_VALUE_REDIS;\n attributes[ATTR_DB_STATEMENT] = 'connect';\n attributes[ATTR_DB_CONNECTION_STRING] = `redis://${host}:${port}`;\n }\n if (instrumentation._dbSemconvStability & SemconvStability.STABLE) {\n attributes[ATTR_DB_SYSTEM_NAME] = DB_SYSTEM_NAME_VALUE_REDIS;\n attributes[ATTR_DB_QUERY_TEXT] = 'connect';\n }\n if (instrumentation._netSemconvStability & SemconvStability.OLD) {\n attributes[ATTR_NET_PEER_NAME] = host;\n attributes[ATTR_NET_PEER_PORT] = port;\n }\n if (instrumentation._netSemconvStability & SemconvStability.STABLE) {\n attributes[ATTR_SERVER_ADDRESS] = host;\n attributes[ATTR_SERVER_PORT] = port;\n }\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis';\n const span = instrumentation.tracer.startSpan('connect', {\n kind: SpanKind.CLIENT,\n attributes,\n });\n try {\n const result = original.apply(this, arguments);\n if (typeof result?.then === 'function') {\n return result.then(\n (value: unknown) => {\n endSpan(span, null);\n return value;\n },\n (error: Error) => {\n endSpan(span, error);\n return Promise.reject(error);\n },\n );\n }\n endSpan(span, null);\n return result;\n } catch (error) {\n endSpan(span, error as Error);\n throw error;\n }\n };\n }\n}\n"],"names":["SpanStatusCode","InstrumentationBase","semconvStabilityFromStr","InstrumentationNodeModuleDefinition","isWrapped","instrumentation","defaultDbStatementSerializer","trace","context","SemconvStability","ATTR_DB_SYSTEM","DB_SYSTEM_VALUE_REDIS","ATTR_DB_STATEMENT","ATTR_DB_CONNECTION_STRING","ATTR_DB_SYSTEM_NAME","DB_SYSTEM_NAME_VALUE_REDIS","ATTR_DB_QUERY_TEXT","ATTR_NET_PEER_NAME","ATTR_NET_PEER_PORT","ATTR_SERVER_ADDRESS","ATTR_SERVER_PORT","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SpanKind","safeExecuteInTheMiddle","diag"],"mappings":"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"}
|