@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.
- package/libs/index.mjs +29 -130
- 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
|
-
//
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
//
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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) {
|