@saidsef/tracing-node 3.21.0 → 3.22.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/libs/index.mjs +51 -123
- package/package.json +8 -6
package/libs/index.mjs
CHANGED
|
@@ -17,9 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import {AwsInstrumentation} from '@opentelemetry/instrumentation-aws-sdk';
|
|
20
|
-
import {AsyncHooksContextManager} from '@opentelemetry/context-async-hooks';
|
|
21
20
|
import {BatchSpanProcessor} from '@opentelemetry/sdk-trace-base';
|
|
22
|
-
import {CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator} from '@opentelemetry/core';
|
|
23
21
|
import {ConnectInstrumentation} from '@opentelemetry/instrumentation-connect';
|
|
24
22
|
import {diag, DiagConsoleLogger, DiagLogLevel} from '@opentelemetry/api';
|
|
25
23
|
import {HttpInstrumentation} from '@opentelemetry/instrumentation-http';
|
|
@@ -101,29 +99,26 @@ export function setupTracing(options = {}) {
|
|
|
101
99
|
exportTimeoutMillis: 10000,
|
|
102
100
|
});
|
|
103
101
|
|
|
102
|
+
// Explicit attributes (service/container) must win over env detection, so
|
|
103
|
+
// detect first and merge the explicit resource on top. Only include defined
|
|
104
|
+
// keys so an undefined hostname does not write container.name: undefined.
|
|
105
|
+
const explicitAttributes = {[ATTR_SERVICE_NAME]: serviceName};
|
|
106
|
+
if (hostname) {
|
|
107
|
+
explicitAttributes[ATTR_CONTAINER_NAME] = hostname;
|
|
108
|
+
}
|
|
109
|
+
|
|
104
110
|
tracerProvider = new NodeTracerProvider({
|
|
105
111
|
spanProcessors: [spanProcessor],
|
|
106
|
-
resource:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}).merge(
|
|
110
|
-
detectResources({
|
|
111
|
-
detectors: [envDetector, hostDetector, osDetector, processDetector, serviceInstanceIdDetector],
|
|
112
|
-
})
|
|
113
|
-
),
|
|
114
|
-
autoDetectResources: true,
|
|
112
|
+
resource: detectResources({
|
|
113
|
+
detectors: [envDetector, hostDetector, osDetector, processDetector, serviceInstanceIdDetector],
|
|
114
|
+
}).merge(resourceFromAttributes(explicitAttributes)),
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
new W3CTraceContextPropagator(),
|
|
123
|
-
new W3CBaggagePropagator(),
|
|
124
|
-
],
|
|
125
|
-
}),
|
|
126
|
-
});
|
|
117
|
+
// Register globally. With no overrides, register() installs the modern
|
|
118
|
+
// AsyncLocalStorageContextManager and a CompositePropagator of
|
|
119
|
+
// W3CTraceContext + W3CBaggage - identical propagation to the previous
|
|
120
|
+
// explicit config, with the recommended context manager.
|
|
121
|
+
tracerProvider.register();
|
|
127
122
|
|
|
128
123
|
// Ignore spans from static assets.
|
|
129
124
|
const ignoreIncomingRequestHook = (req) => {
|
|
@@ -207,89 +202,68 @@ export function setupTracing(options = {}) {
|
|
|
207
202
|
},
|
|
208
203
|
}),
|
|
209
204
|
new ExpressInstrumentation({
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (
|
|
214
|
-
span.setAttribute('express.route',
|
|
215
|
-
|
|
205
|
+
requestHook: (span, info) => {
|
|
206
|
+
// info is ExpressRequestInfo: { request, route, layerType }
|
|
207
|
+
const request = info.request;
|
|
208
|
+
if (info.route) {
|
|
209
|
+
span.setAttribute('express.route', info.route);
|
|
210
|
+
if (request?.method) {
|
|
211
|
+
span.updateName(`${request.method} ${info.route}`);
|
|
212
|
+
}
|
|
216
213
|
}
|
|
217
|
-
if (request
|
|
214
|
+
if (request?.params && Object.keys(request.params).length > 0) {
|
|
218
215
|
span.setAttribute('express.params', JSON.stringify(request.params));
|
|
219
216
|
}
|
|
220
|
-
if (request
|
|
217
|
+
if (request?.query && Object.keys(request.query).length > 0) {
|
|
221
218
|
span.setAttribute('express.query', JSON.stringify(request.query));
|
|
222
219
|
}
|
|
223
220
|
// Add user context if available
|
|
224
|
-
if (request
|
|
221
|
+
if (request?.user?.id) {
|
|
225
222
|
span.setAttribute('user.id', request.user.id);
|
|
226
223
|
}
|
|
227
224
|
},
|
|
228
225
|
}),
|
|
229
226
|
new PinoInstrumentation({
|
|
230
227
|
logHook: (span, record) => {
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
record['trace_id'] = spanContext.traceId;
|
|
234
|
-
record['span_id'] = spanContext.spanId;
|
|
235
|
-
record['trace_flags'] = `0${spanContext.traceFlags.toString(16)}`;
|
|
236
|
-
|
|
237
|
-
// Add service name for better log correlation
|
|
228
|
+
// trace_id/span_id/trace_flags are injected by the instrumentation by
|
|
229
|
+
// default; only add service name for better log correlation.
|
|
238
230
|
if (serviceName) {
|
|
239
231
|
record['service.name'] = serviceName;
|
|
240
232
|
}
|
|
241
233
|
},
|
|
242
|
-
logSeverity: {
|
|
243
|
-
error: 'ERROR',
|
|
244
|
-
warn: 'WARN',
|
|
245
|
-
info: 'INFO',
|
|
246
|
-
debug: 'DEBUG',
|
|
247
|
-
trace: 'TRACE',
|
|
248
|
-
},
|
|
249
|
-
}),
|
|
250
|
-
new ConnectInstrumentation({
|
|
251
|
-
ignoreIncomingRequestHook,
|
|
252
|
-
requestHook: (span, request) => {
|
|
253
|
-
// Add Connect middleware attributes
|
|
254
|
-
if (request.url) {
|
|
255
|
-
span.setAttribute('connect.url', request.url);
|
|
256
|
-
}
|
|
257
|
-
if (request.method) {
|
|
258
|
-
span.setAttribute('connect.method', request.method);
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
234
|
}),
|
|
235
|
+
// ConnectInstrumentation accepts only the base InstrumentationConfig; it has
|
|
236
|
+
// no request/ignore hooks, so configure it with defaults.
|
|
237
|
+
new ConnectInstrumentation(),
|
|
262
238
|
new AwsInstrumentation({
|
|
263
239
|
suppressInternalInstrumentation: false,
|
|
264
240
|
sqsExtractContextPropagationFromPayload: true,
|
|
265
|
-
preRequestHook: (span,
|
|
266
|
-
//
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
269
|
-
span.setAttribute('peer.service',
|
|
270
|
-
span.setAttribute('aws.service',
|
|
241
|
+
preRequestHook: (span, requestInfo) => {
|
|
242
|
+
// requestInfo is AwsSdkRequestHookInformation: { request: NormalizedRequest }
|
|
243
|
+
const awsServiceName = requestInfo.request?.serviceName;
|
|
244
|
+
if (awsServiceName) {
|
|
245
|
+
span.setAttribute('peer.service', awsServiceName.toLowerCase());
|
|
246
|
+
span.setAttribute('aws.service', awsServiceName.toLowerCase());
|
|
271
247
|
}
|
|
272
248
|
},
|
|
273
|
-
responseHook: (span,
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
249
|
+
responseHook: (span, responseInfo) => {
|
|
250
|
+
// responseInfo is AwsSdkResponseHookInformation: { response: NormalizedResponse }
|
|
251
|
+
const requestId = responseInfo.response?.requestId;
|
|
252
|
+
if (requestId) {
|
|
253
|
+
span.setAttribute('aws.request_id', requestId);
|
|
277
254
|
}
|
|
278
255
|
},
|
|
279
256
|
}),
|
|
280
257
|
new IORedisInstrumentation({
|
|
281
258
|
requireParentSpan: false,
|
|
282
|
-
requestHook: (span, cmdName, cmdArgs) => {
|
|
283
|
-
//
|
|
259
|
+
requestHook: (span, {cmdName, cmdArgs}) => {
|
|
260
|
+
// requestInfo is IORedisRequestHookInformation: { cmdName, cmdArgs }.
|
|
261
|
+
// Set peer.service for service graph visualization - CRITICAL for Tempo.
|
|
262
|
+
// The span is already created with SpanKind.CLIENT and net.peer.name is
|
|
263
|
+
// already set to the real host by the instrumentation, so we do not
|
|
264
|
+
// override those here.
|
|
284
265
|
span.setAttribute('peer.service', 'redis');
|
|
285
266
|
span.setAttribute('db.system', 'redis');
|
|
286
|
-
|
|
287
|
-
// CRITICAL: Ensure span kind is CLIENT for service graph
|
|
288
|
-
span.setAttribute('span.kind', 'CLIENT');
|
|
289
|
-
|
|
290
|
-
// Add network peer attributes (helps Tempo identify the service)
|
|
291
|
-
span.setAttribute('net.peer.name', 'redis');
|
|
292
|
-
span.setAttribute('db.connection_string', 'redis');
|
|
293
267
|
|
|
294
268
|
// Add command details for better observability
|
|
295
269
|
if (cmdName) {
|
|
@@ -348,56 +322,10 @@ export function setupTracing(options = {}) {
|
|
|
348
322
|
if (enableDnsInstrumentation) {
|
|
349
323
|
// Enable DNS instrumentation if specified
|
|
350
324
|
// This instrumentation is useful for tracing DNS operations.
|
|
325
|
+
// DnsInstrumentationConfig only supports ignoreHostnames; it has no
|
|
326
|
+
// request/response/error hooks.
|
|
351
327
|
instrumentations.push(new DnsInstrumentation({
|
|
352
328
|
ignoreHostnames: ['localhost', '127.0.0.1', '::1'],
|
|
353
|
-
requestHook: (span, request) => {
|
|
354
|
-
// Add DNS query details for better observability
|
|
355
|
-
if (request.hostname) {
|
|
356
|
-
span.setAttribute('dns.hostname', request.hostname);
|
|
357
|
-
span.updateName(`DNS ${request.hostname}`);
|
|
358
|
-
}
|
|
359
|
-
if (request.rrtype) {
|
|
360
|
-
span.setAttribute('dns.record_type', request.rrtype);
|
|
361
|
-
}
|
|
362
|
-
// Add additional context
|
|
363
|
-
span.setAttribute('peer.service', 'dns');
|
|
364
|
-
span.setAttribute('dns.query_count', 1);
|
|
365
|
-
},
|
|
366
|
-
responseHook: (span, response) => {
|
|
367
|
-
// Add DNS response details
|
|
368
|
-
if (Array.isArray(response)) {
|
|
369
|
-
span.setAttribute('dns.result_count', response.length);
|
|
370
|
-
// Log first few results for debugging (limit to avoid overwhelming spans)
|
|
371
|
-
const resultSample = response.slice(0, 3).map(r =>
|
|
372
|
-
typeof r === 'string' ? r : JSON.stringify(r)
|
|
373
|
-
);
|
|
374
|
-
if (resultSample.length > 0) {
|
|
375
|
-
span.setAttribute('dns.results', JSON.stringify(resultSample));
|
|
376
|
-
}
|
|
377
|
-
} else if (response) {
|
|
378
|
-
span.setAttribute('dns.result_count', 1);
|
|
379
|
-
span.setAttribute('dns.result', typeof response === 'string' ? response : JSON.stringify(response));
|
|
380
|
-
}
|
|
381
|
-
},
|
|
382
|
-
errorHook: (span, error) => {
|
|
383
|
-
// Enhanced error tracking for DNS failures
|
|
384
|
-
if (error) {
|
|
385
|
-
span.setAttribute('dns.error', true);
|
|
386
|
-
span.setAttribute('dns.error.code', error.code || 'UNKNOWN');
|
|
387
|
-
span.setAttribute('dns.error.message', error.message || 'DNS lookup failed');
|
|
388
|
-
|
|
389
|
-
// Categorize common DNS errors
|
|
390
|
-
if (error.code === 'ENOTFOUND') {
|
|
391
|
-
span.setAttribute('dns.error.type', 'NOT_FOUND');
|
|
392
|
-
} else if (error.code === 'ETIMEOUT') {
|
|
393
|
-
span.setAttribute('dns.error.type', 'TIMEOUT');
|
|
394
|
-
} else if (error.code === 'ECONNREFUSED') {
|
|
395
|
-
span.setAttribute('dns.error.type', 'CONNECTION_REFUSED');
|
|
396
|
-
} else {
|
|
397
|
-
span.setAttribute('dns.error.type', 'OTHER');
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
},
|
|
401
329
|
}));
|
|
402
330
|
}
|
|
403
331
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saidsef/tracing-node",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.22.0",
|
|
4
4
|
"description": "tracing NodeJS - Wrapper for OpenTelemetry instrumentation packages",
|
|
5
5
|
"main": "libs/index.mjs",
|
|
6
6
|
"scripts": {
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
"homepage": "https://github.com/saidsef/tracing-node#readme",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@opentelemetry/api": "^1.9.0",
|
|
34
|
-
"@opentelemetry/context-async-hooks": "^2.8.0",
|
|
35
34
|
"@opentelemetry/exporter-trace-otlp-grpc": "^0.219.0",
|
|
36
35
|
"@opentelemetry/instrumentation": "^0.219.0",
|
|
37
36
|
"@opentelemetry/instrumentation-aws-sdk": "^0.74.0",
|
|
@@ -46,13 +45,16 @@
|
|
|
46
45
|
"@opentelemetry/sdk-trace-base": "^2.8.0",
|
|
47
46
|
"@opentelemetry/sdk-trace-node": "^2.8.0",
|
|
48
47
|
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
49
|
-
"opentelemetry-instrumentation-elasticsearch": "0.41.0"
|
|
48
|
+
"opentelemetry-instrumentation-elasticsearch": "^0.41.0"
|
|
50
49
|
},
|
|
51
50
|
"devDependencies": {
|
|
52
|
-
"eslint": "^10.5.0"
|
|
53
|
-
"jest": "^30.0.0"
|
|
51
|
+
"eslint": "^10.5.0"
|
|
54
52
|
},
|
|
55
53
|
"overrides": {
|
|
56
|
-
"protobufjs": "^7.5.3"
|
|
54
|
+
"protobufjs": "^7.5.3",
|
|
55
|
+
"@opentelemetry/core": "^2.8.0"
|
|
56
|
+
},
|
|
57
|
+
"allowScripts": {
|
|
58
|
+
"protobufjs@7.6.4": true
|
|
57
59
|
}
|
|
58
60
|
}
|