0
# Distributed Tracing
1
2
Cross-service tracing capabilities with trace metadata extraction and injection for microservices architectures.
3
4
## Capabilities
5
6
### Get Linking Metadata
7
8
Retrieve linking metadata for correlating logs with traces across services.
9
10
```javascript { .api }
11
/**
12
* Returns linking metadata for correlating logs with traces.
13
* @param {boolean} [omitSupportability] - Whether to skip supportability metric (defaults to false)
14
* @returns {object} Object containing trace.id, span.id, entity.name, entity.type, entity.guid, hostname
15
*/
16
function getLinkingMetadata(omitSupportability);
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
const newrelic = require('newrelic');
23
24
// Basic linking metadata for logging
25
function logWithTraceContext(message, level = 'info') {
26
const metadata = newrelic.getLinkingMetadata();
27
28
console.log(JSON.stringify({
29
timestamp: new Date().toISOString(),
30
level: level,
31
message: message,
32
...metadata // Includes trace.id, span.id, entity.name, etc.
33
}));
34
}
35
36
// Usage
37
logWithTraceContext('Processing user order', 'info');
38
// Output: {"timestamp":"2023-10-01T12:00:00.000Z","level":"info","message":"Processing user order","trace.id":"abc123","span.id":"def456","entity.name":"my-service","entity.type":"SERVICE","entity.guid":"MTIzNDU2fEFQTXxBUFBMSUNBVElPTnw3ODkw","hostname":"server-1"}
39
40
// Structured logging with winston
41
const winston = require('winston');
42
43
const logger = winston.createLogger({
44
format: winston.format.combine(
45
winston.format.timestamp(),
46
winston.format.json(),
47
winston.format.printf(info => {
48
const metadata = newrelic.getLinkingMetadata(true); // Skip supportability metric
49
return JSON.stringify({
50
...info,
51
...metadata
52
});
53
})
54
),
55
transports: [new winston.transports.Console()]
56
});
57
58
logger.info('Order processed successfully', { orderId: '12345' });
59
```
60
61
### Get Trace Metadata
62
63
Get the current trace and span identifiers for distributed tracing.
64
65
```javascript { .api }
66
/**
67
* Returns the current trace and span identifiers.
68
* @returns {object} Object containing traceId and spanId
69
*/
70
function getTraceMetadata();
71
```
72
73
**Usage Examples:**
74
75
```javascript
76
// Basic trace metadata
77
function getCurrentTraceInfo() {
78
const metadata = newrelic.getTraceMetadata();
79
console.log(`Current trace ID: ${metadata.traceId}`);
80
console.log(`Current span ID: ${metadata.spanId}`);
81
return metadata;
82
}
83
84
// Add trace context to API responses
85
app.get('/api/users/:id', (req, res) => {
86
const user = getUserById(req.params.id);
87
const traceMetadata = newrelic.getTraceMetadata();
88
89
res.json({
90
user: user,
91
_meta: {
92
traceId: traceMetadata.traceId,
93
spanId: traceMetadata.spanId,
94
timestamp: new Date().toISOString()
95
}
96
});
97
});
98
99
// Custom correlation IDs
100
function generateCorrelationId() {
101
const traceMetadata = newrelic.getTraceMetadata();
102
return `${traceMetadata.traceId}-${Date.now()}`;
103
}
104
```
105
106
## Linking Metadata Structure
107
108
```javascript { .api }
109
interface LinkingMetadata {
110
/** Current trace identifier */
111
'trace.id': string;
112
/** Current span identifier */
113
'span.id': string;
114
/** Application name from New Relic configuration */
115
'entity.name': string;
116
/** Entity type, always "SERVICE" */
117
'entity.type': string;
118
/** New Relic entity GUID */
119
'entity.guid': string;
120
/** Hostname of the server */
121
hostname: string;
122
}
123
124
interface TraceMetadata {
125
/** Current distributed trace ID */
126
traceId: string;
127
/** Current span ID */
128
spanId: string;
129
}
130
```
131
132
## Transaction Handle Distributed Tracing
133
134
When using `getTransaction()`, the returned handle provides distributed tracing methods:
135
136
```javascript { .api }
137
/**
138
* Accept and process incoming distributed trace headers from upstream services
139
* @param {string} transportType - Transport mechanism (e.g., 'HTTP', 'HTTPS', 'Queue')
140
* @param {object} headers - Headers object containing distributed trace information
141
*/
142
TransactionHandle.prototype.acceptDistributedTraceHeaders = function(transportType, headers);
143
144
/**
145
* Insert distributed trace headers for outgoing requests to downstream services
146
* @param {object} headers - Headers object to modify with distributed trace information
147
*/
148
TransactionHandle.prototype.insertDistributedTraceHeaders = function(headers);
149
```
150
151
## Common Integration Patterns
152
153
### HTTP Client Instrumentation
154
155
```javascript
156
const axios = require('axios');
157
158
// Automatic header injection for outgoing requests
159
axios.interceptors.request.use((config) => {
160
const transaction = newrelic.getTransaction();
161
if (transaction) {
162
config.headers = config.headers || {};
163
transaction.insertDistributedTraceHeaders(config.headers);
164
}
165
return config;
166
});
167
168
// Manual header injection
169
async function callDownstreamService(data) {
170
const transaction = newrelic.getTransaction();
171
const headers = { 'Content-Type': 'application/json' };
172
173
if (transaction) {
174
transaction.insertDistributedTraceHeaders(headers);
175
}
176
177
const response = await axios.post('https://downstream-service/api/process', data, {
178
headers: headers
179
});
180
return response.data;
181
}
182
```
183
184
### HTTP Server Instrumentation
185
186
```javascript
187
// Express middleware to accept incoming distributed trace headers
188
app.use((req, res, next) => {
189
const transaction = newrelic.getTransaction();
190
if (transaction) {
191
transaction.acceptDistributedTraceHeaders('HTTP', req.headers);
192
}
193
next();
194
});
195
196
// Manual header processing
197
app.post('/api/webhook', (req, res) => {
198
const transaction = newrelic.getTransaction();
199
if (transaction) {
200
transaction.acceptDistributedTraceHeaders('HTTP', req.headers);
201
}
202
203
// Process webhook...
204
res.json({ status: 'processed' });
205
});
206
```
207
208
### Message Queue Integration
209
210
```javascript
211
// Producer - add trace headers to message
212
function publishMessage(queueName, messageData) {
213
const transaction = newrelic.getTransaction();
214
const messageHeaders = {};
215
216
if (transaction) {
217
transaction.insertDistributedTraceHeaders(messageHeaders);
218
}
219
220
return messageQueue.publish(queueName, {
221
data: messageData,
222
headers: messageHeaders,
223
timestamp: Date.now()
224
});
225
}
226
227
// Consumer - accept trace headers from message
228
function processMessage(message) {
229
return newrelic.startBackgroundTransaction('ProcessMessage', 'Queue', () => {
230
const transaction = newrelic.getTransaction();
231
232
if (transaction && message.headers) {
233
transaction.acceptDistributedTraceHeaders('Queue', message.headers);
234
}
235
236
// Process the message
237
return handleMessage(message.data);
238
});
239
}
240
```
241
242
### Microservices Architecture
243
244
```javascript
245
// Service A - initiating a distributed trace
246
async function processUserRequest(userData) {
247
// Start with web transaction (automatically creates trace)
248
const validation = await callValidationService(userData);
249
const enriched = await callEnrichmentService(userData, validation);
250
const stored = await callStorageService(enriched);
251
252
return stored;
253
}
254
255
async function callValidationService(userData) {
256
const transaction = newrelic.getTransaction();
257
const headers = { 'Content-Type': 'application/json' };
258
259
if (transaction) {
260
transaction.insertDistributedTraceHeaders(headers);
261
}
262
263
const response = await fetch('http://validation-service/validate', {
264
method: 'POST',
265
headers: headers,
266
body: JSON.stringify(userData)
267
});
268
269
return response.json();
270
}
271
272
// Service B - validation service
273
app.post('/validate', (req, res) => {
274
const transaction = newrelic.getTransaction();
275
if (transaction) {
276
transaction.acceptDistributedTraceHeaders('HTTP', req.headers);
277
}
278
279
const result = validateUserData(req.body);
280
res.json(result);
281
});
282
```
283
284
### Database Operation Correlation
285
286
```javascript
287
// Add trace context to database operations for correlation
288
async function performDatabaseOperation(query, params) {
289
const traceMetadata = newrelic.getTraceMetadata();
290
291
// Add trace context to database session or query comments
292
const contextualQuery = `/* traceId: ${traceMetadata.traceId}, spanId: ${traceMetadata.spanId} */ ${query}`;
293
294
return await database.execute(contextualQuery, params);
295
}
296
```
297
298
### Log Correlation
299
300
```javascript
301
const winston = require('winston');
302
303
// Custom winston format that adds trace context
304
const traceFormat = winston.format((info) => {
305
const metadata = newrelic.getLinkingMetadata(true);
306
return { ...info, ...metadata };
307
});
308
309
const logger = winston.createLogger({
310
format: winston.format.combine(
311
winston.format.timestamp(),
312
traceFormat(),
313
winston.format.json()
314
),
315
transports: [
316
new winston.transports.Console(),
317
new winston.transports.File({ filename: 'app.log' })
318
]
319
});
320
321
// Usage - logs will automatically include trace context
322
logger.info('User order processed', {
323
orderId: '12345',
324
userId: 'user-789'
325
});
326
```
327
328
### Custom Correlation Strategies
329
330
```javascript
331
// Create custom correlation IDs based on trace metadata
332
function createCorrelationId(prefix = 'corr') {
333
const traceMetadata = newrelic.getTraceMetadata();
334
const timestamp = Date.now();
335
336
if (traceMetadata.traceId) {
337
return `${prefix}-${traceMetadata.traceId}-${timestamp}`;
338
}
339
340
// Fallback for when no trace is active
341
return `${prefix}-${require('crypto').randomUUID()}-${timestamp}`;
342
}
343
344
// Add correlation ID to all responses
345
app.use((req, res, next) => {
346
const correlationId = createCorrelationId('req');
347
res.set('X-Correlation-ID', correlationId);
348
req.correlationId = correlationId;
349
next();
350
});
351
352
// Use correlation ID in logging
353
app.use((req, res, next) => {
354
const originalSend = res.send;
355
res.send = function(data) {
356
logger.info('Request completed', {
357
correlationId: req.correlationId,
358
method: req.method,
359
url: req.url,
360
statusCode: res.statusCode
361
});
362
return originalSend.call(this, data);
363
};
364
next();
365
});
366
```
367
368
### Cross-Platform Tracing
369
370
```javascript
371
// When calling non-Node.js services, ensure trace context is propagated
372
async function callPythonService(data) {
373
const transaction = newrelic.getTransaction();
374
const headers = {
375
'Content-Type': 'application/json',
376
'X-Service-Context': 'node-service'
377
};
378
379
if (transaction) {
380
transaction.insertDistributedTraceHeaders(headers);
381
382
// Add additional context for non-New Relic instrumented services
383
const traceMetadata = newrelic.getTraceMetadata();
384
headers['X-Trace-ID'] = traceMetadata.traceId;
385
headers['X-Span-ID'] = traceMetadata.spanId;
386
}
387
388
return await fetch('http://python-service/process', {
389
method: 'POST',
390
headers: headers,
391
body: JSON.stringify(data)
392
});
393
}
394
```
395
396
## Configuration Requirements
397
398
Distributed tracing requires:
399
400
1. **Agent Configuration**: `distributed_tracing.enabled: true` (default)
401
2. **Network Connectivity**: Services must be able to communicate
402
3. **Header Propagation**: HTTP clients and servers must propagate trace headers
403
4. **Transaction Context**: Trace metadata is only available within active transactions
404
405
## Best Practices
406
407
1. **Automatic Instrumentation**: Use automatic instrumentation when possible (most HTTP libraries are auto-instrumented)
408
2. **Manual Header Management**: For custom protocols or clients, manually manage header injection/acceptance
409
3. **Error Handling**: Handle cases where trace metadata might not be available
410
4. **Performance**: Trace header operations are lightweight, but avoid unnecessary calls in hot paths
411
5. **Security**: Be cautious about trace headers in logs or external systems
412
6. **Consistency**: Ensure all services in your architecture participate in distributed tracing
413
7. **Monitoring**: Use New Relic's distributed tracing UI to visualize and troubleshoot trace flows