@saidsef/tracing-node 3.11.0 → 3.12.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/README.md +12 -10
- package/libs/index.mjs +129 -17
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -12,19 +12,21 @@ Get telemetry for your app in less than 3 minutes!
|
|
|
12
12
|
Effortlessly supercharge your applications with world-class distributed tracing! This OpenTelemetry wrapper delivers seamless, lightning-fast observability, empowering developers to monitor, debug, and optimise microservices with ease. Designed for modern cloud-native environments, it's the smart choice for engineers who demand reliability, scalability, and actionable insights. Get started in minutes and unlock the full potential of your service architecture—no fuss, just results. This is to make instrumentation (more) idempotent.
|
|
13
13
|
|
|
14
14
|
## Features
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
| Feature | Description |
|
|
16
|
+
|---------|-------------|
|
|
17
|
+
| HTTP/HTTPS instrumentation | Automatic service detection |
|
|
18
|
+
| Express.js support | Framework instrumentation |
|
|
19
|
+
| Elasticsearch client | Database instrumentation |
|
|
20
|
+
| IORedis client | Cache instrumentation |
|
|
21
|
+
| AWS SDK | Cloud service instrumentation |
|
|
22
|
+
| Pino logger | Integration with trace/span IDs |
|
|
23
|
+
| DNS/FS instrumentation | Optional monitoring |
|
|
24
|
+
| Resource detection | Host, OS, process, container |
|
|
25
|
+
| W3C Trace Context | Standard propagation |
|
|
25
26
|
|
|
26
27
|
## Prerequisites
|
|
27
28
|
- NodeJS
|
|
29
|
+
- Observability
|
|
28
30
|
- ...
|
|
29
31
|
- Profit?
|
|
30
32
|
|
package/libs/index.mjs
CHANGED
|
@@ -109,24 +109,61 @@ 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
|
+
// 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 || '';
|
|
116
116
|
|
|
117
|
-
//
|
|
118
|
-
if (hostname
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
+
}
|
|
122
130
|
}
|
|
123
131
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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';
|
|
129
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
|
|
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';
|
|
130
167
|
};
|
|
131
168
|
|
|
132
169
|
// Register instrumentations
|
|
@@ -134,8 +171,39 @@ export function setupTracing(options = {}) {
|
|
|
134
171
|
new HttpInstrumentation({
|
|
135
172
|
serverName: serviceName,
|
|
136
173
|
ignoreIncomingRequestHook,
|
|
137
|
-
|
|
174
|
+
requireParentforOutgoingSpans: false,
|
|
175
|
+
requireParentforIncomingSpans: false,
|
|
138
176
|
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
|
+
|
|
139
207
|
// Enrich spans with additional HTTP request attributes
|
|
140
208
|
if (request.headers) {
|
|
141
209
|
const userAgent = request.headers['user-agent'];
|
|
@@ -240,11 +308,55 @@ export function setupTracing(options = {}) {
|
|
|
240
308
|
},
|
|
241
309
|
}),
|
|
242
310
|
new IORedisInstrumentation({
|
|
243
|
-
|
|
311
|
+
requireParentSpan: false,
|
|
312
|
+
responseHook: (span, cmdName, cmdArgs, response) => {
|
|
313
|
+
// Set peer.service for service graph visualization
|
|
244
314
|
span.setAttribute('peer.service', 'redis');
|
|
315
|
+
span.setAttribute('db.system', 'redis');
|
|
316
|
+
|
|
317
|
+
// Add command details for better observability
|
|
318
|
+
if (cmdName) {
|
|
319
|
+
span.setAttribute('db.operation', cmdName.toUpperCase());
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Log response size if available
|
|
323
|
+
if (response !== undefined && response !== null) {
|
|
324
|
+
const responseType = typeof response;
|
|
325
|
+
span.setAttribute('db.response.type', responseType);
|
|
326
|
+
|
|
327
|
+
if (Array.isArray(response)) {
|
|
328
|
+
span.setAttribute('db.response.count', response.length);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
245
331
|
},
|
|
246
|
-
requestHook: (span) => {
|
|
332
|
+
requestHook: (span, cmdName, cmdArgs) => {
|
|
333
|
+
// Set peer.service for service graph visualization - CRITICAL for Tempo
|
|
247
334
|
span.setAttribute('peer.service', 'redis');
|
|
335
|
+
span.setAttribute('db.system', 'redis');
|
|
336
|
+
|
|
337
|
+
// Add command details
|
|
338
|
+
if (cmdName) {
|
|
339
|
+
span.setAttribute('db.operation', cmdName.toUpperCase());
|
|
340
|
+
span.updateName(`redis.${cmdName.toUpperCase()}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Add key information (first argument is usually the key)
|
|
344
|
+
if (cmdArgs && cmdArgs.length > 0) {
|
|
345
|
+
span.setAttribute('db.redis.key', String(cmdArgs[0]));
|
|
346
|
+
|
|
347
|
+
// For operations with multiple keys or complex args
|
|
348
|
+
if (cmdArgs.length > 1) {
|
|
349
|
+
span.setAttribute('db.redis.args_count', cmdArgs.length);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
dbStatementSerializer: (cmdName, cmdArgs) => {
|
|
354
|
+
// Serialize command for better observability (limit arg length to avoid huge spans)
|
|
355
|
+
const args = cmdArgs.map(arg => {
|
|
356
|
+
const str = String(arg);
|
|
357
|
+
return str.length > 100 ? `${str.substring(0, 100)}...` : str;
|
|
358
|
+
});
|
|
359
|
+
return `${cmdName} ${args.join(' ')}`;
|
|
248
360
|
},
|
|
249
361
|
}),
|
|
250
362
|
new ElasticsearchInstrumentation(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saidsef/tracing-node",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.0",
|
|
4
4
|
"description": "tracing NodeJS - Wrapper for OpenTelemetry instrumentation packages",
|
|
5
5
|
"main": "libs/index.mjs",
|
|
6
6
|
"scripts": {
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@opentelemetry/api": "^1.9.0",
|
|
34
34
|
"@opentelemetry/context-async-hooks": "^2.0.1",
|
|
35
|
-
"@opentelemetry/exporter-trace-otlp-grpc": "^0.
|
|
36
|
-
"@opentelemetry/instrumentation": "^0.
|
|
37
|
-
"@opentelemetry/instrumentation-aws-sdk": "^0.
|
|
38
|
-
"@opentelemetry/instrumentation-connect": "^0.
|
|
39
|
-
"@opentelemetry/instrumentation-dns": "^0.
|
|
40
|
-
"@opentelemetry/instrumentation-express": "^0.
|
|
41
|
-
"@opentelemetry/instrumentation-fs": "^0.
|
|
42
|
-
"@opentelemetry/instrumentation-http": "^0.
|
|
43
|
-
"@opentelemetry/instrumentation-ioredis": "^0.
|
|
44
|
-
"@opentelemetry/instrumentation-pino": "^0.
|
|
35
|
+
"@opentelemetry/exporter-trace-otlp-grpc": "^0.208.0",
|
|
36
|
+
"@opentelemetry/instrumentation": "^0.208.0",
|
|
37
|
+
"@opentelemetry/instrumentation-aws-sdk": "^0.64.0",
|
|
38
|
+
"@opentelemetry/instrumentation-connect": "^0.52.0",
|
|
39
|
+
"@opentelemetry/instrumentation-dns": "^0.52.0",
|
|
40
|
+
"@opentelemetry/instrumentation-express": "^0.57.0",
|
|
41
|
+
"@opentelemetry/instrumentation-fs": "^0.28.0",
|
|
42
|
+
"@opentelemetry/instrumentation-http": "^0.208.0",
|
|
43
|
+
"@opentelemetry/instrumentation-ioredis": "^0.56.0",
|
|
44
|
+
"@opentelemetry/instrumentation-pino": "^0.55.0",
|
|
45
45
|
"@opentelemetry/resources": "^2.0.1",
|
|
46
46
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
47
47
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|