@saidsef/tracing-node 3.13.7 → 3.14.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 +60 -27
- package/libs/index.test.mjs +19 -3
- package/package.json +2 -2
package/libs/index.mjs
CHANGED
|
@@ -85,14 +85,21 @@ export function setupTracing(options = {}) {
|
|
|
85
85
|
|
|
86
86
|
// Configure exporter with the Collector endpoint - uses gRPC
|
|
87
87
|
const exportOptions = {
|
|
88
|
-
concurrencyLimit
|
|
89
|
-
url
|
|
90
|
-
timeoutMillis:
|
|
88
|
+
concurrencyLimit,
|
|
89
|
+
url,
|
|
90
|
+
timeoutMillis: 10000,
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
// Register the span processor with the tracer provider
|
|
94
94
|
const exporter = new OTLPTraceExporter(exportOptions);
|
|
95
|
-
|
|
95
|
+
|
|
96
|
+
// Configure BatchSpanProcessor for production workloads
|
|
97
|
+
const spanProcessor = new BatchSpanProcessor(exporter, {
|
|
98
|
+
maxQueueSize: 4096,
|
|
99
|
+
maxExportBatchSize: 1024,
|
|
100
|
+
scheduledDelayMillis: 2000,
|
|
101
|
+
exportTimeoutMillis: 10000,
|
|
102
|
+
});
|
|
96
103
|
|
|
97
104
|
tracerProvider = new NodeTracerProvider({
|
|
98
105
|
spanProcessors: [spanProcessor],
|
|
@@ -151,35 +158,52 @@ export function setupTracing(options = {}) {
|
|
|
151
158
|
applyCustomAttributesOnSpan,
|
|
152
159
|
requestHook: (span, request) => {
|
|
153
160
|
// Enrich spans with additional HTTP request attributes
|
|
154
|
-
if (request.headers)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
if (!request.headers) return;
|
|
162
|
+
|
|
163
|
+
const headers = request.headers;
|
|
164
|
+
|
|
165
|
+
// Safe header extraction with case-insensitive fallback
|
|
166
|
+
const userAgent = headers['user-agent'] || headers['User-Agent'];
|
|
167
|
+
const contentType = headers['content-type'] || headers['Content-Type'];
|
|
168
|
+
const contentLength = headers['content-length'] || headers['Content-Length'];
|
|
169
|
+
const requestId = headers['x-request-id'] || headers['X-Request-ID'];
|
|
170
|
+
const correlationId = headers['x-correlation-id'] || headers['X-Correlation-ID'];
|
|
171
|
+
|
|
172
|
+
// Only set attributes if values exist
|
|
173
|
+
if (userAgent) span.setAttribute('http.user_agent', userAgent);
|
|
174
|
+
if (contentType) span.setAttribute('http.request.content_type', contentType);
|
|
175
|
+
|
|
176
|
+
// Safe integer parsing with validation
|
|
177
|
+
if (contentLength) {
|
|
178
|
+
const length = parseInt(contentLength, 10);
|
|
179
|
+
if (!Number.isNaN(length) && length >= 0) {
|
|
180
|
+
span.setAttribute('http.request.content_length', length);
|
|
181
|
+
}
|
|
162
182
|
}
|
|
183
|
+
|
|
184
|
+
// Correlation headers for distributed tracing
|
|
185
|
+
if (requestId) span.setAttribute('http.request_id', requestId);
|
|
186
|
+
if (correlationId) span.setAttribute('http.correlation_id', correlationId);
|
|
163
187
|
},
|
|
164
188
|
responseHook: (span, response) => {
|
|
165
189
|
// Add response attributes for better observability
|
|
166
|
-
if (response.headers)
|
|
167
|
-
|
|
168
|
-
|
|
190
|
+
if (!response.headers) return;
|
|
191
|
+
|
|
192
|
+
const headers = response.headers;
|
|
193
|
+
const contentType = headers['content-type'] || headers['Content-Type'];
|
|
194
|
+
const contentLength = headers['content-length'] || headers['Content-Length'];
|
|
195
|
+
const requestId = headers['x-request-id'] || headers['X-Request-ID'];
|
|
169
196
|
|
|
170
|
-
|
|
171
|
-
|
|
197
|
+
if (contentType) span.setAttribute('http.response.content_type', contentType);
|
|
198
|
+
|
|
199
|
+
if (contentLength) {
|
|
200
|
+
const length = parseInt(contentLength, 10);
|
|
201
|
+
if (!Number.isNaN(length) && length >= 0) {
|
|
202
|
+
span.setAttribute('http.response.content_length', length);
|
|
203
|
+
}
|
|
172
204
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
server: {
|
|
176
|
-
requestHeaders: ['x-request-id', 'x-correlation-id', 'x-trace-id'],
|
|
177
|
-
responseHeaders: ['x-request-id', 'x-correlation-id'],
|
|
178
|
-
},
|
|
179
|
-
client: {
|
|
180
|
-
requestHeaders: ['x-request-id', 'x-correlation-id', 'x-trace-id'],
|
|
181
|
-
responseHeaders: ['x-request-id', 'x-correlation-id'],
|
|
182
|
-
},
|
|
205
|
+
|
|
206
|
+
if (requestId) span.setAttribute('http.request_id', requestId);
|
|
183
207
|
},
|
|
184
208
|
}),
|
|
185
209
|
new ExpressInstrumentation({
|
|
@@ -409,3 +433,12 @@ export async function stopTracing() {
|
|
|
409
433
|
console.warn('Tracer provider is not initialized.');
|
|
410
434
|
}
|
|
411
435
|
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* @internal
|
|
439
|
+
* Resets the tracer provider for testing purposes.
|
|
440
|
+
* DO NOT use in production code.
|
|
441
|
+
*/
|
|
442
|
+
export function __resetTracingForTesting() {
|
|
443
|
+
tracerProvider = null;
|
|
444
|
+
}
|
package/libs/index.test.mjs
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
// index.test.mjs
|
|
2
|
-
import { describe, it, beforeEach } from 'node:test';
|
|
2
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
3
3
|
import assert from 'node:assert';
|
|
4
4
|
|
|
5
5
|
describe('setupTracing', () => {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
let stopTracing;
|
|
7
|
+
|
|
8
|
+
// Clear environment and reset tracing state before each test
|
|
9
|
+
beforeEach(async () => {
|
|
8
10
|
delete process.env.SERVICE_NAME;
|
|
9
11
|
delete process.env.ENDPOINT;
|
|
10
12
|
delete process.env.HOSTNAME;
|
|
11
13
|
delete process.env.CONTAINER_NAME;
|
|
14
|
+
|
|
15
|
+
// Import and store stopTracing for cleanup
|
|
16
|
+
const tracing = await import('./index.mjs');
|
|
17
|
+
stopTracing = tracing.stopTracing;
|
|
18
|
+
|
|
19
|
+
// Reset singleton for test isolation
|
|
20
|
+
tracing.__resetTracingForTesting();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Clean up tracing after each test
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
if (stopTracing) {
|
|
26
|
+
await stopTracing();
|
|
27
|
+
}
|
|
12
28
|
});
|
|
13
29
|
|
|
14
30
|
it('should throw error when serviceName is not provided', async () => {
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saidsef/tracing-node",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.14.0",
|
|
4
4
|
"description": "tracing NodeJS - Wrapper for OpenTelemetry instrumentation packages",
|
|
5
5
|
"main": "libs/index.mjs",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node --trace-warnings --test --report-uncaught-exception
|
|
7
|
+
"test": "node --trace-warnings --test --report-uncaught-exception libs/index.test.mjs",
|
|
8
8
|
"lint": "eslint .",
|
|
9
9
|
"rebuild": "rm -rfv node_modules/ package-lock.json && npm install --prod --omit=dev"
|
|
10
10
|
},
|