@saidsef/tracing-node 3.12.1 → 3.13.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 (2) hide show
  1. package/libs/index.mjs +49 -106
  2. package/package.json +1 -1
package/libs/index.mjs CHANGED
@@ -109,61 +109,24 @@ export function setupTracing(options = {}) {
109
109
  return req.url.startsWith('/metrics') || req.url.startsWith('/healthz');
110
110
  };
111
111
 
112
- // Helper function to extract hostname from various request formats
113
- const extractHostname = (request) => {
114
- // Try to get hostname from various possible locations
115
- let hostname = request?.hostname || request?.host || '';
112
+ // Hook to set peer service name for outgoing requests
113
+ const applyCustomAttributesOnSpan = (span, request) => {
114
+ const url = request?.url || request?.uri || '';
115
+ const hostname = request?.hostname || request?.host || '';
116
116
 
117
- // If not found, try to parse from URL
118
- if (!hostname && request?.url) {
119
- try {
120
- const urlObj = new URL(request.url);
121
- hostname = urlObj.hostname;
122
- } catch {
123
- // If URL parsing fails, try to extract from request options
124
- if (request?.options?.hostname) {
125
- hostname = request.options.hostname;
126
- } else if (request?.options?.host) {
127
- hostname = request.options.host;
128
- }
129
- }
130
- }
131
-
132
- return hostname;
133
- };
134
-
135
- // Helper function to determine peer service name from hostname/URL
136
- const getPeerServiceName = (hostname, url = '') => {
137
- const lowerHostname = hostname.toLowerCase();
138
- const lowerUrl = url.toLowerCase();
139
-
140
- // Check for known service patterns
141
- if (lowerHostname.includes('elasticsearch') || lowerUrl.includes('elasticsearch') ||
142
- lowerHostname.includes(':9200') || lowerUrl.includes(':9200')) {
143
- return 'elasticsearch';
144
- }
145
-
146
- if (lowerHostname.includes('redis') || lowerUrl.includes('redis') ||
147
- lowerHostname.includes(':6379') || lowerUrl.includes(':6379')) {
148
- return 'redis';
149
- }
150
-
151
- // Extract service name from hostname patterns like:
152
- // - service-name.namespace.svc.cluster.local
153
- // - service-name.namespace.svc
154
- // - api.service-name.com
155
- if (lowerHostname.includes('.svc')) {
156
- const parts = lowerHostname.split('.');
157
- return parts[0]; // Return the service name part
117
+ // Detect Elasticsearch endpoints
118
+ if (hostname.includes('elasticsearch') || url.includes('elasticsearch') ||
119
+ hostname.includes(':9200') || url.includes(':9200')) {
120
+ span.setAttribute('peer.service', 'elasticsearch');
121
+ span.setAttribute('db.system', 'elasticsearch');
158
122
  }
159
123
 
160
- // For external domains, use the hostname without 'www'
161
- if (lowerHostname.startsWith('www.')) {
162
- return lowerHostname.substring(4);
124
+ // Detect Redis endpoints
125
+ if (hostname.includes('redis') || url.includes('redis') ||
126
+ hostname.includes(':6379') || url.includes(':6379')) {
127
+ span.setAttribute('peer.service', 'redis');
128
+ span.setAttribute('db.system', 'redis');
163
129
  }
164
-
165
- // Return the full hostname as the service name
166
- return hostname || 'unknown';
167
130
  };
168
131
 
169
132
  // Register instrumentations
@@ -171,39 +134,8 @@ export function setupTracing(options = {}) {
171
134
  new HttpInstrumentation({
172
135
  serverName: serviceName,
173
136
  ignoreIncomingRequestHook,
174
- requireParentforOutgoingSpans: false,
175
- requireParentforIncomingSpans: false,
137
+ applyCustomAttributesOnSpan,
176
138
  requestHook: (span, request) => {
177
- const spanKind = span.kind;
178
- const isClientSpan = spanKind === 3; // SpanKind.CLIENT = 3
179
-
180
- // For CLIENT spans (outgoing requests), add peer service attributes
181
- if (isClientSpan) {
182
- const hostname = extractHostname(request);
183
- const url = request?.url || request?.uri || '';
184
-
185
- if (hostname) {
186
- const peerService = getPeerServiceName(hostname, url);
187
-
188
- // Set attributes for service graph
189
- span.setAttribute('peer.service', peerService);
190
- span.setAttribute('net.peer.name', hostname);
191
-
192
- // Add port if available
193
- const port = request?.port || request?.options?.port;
194
- if (port) {
195
- span.setAttribute('net.peer.port', parseInt(port, 10));
196
- }
197
-
198
- // Add method for better span naming
199
- const method = request?.method || 'GET';
200
- span.setAttribute('http.method', method.toUpperCase());
201
-
202
- // Update span name for clarity
203
- span.updateName(`${method.toUpperCase()} ${peerService}`);
204
- }
205
- }
206
-
207
139
  // Enrich spans with additional HTTP request attributes
208
140
  if (request.headers) {
209
141
  const userAgent = request.headers['user-agent'];
@@ -309,22 +241,45 @@ export function setupTracing(options = {}) {
309
241
  }),
310
242
  new IORedisInstrumentation({
311
243
  requireParentSpan: false,
312
- requestHook: (span) => {
244
+ requestHook: (span, cmdName, cmdArgs) => {
313
245
  // Set peer.service for service graph visualization - CRITICAL for Tempo
314
- // This must be set in requestHook to ensure it's available for service graph
315
246
  span.setAttribute('peer.service', 'redis');
316
247
  span.setAttribute('db.system', 'redis');
317
-
318
- // Ensure span kind is CLIENT for proper service graph visualization
319
- span.setAttribute('span.kind', 'CLIENT');
320
-
321
- // Add additional attributes for better service graph visualization
322
- span.setAttribute('db.connection_string', 'redis');
323
- span.setAttribute('net.peer.name', 'redis');
248
+
249
+ // Add command details for better observability
250
+ if (cmdName) {
251
+ span.setAttribute('db.operation', cmdName.toUpperCase());
252
+ span.updateName(`redis.${cmdName.toUpperCase()}`);
253
+ }
254
+
255
+ // Add key information (first argument is usually the key)
256
+ if (cmdArgs && cmdArgs.length > 0) {
257
+ span.setAttribute('db.redis.key', String(cmdArgs[0]));
258
+
259
+ // For operations with multiple keys or complex args
260
+ if (cmdArgs.length > 1) {
261
+ span.setAttribute('db.redis.args_count', cmdArgs.length);
262
+ }
263
+ }
324
264
  },
325
- responseHook: (span) => {
265
+ responseHook: (span, cmdName, cmdArgs, response) => {
326
266
  // Ensure peer.service persists through response
327
267
  span.setAttribute('peer.service', 'redis');
268
+
269
+ // Add command details for better observability
270
+ if (cmdName) {
271
+ span.setAttribute('db.operation', cmdName.toUpperCase());
272
+ }
273
+
274
+ // Log response size if available
275
+ if (response !== undefined && response !== null) {
276
+ const responseType = typeof response;
277
+ span.setAttribute('db.response.type', responseType);
278
+
279
+ if (Array.isArray(response)) {
280
+ span.setAttribute('db.response.count', response.length);
281
+ }
282
+ }
328
283
  },
329
284
  dbStatementSerializer: (cmdName, cmdArgs) => {
330
285
  // Serialize command for better observability (limit arg length to avoid huge spans)
@@ -335,19 +290,7 @@ export function setupTracing(options = {}) {
335
290
  return `${cmdName} ${args.join(' ')}`;
336
291
  },
337
292
  }),
338
- new ElasticsearchInstrumentation({
339
- suppressInternalInstrumentation: true,
340
- requestHook: (span) => {
341
- // Set peer.service for service graph visualization - CRITICAL for Tempo
342
- span.setAttribute('peer.service', 'elasticsearch');
343
- span.setAttribute('db.system', 'elasticsearch');
344
- },
345
- responseHook: (span) => {
346
- // Ensure peer.service persists through response
347
- span.setAttribute('peer.service', 'elasticsearch');
348
- span.setAttribute('db.system', 'elasticsearch');
349
- },
350
- }),
293
+ new ElasticsearchInstrumentation(),
351
294
  ];
352
295
 
353
296
  if (enableFsInstrumentation) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saidsef/tracing-node",
3
- "version": "3.12.1",
3
+ "version": "3.13.0",
4
4
  "description": "tracing NodeJS - Wrapper for OpenTelemetry instrumentation packages",
5
5
  "main": "libs/index.mjs",
6
6
  "scripts": {