@justanalyticsapp/node 0.1.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/dist/client.d.ts +286 -0
- package/dist/client.js +681 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +126 -0
- package/dist/context.js +170 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +135 -0
- package/dist/errors.js +180 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +314 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/express.d.ts +77 -0
- package/dist/integrations/express.js +87 -0
- package/dist/integrations/express.js.map +1 -0
- package/dist/integrations/http.d.ts +129 -0
- package/dist/integrations/http.js +465 -0
- package/dist/integrations/http.js.map +1 -0
- package/dist/integrations/metrics.d.ts +110 -0
- package/dist/integrations/metrics.js +313 -0
- package/dist/integrations/metrics.js.map +1 -0
- package/dist/integrations/next.d.ts +252 -0
- package/dist/integrations/next.js +480 -0
- package/dist/integrations/next.js.map +1 -0
- package/dist/integrations/pg.d.ts +169 -0
- package/dist/integrations/pg.js +616 -0
- package/dist/integrations/pg.js.map +1 -0
- package/dist/integrations/pino.d.ts +52 -0
- package/dist/integrations/pino.js +153 -0
- package/dist/integrations/pino.js.map +1 -0
- package/dist/integrations/redis.d.ts +190 -0
- package/dist/integrations/redis.js +597 -0
- package/dist/integrations/redis.js.map +1 -0
- package/dist/integrations/winston.d.ts +48 -0
- package/dist/integrations/winston.js +99 -0
- package/dist/integrations/winston.js.map +1 -0
- package/dist/logger.d.ts +148 -0
- package/dist/logger.js +162 -0
- package/dist/logger.js.map +1 -0
- package/dist/span.d.ts +192 -0
- package/dist/span.js +197 -0
- package/dist/span.js.map +1 -0
- package/dist/transport.d.ts +246 -0
- package/dist/transport.js +654 -0
- package/dist/transport.js.map +1 -0
- package/dist/utils/headers.d.ts +60 -0
- package/dist/utils/headers.js +93 -0
- package/dist/utils/headers.js.map +1 -0
- package/dist/utils/id.d.ts +23 -0
- package/dist/utils/id.js +36 -0
- package/dist/utils/id.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file packages/node-sdk/src/integrations/redis.ts
|
|
4
|
+
* @description Redis auto-instrumentation integration for the JustAnalytics Node.js SDK.
|
|
5
|
+
*
|
|
6
|
+
* Implements Story 040 - Redis Auto-Instrumentation
|
|
7
|
+
*
|
|
8
|
+
* Monkey-patches `ioredis` (Redis.prototype.sendCommand) and/or `@redis/client`
|
|
9
|
+
* (Commander.prototype.sendCommand) to automatically create `redis.command` spans
|
|
10
|
+
* for all Redis operations. This captures all Redis traffic regardless of which
|
|
11
|
+
* higher-level abstraction the developer uses.
|
|
12
|
+
*
|
|
13
|
+
* Follows the same monkey-patching pattern established in Story 036 (HTTP Auto-Instrumentation)
|
|
14
|
+
* and Story 039 (PostgreSQL Auto-Instrumentation):
|
|
15
|
+
* - Integration class with `enable()`/`disable()` lifecycle methods
|
|
16
|
+
* - Original function preservation for clean teardown
|
|
17
|
+
* - Integration with AsyncLocalStorage context for automatic parent-child span relationships
|
|
18
|
+
* - Fail-open design: if instrumentation code fails, the original command executes normally
|
|
19
|
+
*
|
|
20
|
+
* CRITICAL SECURITY: Redis values are NEVER captured in span attributes.
|
|
21
|
+
* Only command name + key name(s) are recorded in `db.statement`.
|
|
22
|
+
*
|
|
23
|
+
* References:
|
|
24
|
+
* - OpenTelemetry Database Semantic Conventions (db.system, db.statement, etc.)
|
|
25
|
+
* - Story 035 - Node.js SDK Core (Span, context, transport)
|
|
26
|
+
* - Story 036 - HTTP Auto-Instrumentation (integration pattern)
|
|
27
|
+
* - Story 039 - PostgreSQL Auto-Instrumentation (database integration pattern)
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.RedisIntegration = void 0;
|
|
31
|
+
exports.formatRedisStatement = formatRedisStatement;
|
|
32
|
+
exports.sanitizeRedisConnectionString = sanitizeRedisConnectionString;
|
|
33
|
+
const span_1 = require("../span");
|
|
34
|
+
const context_1 = require("../context");
|
|
35
|
+
const id_1 = require("../utils/id");
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Command Classification Maps
|
|
38
|
+
// ============================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Commands where the first argument is NOT a key (no key extraction needed).
|
|
41
|
+
* These commands take no key argument or their first arg has special meaning.
|
|
42
|
+
*/
|
|
43
|
+
const NO_KEY_COMMANDS = new Set([
|
|
44
|
+
'PING', 'INFO', 'DBSIZE', 'FLUSHDB', 'FLUSHALL', 'TIME', 'QUIT',
|
|
45
|
+
'AUTH', 'SELECT', 'CONFIG', 'CLIENT', 'CLUSTER', 'DEBUG', 'MULTI',
|
|
46
|
+
'EXEC', 'DISCARD', 'WATCH', 'UNWATCH', 'SUBSCRIBE', 'UNSUBSCRIBE',
|
|
47
|
+
'PSUBSCRIBE', 'PUNSUBSCRIBE', 'PUBLISH', 'SLOWLOG', 'COMMAND',
|
|
48
|
+
'OBJECT', 'SCRIPT', 'MEMORY', 'MODULE', 'WAIT', 'SAVE', 'BGSAVE',
|
|
49
|
+
'BGREWRITEAOF', 'LASTSAVE', 'SHUTDOWN',
|
|
50
|
+
]);
|
|
51
|
+
/**
|
|
52
|
+
* Commands where only the key argument(s) should be included
|
|
53
|
+
* (all subsequent args are values and must be stripped).
|
|
54
|
+
* Map of command name -> number of key arguments.
|
|
55
|
+
*
|
|
56
|
+
* Special values:
|
|
57
|
+
* - `-1`: All args are keys (e.g., MGET, DEL with multiple keys)
|
|
58
|
+
* - `-2`: Alternating key/value pairs (e.g., MSET key1 val1 key2 val2) - extract keys only
|
|
59
|
+
* - `0`: Command with no key args
|
|
60
|
+
* - `N > 0`: Fixed number of key/field args to include
|
|
61
|
+
*
|
|
62
|
+
* For commands not in this map, only the first argument (key) is included.
|
|
63
|
+
*/
|
|
64
|
+
const KEY_ONLY_COMMANDS = {
|
|
65
|
+
// Single-key commands: include 1 key
|
|
66
|
+
'GET': 1, 'SET': 1, 'DEL': -1, 'EXISTS': -1, 'EXPIRE': 1,
|
|
67
|
+
'EXPIREAT': 1, 'TTL': 1, 'PTTL': 1, 'TYPE': 1, 'PERSIST': 1,
|
|
68
|
+
'INCR': 1, 'INCRBY': 1, 'INCRBYFLOAT': 1, 'DECR': 1, 'DECRBY': 1,
|
|
69
|
+
'APPEND': 1, 'STRLEN': 1, 'GETRANGE': 1, 'SETRANGE': 1, 'GETSET': 1,
|
|
70
|
+
'SETNX': 1, 'SETEX': 1, 'PSETEX': 1, 'GETDEL': 1,
|
|
71
|
+
// Multi-key commands: -1 means all args are keys
|
|
72
|
+
'MGET': -1, 'UNLINK': -1, 'TOUCH': -1,
|
|
73
|
+
'MSET': -2, // -2 = alternating key/value pairs, extract keys only
|
|
74
|
+
// Hash commands: include key + field name (2 args)
|
|
75
|
+
'HGET': 2, 'HSET': 2, 'HDEL': 2, 'HEXISTS': 2, 'HINCRBY': 2,
|
|
76
|
+
'HINCRBYFLOAT': 2, 'HLEN': 1, 'HKEYS': 1, 'HVALS': 1, 'HGETALL': 1,
|
|
77
|
+
'HMGET': -1, // key + all fields
|
|
78
|
+
'HMSET': 2, // key + first field only (rest are field/value pairs)
|
|
79
|
+
'HSETNX': 2,
|
|
80
|
+
// List commands: include key only
|
|
81
|
+
'LPUSH': 1, 'RPUSH': 1, 'LPOP': 1, 'RPOP': 1, 'LLEN': 1,
|
|
82
|
+
'LRANGE': 1, 'LINDEX': 1, 'LSET': 1, 'LREM': 1, 'LTRIM': 1,
|
|
83
|
+
'RPOPLPUSH': 2, 'LMOVE': 2, 'BLPOP': -1, 'BRPOP': -1,
|
|
84
|
+
// Set commands: include key only
|
|
85
|
+
'SADD': 1, 'SREM': 1, 'SMEMBERS': 1, 'SISMEMBER': 1, 'SCARD': 1,
|
|
86
|
+
'SPOP': 1, 'SRANDMEMBER': 1, 'SUNION': -1, 'SINTER': -1, 'SDIFF': -1,
|
|
87
|
+
// Sorted set commands: include key only
|
|
88
|
+
'ZADD': 1, 'ZREM': 1, 'ZSCORE': 1, 'ZRANK': 1, 'ZREVRANK': 1,
|
|
89
|
+
'ZRANGE': 1, 'ZRANGEBYSCORE': 1, 'ZREVRANGEBYSCORE': 1, 'ZCARD': 1,
|
|
90
|
+
'ZCOUNT': 1, 'ZINCRBY': 1, 'ZRANGEBYLEX': 1,
|
|
91
|
+
'ZUNIONSTORE': 1, 'ZINTERSTORE': 1,
|
|
92
|
+
// Stream commands
|
|
93
|
+
'XADD': 1, 'XREAD': 0, 'XRANGE': 1, 'XREVRANGE': 1, 'XLEN': 1,
|
|
94
|
+
'XINFO': 0, 'XACK': 1, 'XDEL': 1, 'XTRIM': 1,
|
|
95
|
+
// Key management
|
|
96
|
+
'RENAME': 2, 'RENAMENX': 2, 'DUMP': 1, 'RESTORE': 1,
|
|
97
|
+
'SORT': 1, 'SCAN': 0,
|
|
98
|
+
};
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Statement Formatting Utilities (exported for testing)
|
|
101
|
+
// ============================================================================
|
|
102
|
+
/**
|
|
103
|
+
* Format the db.statement attribute from a Redis command and its arguments.
|
|
104
|
+
*
|
|
105
|
+
* Rules:
|
|
106
|
+
* 1. Command name is always UPPERCASE
|
|
107
|
+
* 2. For NO_KEY_COMMANDS, statement is just the command name
|
|
108
|
+
* 3. For known commands, include only key name(s) per KEY_ONLY_COMMANDS mapping
|
|
109
|
+
* 4. For unknown commands, include only the first argument (assumed to be the key)
|
|
110
|
+
* 5. Values are NEVER included
|
|
111
|
+
* 6. Truncate to maxStatementLength
|
|
112
|
+
*
|
|
113
|
+
* @param command - Redis command name (e.g., "get", "SET", "hget")
|
|
114
|
+
* @param args - Command arguments array
|
|
115
|
+
* @param maxLength - Maximum statement length (default: 512)
|
|
116
|
+
* @returns Formatted statement (e.g., "GET user:123", "HGET cache:data field")
|
|
117
|
+
*/
|
|
118
|
+
function formatRedisStatement(command, args, maxLength = 512) {
|
|
119
|
+
try {
|
|
120
|
+
const upperCommand = command.toUpperCase();
|
|
121
|
+
// No-key commands: just the command name
|
|
122
|
+
if (NO_KEY_COMMANDS.has(upperCommand)) {
|
|
123
|
+
return upperCommand;
|
|
124
|
+
}
|
|
125
|
+
if (!args || args.length === 0) {
|
|
126
|
+
return upperCommand;
|
|
127
|
+
}
|
|
128
|
+
const keyCount = KEY_ONLY_COMMANDS[upperCommand];
|
|
129
|
+
let parts;
|
|
130
|
+
if (keyCount === undefined) {
|
|
131
|
+
// Unknown command: include first arg only (assumed key)
|
|
132
|
+
parts = [upperCommand, String(args[0])];
|
|
133
|
+
}
|
|
134
|
+
else if (keyCount === 0) {
|
|
135
|
+
// Command with no key args
|
|
136
|
+
parts = [upperCommand];
|
|
137
|
+
}
|
|
138
|
+
else if (keyCount === -1) {
|
|
139
|
+
// All args are keys (e.g., MGET, DEL with multiple keys)
|
|
140
|
+
parts = [upperCommand, ...args.map(String)];
|
|
141
|
+
}
|
|
142
|
+
else if (keyCount === -2) {
|
|
143
|
+
// Alternating key/value pairs (MSET key1 val1 key2 val2)
|
|
144
|
+
parts = [upperCommand];
|
|
145
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
146
|
+
parts.push(String(args[i]));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Fixed number of key/field args
|
|
151
|
+
parts = [upperCommand, ...args.slice(0, keyCount).map(String)];
|
|
152
|
+
}
|
|
153
|
+
let result = parts.join(' ');
|
|
154
|
+
if (result.length > maxLength) {
|
|
155
|
+
result = result.substring(0, maxLength - 3) + '...';
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// If formatting fails, return just the command name as a fallback
|
|
161
|
+
return command.toUpperCase();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function sanitizeRedisConnectionString(hostOrConnStr, port, password, db, user) {
|
|
165
|
+
// If called with only a string that looks like a redis:// URL, sanitize it
|
|
166
|
+
if (port === undefined && hostOrConnStr.startsWith('redis://')) {
|
|
167
|
+
// Replace password in redis://user:password@host:port/db format
|
|
168
|
+
return hostOrConnStr.replace(/^(redis:\/\/)([^:]+):([^@]+)(@)/, '$1$2:***$4').replace(
|
|
169
|
+
// Also handle redis://:password@host format (no user)
|
|
170
|
+
/^(redis:\/\/:)([^@]+)(@)/, '$1***$3');
|
|
171
|
+
}
|
|
172
|
+
// Build from components
|
|
173
|
+
const host = hostOrConnStr;
|
|
174
|
+
const portNum = port;
|
|
175
|
+
const protocol = 'redis://';
|
|
176
|
+
const authPart = user
|
|
177
|
+
? `${user}:***@`
|
|
178
|
+
: password
|
|
179
|
+
? `:***@`
|
|
180
|
+
: '';
|
|
181
|
+
const dbPart = db && db !== 0 ? `/${db}` : '';
|
|
182
|
+
return `${protocol}${authPart}${host}:${portNum}${dbPart}`;
|
|
183
|
+
}
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// RedisIntegration Class
|
|
186
|
+
// ============================================================================
|
|
187
|
+
/**
|
|
188
|
+
* RedisIntegration monkey-patches ioredis and/or @redis/client
|
|
189
|
+
* to auto-create redis.command spans for all Redis operations.
|
|
190
|
+
*
|
|
191
|
+
* Follows the same pattern as HttpIntegration (Story 036) and
|
|
192
|
+
* PgIntegration (Story 039):
|
|
193
|
+
* - Constructor accepts serviceName, options, onSpanEnd callback
|
|
194
|
+
* - enable() patches, disable() restores
|
|
195
|
+
* - Original functions preserved for clean teardown
|
|
196
|
+
* - Fail-open design: instrumentation failures never crash the host process
|
|
197
|
+
*
|
|
198
|
+
* Security: NEVER captures Redis values in span attributes.
|
|
199
|
+
* Only command name + key name(s) are recorded.
|
|
200
|
+
*/
|
|
201
|
+
class RedisIntegration {
|
|
202
|
+
/**
|
|
203
|
+
* Create a new RedisIntegration.
|
|
204
|
+
*
|
|
205
|
+
* @param serviceName - The service name for span attribution
|
|
206
|
+
* @param options - Integration configuration options
|
|
207
|
+
* @param onSpanEnd - Callback invoked when a span ends (enqueues to transport)
|
|
208
|
+
*/
|
|
209
|
+
constructor(serviceName, options, onSpanEnd) {
|
|
210
|
+
this._enabled = false;
|
|
211
|
+
// ioredis originals
|
|
212
|
+
this._originalIoRedisSendCommand = null;
|
|
213
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
214
|
+
this._ioRedisPrototype = null;
|
|
215
|
+
// @redis/client originals
|
|
216
|
+
this._originalNodeRedisSendCommand = null;
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
218
|
+
this._nodeRedisPrototype = null;
|
|
219
|
+
this._serviceName = serviceName;
|
|
220
|
+
this._onSpanEnd = onSpanEnd;
|
|
221
|
+
// Resolve options with defaults
|
|
222
|
+
const opts = options || {};
|
|
223
|
+
this._options = {
|
|
224
|
+
enabled: opts.enabled !== false,
|
|
225
|
+
maxStatementLength: opts.maxStatementLength ?? 512,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Activate the integration: load Redis modules and patch prototypes.
|
|
230
|
+
*
|
|
231
|
+
* Attempts to load both ioredis and @redis/client independently.
|
|
232
|
+
* If neither is installed, silently skips. If only one is installed,
|
|
233
|
+
* only that library is patched.
|
|
234
|
+
*
|
|
235
|
+
* Calling enable() when already enabled is a no-op (idempotent).
|
|
236
|
+
*/
|
|
237
|
+
enable() {
|
|
238
|
+
if (this._enabled)
|
|
239
|
+
return;
|
|
240
|
+
if (!this._options.enabled)
|
|
241
|
+
return;
|
|
242
|
+
try {
|
|
243
|
+
let patchedAny = false;
|
|
244
|
+
// Attempt to patch ioredis
|
|
245
|
+
try {
|
|
246
|
+
this._patchIoRedis();
|
|
247
|
+
if (this._ioRedisPrototype) {
|
|
248
|
+
patchedAny = true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// ioredis not available or patching failed -- silently skip
|
|
253
|
+
}
|
|
254
|
+
// Attempt to patch @redis/client
|
|
255
|
+
try {
|
|
256
|
+
this._patchNodeRedis();
|
|
257
|
+
if (this._nodeRedisPrototype) {
|
|
258
|
+
patchedAny = true;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// @redis/client not available or patching failed -- silently skip
|
|
263
|
+
}
|
|
264
|
+
if (!patchedAny) {
|
|
265
|
+
if (typeof console !== 'undefined') {
|
|
266
|
+
console.debug('[JustAnalytics] Neither ioredis nor @redis/client found. Skipping Redis auto-instrumentation.');
|
|
267
|
+
}
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
this._enabled = true;
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
// Top-level failure: restore any partial patches
|
|
274
|
+
this._restoreOriginals();
|
|
275
|
+
if (typeof console !== 'undefined') {
|
|
276
|
+
console.warn('[JustAnalytics] Failed to enable Redis integration:', error instanceof Error ? error.message : String(error));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Deactivate: restore original Redis functions.
|
|
282
|
+
*
|
|
283
|
+
* Calling disable() when not enabled is a no-op (idempotent).
|
|
284
|
+
*/
|
|
285
|
+
disable() {
|
|
286
|
+
if (!this._enabled)
|
|
287
|
+
return;
|
|
288
|
+
this._restoreOriginals();
|
|
289
|
+
this._enabled = false;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Attempt to load and patch ioredis.
|
|
293
|
+
*
|
|
294
|
+
* ioredis routes ALL commands (including pipeline/cluster) through
|
|
295
|
+
* Redis.prototype.sendCommand. By patching this one method, we capture
|
|
296
|
+
* all commands regardless of which method the developer calls.
|
|
297
|
+
*/
|
|
298
|
+
_patchIoRedis() {
|
|
299
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
300
|
+
let ioredis;
|
|
301
|
+
try {
|
|
302
|
+
ioredis = require('ioredis');
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// ioredis module is not installed -- silently skip
|
|
306
|
+
if (typeof console !== 'undefined') {
|
|
307
|
+
console.debug('[JustAnalytics] ioredis module not found. Skipping ioredis auto-instrumentation.');
|
|
308
|
+
}
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const RedisClass = ioredis.default || ioredis;
|
|
312
|
+
if (!RedisClass || !RedisClass.prototype) {
|
|
313
|
+
if (typeof console !== 'undefined') {
|
|
314
|
+
console.debug('[JustAnalytics] ioredis.Redis prototype not found. Skipping ioredis auto-instrumentation.');
|
|
315
|
+
}
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
// Store references for restoration
|
|
319
|
+
this._ioRedisPrototype = RedisClass.prototype;
|
|
320
|
+
this._originalIoRedisSendCommand = RedisClass.prototype.sendCommand;
|
|
321
|
+
// Patch sendCommand
|
|
322
|
+
RedisClass.prototype.sendCommand = this._wrapIoRedisSendCommand(this._originalIoRedisSendCommand);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Attempt to load and patch @redis/client.
|
|
326
|
+
*
|
|
327
|
+
* node-redis v4+ uses a Commander class. All commands go through
|
|
328
|
+
* sendCommand(args: string[]) where args[0] is the command name.
|
|
329
|
+
*/
|
|
330
|
+
_patchNodeRedis() {
|
|
331
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
332
|
+
let nodeRedis;
|
|
333
|
+
try {
|
|
334
|
+
nodeRedis = require('@redis/client');
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// @redis/client module is not installed -- silently skip
|
|
338
|
+
if (typeof console !== 'undefined') {
|
|
339
|
+
console.debug('[JustAnalytics] @redis/client module not found. Skipping node-redis auto-instrumentation.');
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// node-redis v4+ exposes a default Commander or client class
|
|
344
|
+
// The exact internal structure varies, so we try multiple paths defensively
|
|
345
|
+
const Commander = nodeRedis.Commander || nodeRedis.RedisClient;
|
|
346
|
+
if (Commander && Commander.prototype && Commander.prototype.sendCommand) {
|
|
347
|
+
this._nodeRedisPrototype = Commander.prototype;
|
|
348
|
+
this._originalNodeRedisSendCommand = Commander.prototype.sendCommand;
|
|
349
|
+
Commander.prototype.sendCommand = this._wrapNodeRedisSendCommand(this._originalNodeRedisSendCommand);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// Fallback: try to find sendCommand on the default export
|
|
353
|
+
if (nodeRedis.default && nodeRedis.default.prototype && nodeRedis.default.prototype.sendCommand) {
|
|
354
|
+
this._nodeRedisPrototype = nodeRedis.default.prototype;
|
|
355
|
+
this._originalNodeRedisSendCommand = nodeRedis.default.prototype.sendCommand;
|
|
356
|
+
nodeRedis.default.prototype.sendCommand = this._wrapNodeRedisSendCommand(this._originalNodeRedisSendCommand);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (typeof console !== 'undefined') {
|
|
360
|
+
console.debug('[JustAnalytics] @redis/client sendCommand method not found. Skipping node-redis auto-instrumentation.');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Restore all patched functions to their originals.
|
|
365
|
+
*/
|
|
366
|
+
_restoreOriginals() {
|
|
367
|
+
// Restore ioredis
|
|
368
|
+
if (this._ioRedisPrototype && this._originalIoRedisSendCommand) {
|
|
369
|
+
this._ioRedisPrototype.sendCommand = this._originalIoRedisSendCommand;
|
|
370
|
+
this._originalIoRedisSendCommand = null;
|
|
371
|
+
this._ioRedisPrototype = null;
|
|
372
|
+
}
|
|
373
|
+
// Restore @redis/client
|
|
374
|
+
if (this._nodeRedisPrototype && this._originalNodeRedisSendCommand) {
|
|
375
|
+
this._nodeRedisPrototype.sendCommand = this._originalNodeRedisSendCommand;
|
|
376
|
+
this._originalNodeRedisSendCommand = null;
|
|
377
|
+
this._nodeRedisPrototype = null;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Wrap ioredis Redis.prototype.sendCommand to create redis.command spans.
|
|
382
|
+
*
|
|
383
|
+
* ioredis routes ALL commands (including pipeline/cluster) through
|
|
384
|
+
* sendCommand(command: Command). The Command object has:
|
|
385
|
+
* - command.name: string (e.g., "get", "set", "hget")
|
|
386
|
+
* - command.args: unknown[] (command arguments)
|
|
387
|
+
* - command.promise: Promise (resolves/rejects when the command completes)
|
|
388
|
+
*
|
|
389
|
+
* @param original - The original sendCommand function
|
|
390
|
+
* @returns A wrapped version
|
|
391
|
+
*/
|
|
392
|
+
_wrapIoRedisSendCommand(original) {
|
|
393
|
+
const integration = this;
|
|
394
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
395
|
+
return function patchedSendCommand(...args) {
|
|
396
|
+
try {
|
|
397
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
398
|
+
const command = args[0];
|
|
399
|
+
if (!command || !command.name) {
|
|
400
|
+
return original.apply(this, args);
|
|
401
|
+
}
|
|
402
|
+
const commandName = command.name.toUpperCase();
|
|
403
|
+
const commandArgs = command.args || [];
|
|
404
|
+
// Get active span context
|
|
405
|
+
const parentSpan = (0, context_1.getActiveSpan)();
|
|
406
|
+
const traceId = parentSpan?.traceId ?? (0, id_1.generateTraceId)();
|
|
407
|
+
const parentSpanId = parentSpan?.id ?? null;
|
|
408
|
+
const statement = formatRedisStatement(commandName, commandArgs, integration._options.maxStatementLength);
|
|
409
|
+
const operationName = `redis.command ${commandName}`;
|
|
410
|
+
// Build attributes (OpenTelemetry Database Semantic Conventions)
|
|
411
|
+
const attributes = {
|
|
412
|
+
'db.system': 'redis',
|
|
413
|
+
'db.statement': statement,
|
|
414
|
+
'db.operation': commandName,
|
|
415
|
+
};
|
|
416
|
+
// Extract connection info from ioredis client instance
|
|
417
|
+
const connInfo = integration._getIoRedisConnectionInfo(this);
|
|
418
|
+
Object.assign(attributes, connInfo);
|
|
419
|
+
// Create span
|
|
420
|
+
const span = new span_1.Span({
|
|
421
|
+
operationName,
|
|
422
|
+
serviceName: integration._serviceName,
|
|
423
|
+
kind: 'client',
|
|
424
|
+
traceId,
|
|
425
|
+
parentSpanId,
|
|
426
|
+
attributes,
|
|
427
|
+
});
|
|
428
|
+
// Call original sendCommand
|
|
429
|
+
const result = original.apply(this, args);
|
|
430
|
+
// ioredis Command has a promise property
|
|
431
|
+
if (command.promise && typeof command.promise.then === 'function') {
|
|
432
|
+
command.promise.then(() => {
|
|
433
|
+
span.end();
|
|
434
|
+
integration._onSpanEnd(span);
|
|
435
|
+
}, (error) => {
|
|
436
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
437
|
+
span.end();
|
|
438
|
+
integration._onSpanEnd(span);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
// Fallback: end span immediately
|
|
443
|
+
span.end();
|
|
444
|
+
integration._onSpanEnd(span);
|
|
445
|
+
}
|
|
446
|
+
return result;
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
// If instrumentation code fails, fall through to original
|
|
450
|
+
return original.apply(this, args);
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Wrap @redis/client's sendCommand to create redis.command spans.
|
|
456
|
+
*
|
|
457
|
+
* node-redis v4+ uses a Commander class that dispatches all commands
|
|
458
|
+
* through a sendCommand method. The method signature is:
|
|
459
|
+
* sendCommand(args: string[], options?: CommandOptions): Promise<unknown>
|
|
460
|
+
*
|
|
461
|
+
* Where args[0] is the command name and args[1..] are command arguments.
|
|
462
|
+
*
|
|
463
|
+
* @param original - The original sendCommand function
|
|
464
|
+
* @returns A wrapped version
|
|
465
|
+
*/
|
|
466
|
+
_wrapNodeRedisSendCommand(original) {
|
|
467
|
+
const integration = this;
|
|
468
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
469
|
+
return function patchedSendCommand(...args) {
|
|
470
|
+
try {
|
|
471
|
+
const commandArgs = args[0];
|
|
472
|
+
if (!Array.isArray(commandArgs) || commandArgs.length === 0) {
|
|
473
|
+
return original.apply(this, args);
|
|
474
|
+
}
|
|
475
|
+
const commandName = commandArgs[0].toUpperCase();
|
|
476
|
+
const redisArgs = commandArgs.slice(1);
|
|
477
|
+
// Get active span context
|
|
478
|
+
const parentSpan = (0, context_1.getActiveSpan)();
|
|
479
|
+
const traceId = parentSpan?.traceId ?? (0, id_1.generateTraceId)();
|
|
480
|
+
const parentSpanId = parentSpan?.id ?? null;
|
|
481
|
+
const statement = formatRedisStatement(commandName, redisArgs, integration._options.maxStatementLength);
|
|
482
|
+
const operationName = `redis.command ${commandName}`;
|
|
483
|
+
// Build attributes (OpenTelemetry Database Semantic Conventions)
|
|
484
|
+
const attributes = {
|
|
485
|
+
'db.system': 'redis',
|
|
486
|
+
'db.statement': statement,
|
|
487
|
+
'db.operation': commandName,
|
|
488
|
+
};
|
|
489
|
+
// Extract connection info from @redis/client instance
|
|
490
|
+
const connInfo = integration._getNodeRedisConnectionInfo(this);
|
|
491
|
+
Object.assign(attributes, connInfo);
|
|
492
|
+
// Create span
|
|
493
|
+
const span = new span_1.Span({
|
|
494
|
+
operationName,
|
|
495
|
+
serviceName: integration._serviceName,
|
|
496
|
+
kind: 'client',
|
|
497
|
+
traceId,
|
|
498
|
+
parentSpanId,
|
|
499
|
+
attributes,
|
|
500
|
+
});
|
|
501
|
+
// Call original -- node-redis sendCommand returns a Promise
|
|
502
|
+
try {
|
|
503
|
+
const result = original.apply(this, args);
|
|
504
|
+
if (result && typeof result.then === 'function') {
|
|
505
|
+
return result.then((value) => {
|
|
506
|
+
span.end();
|
|
507
|
+
integration._onSpanEnd(span);
|
|
508
|
+
return value;
|
|
509
|
+
}, (error) => {
|
|
510
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
511
|
+
span.end();
|
|
512
|
+
integration._onSpanEnd(span);
|
|
513
|
+
throw error;
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
// Sync return (unlikely)
|
|
517
|
+
span.end();
|
|
518
|
+
integration._onSpanEnd(span);
|
|
519
|
+
return result;
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
523
|
+
span.end();
|
|
524
|
+
integration._onSpanEnd(span);
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
// If instrumentation code fails, fall through to original
|
|
530
|
+
return original.apply(this, args);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Extract connection info from an ioredis client instance.
|
|
536
|
+
*
|
|
537
|
+
* ioredis stores connection options on the instance as `this.options`.
|
|
538
|
+
*
|
|
539
|
+
* @param client - The ioredis client instance (`this` in the patched method)
|
|
540
|
+
* @returns Attributes object with connection info
|
|
541
|
+
*/
|
|
542
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
543
|
+
_getIoRedisConnectionInfo(client) {
|
|
544
|
+
const attrs = {};
|
|
545
|
+
try {
|
|
546
|
+
const options = client.options || {};
|
|
547
|
+
const host = options.host || 'localhost';
|
|
548
|
+
const port = options.port || 6379;
|
|
549
|
+
const db = options.db || 0;
|
|
550
|
+
attrs['net.peer.name'] = host;
|
|
551
|
+
attrs['net.peer.port'] = port;
|
|
552
|
+
if (db && db !== 0) {
|
|
553
|
+
attrs['db.redis.database_index'] = db;
|
|
554
|
+
}
|
|
555
|
+
// Build sanitized connection string
|
|
556
|
+
attrs['db.connection_string'] = sanitizeRedisConnectionString(host, port, options.password, db, options.username);
|
|
557
|
+
}
|
|
558
|
+
catch {
|
|
559
|
+
// If connection info extraction fails, return what we have
|
|
560
|
+
}
|
|
561
|
+
return attrs;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Extract connection info from a @redis/client instance.
|
|
565
|
+
*
|
|
566
|
+
* node-redis v4+ stores connection options in various ways depending
|
|
567
|
+
* on the version. We try multiple paths defensively.
|
|
568
|
+
*
|
|
569
|
+
* @param client - The @redis/client instance (`this` in the patched method)
|
|
570
|
+
* @returns Attributes object with connection info
|
|
571
|
+
*/
|
|
572
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
573
|
+
_getNodeRedisConnectionInfo(client) {
|
|
574
|
+
const attrs = {};
|
|
575
|
+
try {
|
|
576
|
+
// node-redis v4 stores options in various places
|
|
577
|
+
const options = client.options || client._options || {};
|
|
578
|
+
const socket = options.socket || {};
|
|
579
|
+
const host = socket.host || options.host || 'localhost';
|
|
580
|
+
const port = socket.port || options.port || 6379;
|
|
581
|
+
const db = options.database || 0;
|
|
582
|
+
attrs['net.peer.name'] = host;
|
|
583
|
+
attrs['net.peer.port'] = port;
|
|
584
|
+
if (db && db !== 0) {
|
|
585
|
+
attrs['db.redis.database_index'] = db;
|
|
586
|
+
}
|
|
587
|
+
// Build sanitized connection string
|
|
588
|
+
attrs['db.connection_string'] = sanitizeRedisConnectionString(host, port, options.password, db, options.username);
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
591
|
+
// If connection info extraction fails, return what we have
|
|
592
|
+
}
|
|
593
|
+
return attrs;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
exports.RedisIntegration = RedisIntegration;
|
|
597
|
+
//# sourceMappingURL=redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/integrations/redis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/node-sdk/src/integrations/winston.ts
|
|
3
|
+
* @description Winston transport for JustAnalytics log integration.
|
|
4
|
+
*
|
|
5
|
+
* Implements Story 046 - SDK Log Integration
|
|
6
|
+
*
|
|
7
|
+
* Pipes Winston log entries through the JustAnalytics SDK logger,
|
|
8
|
+
* automatically attaching trace context and batching for transport.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import winston from 'winston';
|
|
13
|
+
* import { JustAnalyticsWinstonTransport } from '@justanalyticsapp/node/winston';
|
|
14
|
+
*
|
|
15
|
+
* const logger = winston.createLogger({
|
|
16
|
+
* transports: [
|
|
17
|
+
* new winston.transports.Console(),
|
|
18
|
+
* new JustAnalyticsWinstonTransport(),
|
|
19
|
+
* ],
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* The transport requires `winston` and `winston-transport` as peer dependencies.
|
|
24
|
+
* Install them separately: `npm install winston winston-transport`
|
|
25
|
+
*/
|
|
26
|
+
import type { LogLevel } from '../logger';
|
|
27
|
+
/** Configuration options for the JustAnalytics Winston transport */
|
|
28
|
+
export interface JustAnalyticsWinstonTransportOptions {
|
|
29
|
+
/** Custom mapping from Winston levels to JA levels */
|
|
30
|
+
levelMap?: Record<string, LogLevel>;
|
|
31
|
+
/** Standard Winston transport options (level, silent, etc.) */
|
|
32
|
+
level?: string;
|
|
33
|
+
silent?: boolean;
|
|
34
|
+
handleExceptions?: boolean;
|
|
35
|
+
handleRejections?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Winston transport that forwards log entries to JustAnalytics.
|
|
39
|
+
*
|
|
40
|
+
* Extracts message, level, and metadata from Winston info objects
|
|
41
|
+
* and pipes them through JA.logger for batched transport with
|
|
42
|
+
* automatic trace context attachment.
|
|
43
|
+
*/
|
|
44
|
+
export declare class JustAnalyticsWinstonTransport {
|
|
45
|
+
private readonly levelMap;
|
|
46
|
+
constructor(opts?: JustAnalyticsWinstonTransportOptions);
|
|
47
|
+
log(info: any, callback: () => void): void;
|
|
48
|
+
}
|