or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aws-lambda.mdbrowser-monitoring.mdcustom-attributes.mdcustom-instrumentation.mddistributed-tracing.mderror-handling.mdindex.mdllm-monitoring.mdmetrics-events.mdsegments-timing.mdtransaction-management.mdurl-naming-rules.mdutilities.md

distributed-tracing.mddocs/

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