@saidsef/tracing-node 3.12.2 → 3.13.1

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 +29 -130
  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';
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');
144
122
  }
145
123
 
146
- if (lowerHostname.includes('redis') || lowerUrl.includes('redis') ||
147
- lowerHostname.includes(':6379') || lowerUrl.includes(':6379')) {
148
- return 'redis';
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');
149
129
  }
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
158
- }
159
-
160
- // For external domains, use the hostname without 'www'
161
- if (lowerHostname.startsWith('www.')) {
162
- return lowerHostname.substring(4);
163
- }
164
-
165
- // Return the full hostname as the service name
166
- return hostname || 'unknown';
167
130
  };
168
131
 
169
132
  // Register instrumentations
@@ -171,46 +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 - CRITICAL for Tempo
189
- span.setAttribute('peer.service', peerService);
190
- span.setAttribute('net.peer.name', hostname);
191
-
192
- // Add db.system for database clients (elasticsearch, redis, etc.)
193
- if (peerService === 'elasticsearch') {
194
- span.setAttribute('db.system', 'elasticsearch');
195
- } else if (peerService === 'redis') {
196
- span.setAttribute('db.system', 'redis');
197
- }
198
-
199
- // Add port if available
200
- const port = request?.port || request?.options?.port;
201
- if (port) {
202
- span.setAttribute('net.peer.port', parseInt(port, 10));
203
- }
204
-
205
- // Add method for better span naming
206
- const method = request?.method || 'GET';
207
- span.setAttribute('http.method', method.toUpperCase());
208
-
209
- // Update span name for clarity
210
- span.updateName(`${method.toUpperCase()} ${peerService}`);
211
- }
212
- }
213
-
214
139
  // Enrich spans with additional HTTP request attributes
215
140
  if (request.headers) {
216
141
  const userAgent = request.headers['user-agent'];
@@ -320,6 +245,13 @@ export function setupTracing(options = {}) {
320
245
  // Set peer.service for service graph visualization - CRITICAL for Tempo
321
246
  span.setAttribute('peer.service', 'redis');
322
247
  span.setAttribute('db.system', 'redis');
248
+
249
+ // CRITICAL: Ensure span kind is CLIENT for service graph
250
+ span.setAttribute('span.kind', 'CLIENT');
251
+
252
+ // Add network peer attributes (helps Tempo identify the service)
253
+ span.setAttribute('net.peer.name', 'redis');
254
+ span.setAttribute('db.connection_string', 'redis');
323
255
 
324
256
  // Add command details for better observability
325
257
  if (cmdName) {
@@ -340,6 +272,12 @@ export function setupTracing(options = {}) {
340
272
  responseHook: (span, cmdName, cmdArgs, response) => {
341
273
  // Ensure peer.service persists through response
342
274
  span.setAttribute('peer.service', 'redis');
275
+ span.setAttribute('db.system', 'redis');
276
+
277
+ // Add command details for better observability
278
+ if (cmdName) {
279
+ span.setAttribute('db.operation', cmdName.toUpperCase());
280
+ }
343
281
 
344
282
  // Log response size if available
345
283
  if (response !== undefined && response !== null) {
@@ -360,46 +298,7 @@ export function setupTracing(options = {}) {
360
298
  return `${cmdName} ${args.join(' ')}`;
361
299
  },
362
300
  }),
363
- new ElasticsearchInstrumentation({
364
- suppressInternalInstrumentation: true,
365
- requestHook: (span, request) => {
366
- // Set peer.service for service graph visualization - CRITICAL for Tempo
367
- // This ensures Elasticsearch spans are properly identified
368
- span.setAttribute('peer.service', 'elasticsearch');
369
- span.setAttribute('db.system', 'elasticsearch');
370
-
371
- // Add operation details if available
372
- if (request?.method) {
373
- span.setAttribute('db.operation', request.method.toUpperCase());
374
- }
375
- },
376
- responseHook: (span, response) => {
377
- // Ensure peer.service persists through response
378
- span.setAttribute('peer.service', 'elasticsearch');
379
- span.setAttribute('db.system', 'elasticsearch');
380
-
381
- // Add response details for better observability
382
- if (response) {
383
- // Add status code if available
384
- if (response.statusCode) {
385
- span.setAttribute('db.response.status_code', response.statusCode);
386
- }
387
-
388
- // Add response body size if available
389
- if (response.body) {
390
- const bodySize = typeof response.body === 'string'
391
- ? response.body.length
392
- : JSON.stringify(response.body).length;
393
- span.setAttribute('db.response.body_size', bodySize);
394
- }
395
-
396
- // Add took time if available (Elasticsearch response timing)
397
- if (response.body?.took) {
398
- span.setAttribute('db.elasticsearch.took_ms', response.body.took);
399
- }
400
- }
401
- },
402
- }),
301
+ new ElasticsearchInstrumentation(),
403
302
  ];
404
303
 
405
304
  if (enableFsInstrumentation) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saidsef/tracing-node",
3
- "version": "3.12.2",
3
+ "version": "3.13.1",
4
4
  "description": "tracing NodeJS - Wrapper for OpenTelemetry instrumentation packages",
5
5
  "main": "libs/index.mjs",
6
6
  "scripts": {