or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

active-observations.mdattribute-creation.mdcontext-management.mdindex.mdmanual-observations.mdobservation-types.mdobserve-decorator.mdotel-span-attributes.mdtrace-id-generation.mdtracer-provider.md

trace-id-generation.mddocs/

0

# Trace ID Generation

1

2

The `createTraceId()` function provides utilities for generating OpenTelemetry-compatible trace IDs with support for both deterministic (seeded) and random generation. This is particularly useful for correlating external IDs with Langfuse traces.

3

4

## Core Function

5

6

### createTraceId

7

8

Creates a trace ID for OpenTelemetry spans with optional deterministic generation.

9

10

```typescript { .api }

11

/**

12

* Creates a trace ID for OpenTelemetry spans.

13

*

14

* @param seed - A seed string for deterministic trace ID generation.

15

* If provided (non-empty), the same seed will always generate the same trace ID.

16

* If empty or falsy, generates a random trace ID.

17

*

18

* Using a seed is especially useful when trying to correlate external,

19

* non-W3C compliant IDs with Langfuse trace IDs. This allows you to later

20

* have a method available for scoring the Langfuse trace given only the

21

* external ID by regenerating the same trace ID from the external ID.

22

*

23

* @returns A Promise that resolves to a 32-character lowercase hexadecimal string

24

* suitable for use as an OpenTelemetry trace ID.

25

*/

26

async function createTraceId(seed?: string): Promise<string>;

27

```

28

29

## Output Format

30

31

The function returns a 32-character lowercase hexadecimal string that conforms to the OpenTelemetry trace ID format:

32

33

```typescript

34

// Example outputs

35

"a1b2c3d4e5f67890a1b2c3d4e5f67890" // Random

36

"f8e7d6c5b4a3928170f8e7d6c5b4a392" // From seed "my-session-123"

37

"c4b3a29180f7e6d5c4b3a29180f7e6d5" // From seed "user-456"

38

```

39

40

## Random Trace IDs

41

42

Generate unique, random trace IDs for each operation.

43

44

```typescript

45

import { createTraceId } from '@langfuse/tracing';

46

47

// Generate random trace IDs

48

const traceId1 = await createTraceId();

49

const traceId2 = await createTraceId();

50

51

console.log(traceId1); // "a1b2c3d4e5f67890a1b2c3d4e5f67890"

52

console.log(traceId2); // "f8e7d6c5b4a3928170f8e7d6c5b4a392"

53

console.log(traceId1 === traceId2); // false - different IDs

54

55

// Alternative: empty string also generates random ID

56

const randomId = await createTraceId("");

57

```

58

59

## Deterministic Trace IDs

60

61

Generate consistent trace IDs from a seed string for correlation purposes.

62

63

```typescript

64

import { createTraceId } from '@langfuse/tracing';

65

66

// Same seed always produces the same trace ID

67

const traceId1 = await createTraceId("my-session-123");

68

const traceId2 = await createTraceId("my-session-123");

69

70

console.log(traceId1 === traceId2); // true - identical IDs

71

72

// Different seeds produce different IDs

73

const sessionA = await createTraceId("session-a");

74

const sessionB = await createTraceId("session-b");

75

76

console.log(sessionA === sessionB); // false - different IDs

77

```

78

79

## Use Cases

80

81

### External ID Correlation

82

83

Correlate external system IDs with Langfuse traces.

84

85

```typescript

86

import { createTraceId, startObservation } from '@langfuse/tracing';

87

88

async function processExternalRequest(externalRequestId: string) {

89

// Generate deterministic trace ID from external ID

90

const traceId = await createTraceId(externalRequestId);

91

92

// Create observation with custom trace ID

93

const span = startObservation('process-request', {

94

input: { externalRequestId }

95

}, {

96

parentSpanContext: {

97

traceId: traceId,

98

spanId: '0123456789abcdef',

99

traceFlags: 1

100

}

101

});

102

103

// Process request...

104

const result = await handleRequest(externalRequestId);

105

106

span.update({ output: result });

107

span.end();

108

109

return result;

110

}

111

112

// Later, score the trace using the external ID

113

async function scoreTrace(externalRequestId: string, score: number) {

114

// Regenerate the same trace ID

115

const traceId = await createTraceId(externalRequestId);

116

117

// Use trace ID to find and score the Langfuse trace

118

await langfuseClient.score({

119

traceId: traceId,

120

name: 'quality',

121

value: score

122

});

123

}

124

125

// Process request

126

await processExternalRequest('ext-12345-67890');

127

128

// Later, score without storing the trace ID

129

await scoreTrace('ext-12345-67890', 0.95);

130

```

131

132

### Session-Based Tracing

133

134

Group operations by session using deterministic trace IDs.

135

136

```typescript

137

import { createTraceId, startObservation } from '@langfuse/tracing';

138

139

async function trackUserSession(sessionId: string, action: string) {

140

// All operations in the same session share the same trace ID

141

const traceId = await createTraceId(sessionId);

142

143

const observation = startObservation(action, {

144

input: { sessionId, action }

145

}, {

146

parentSpanContext: {

147

traceId: traceId,

148

spanId: crypto.randomUUID().replace(/-/g, '').slice(0, 16),

149

traceFlags: 1

150

}

151

});

152

153

// Perform action...

154

const result = await performAction(action);

155

156

observation.update({ output: result });

157

observation.end();

158

159

return result;

160

}

161

162

// All these operations share the same trace ID

163

const sessionId = 'session-abc-123';

164

await trackUserSession(sessionId, 'login');

165

await trackUserSession(sessionId, 'view-product');

166

await trackUserSession(sessionId, 'add-to-cart');

167

await trackUserSession(sessionId, 'checkout');

168

```

169

170

### Distributed Tracing

171

172

Propagate deterministic trace IDs across service boundaries.

173

174

```typescript

175

import { createTraceId, startObservation } from '@langfuse/tracing';

176

177

// Service A: API Gateway

178

async function handleApiRequest(requestId: string) {

179

const traceId = await createTraceId(requestId);

180

181

const span = startObservation('api-gateway', {

182

input: { requestId }

183

}, {

184

parentSpanContext: {

185

traceId: traceId,

186

spanId: '0123456789abcdef',

187

traceFlags: 1

188

}

189

});

190

191

// Call downstream service with request ID

192

const result = await fetch('https://service-b.com/process', {

193

method: 'POST',

194

headers: {

195

'X-Request-Id': requestId,

196

'Content-Type': 'application/json'

197

},

198

body: JSON.stringify({ data: 'value' })

199

});

200

201

span.update({ output: result });

202

span.end();

203

204

return result;

205

}

206

207

// Service B: Processing Service

208

async function processRequest(req: Request) {

209

const requestId = req.headers.get('X-Request-Id');

210

211

// Regenerate the same trace ID from request ID

212

const traceId = await createTraceId(requestId);

213

214

const span = startObservation('process-request', {

215

input: { requestId }

216

}, {

217

parentSpanContext: {

218

traceId: traceId,

219

spanId: '123456789abcdef0',

220

traceFlags: 1

221

}

222

});

223

224

// Process...

225

const result = await process();

226

227

span.update({ output: result });

228

span.end();

229

230

return result;

231

}

232

```

233

234

### Conversation Threading

235

236

Link multiple conversation turns using deterministic trace IDs.

237

238

```typescript

239

import { createTraceId, startObservation } from '@langfuse/tracing';

240

241

async function handleConversationTurn(

242

conversationId: string,

243

turnNumber: number,

244

userMessage: string

245

) {

246

// All turns in conversation share the same trace ID

247

const traceId = await createTraceId(conversationId);

248

249

const generation = startObservation(`turn-${turnNumber}`, {

250

input: { turnNumber, userMessage },

251

model: 'gpt-4'

252

}, {

253

asType: 'generation',

254

parentSpanContext: {

255

traceId: traceId,

256

spanId: crypto.randomUUID().replace(/-/g, '').slice(0, 16),

257

traceFlags: 1

258

}

259

});

260

261

const response = await llm.chat([

262

{ role: 'user', content: userMessage }

263

]);

264

265

generation.update({

266

output: response,

267

usageDetails: { totalTokens: response.usage.totalTokens }

268

});

269

generation.end();

270

271

return response;

272

}

273

274

// All turns in this conversation share the same trace

275

const conversationId = 'conv-abc-123';

276

await handleConversationTurn(conversationId, 1, 'What is AI?');

277

await handleConversationTurn(conversationId, 2, 'Tell me more');

278

await handleConversationTurn(conversationId, 3, 'Give an example');

279

```

280

281

### Batch Processing

282

283

Group batch items under a single trace using deterministic IDs.

284

285

```typescript

286

import { createTraceId, startObservation } from '@langfuse/tracing';

287

288

async function processBatch(batchId: string, items: any[]) {

289

// All items in batch share the same trace ID

290

const traceId = await createTraceId(batchId);

291

292

for (const [index, item] of items.entries()) {

293

const observation = startObservation(`item-${index}`, {

294

input: { batchId, itemId: item.id, index }

295

}, {

296

parentSpanContext: {

297

traceId: traceId,

298

spanId: crypto.randomUUID().replace(/-/g, '').slice(0, 16),

299

traceFlags: 1

300

}

301

});

302

303

const result = await processItem(item);

304

305

observation.update({ output: result });

306

observation.end();

307

}

308

}

309

310

// All items in this batch share the same trace ID

311

await processBatch('batch-2024-01-01', items);

312

```

313

314

### Testing and Debugging

315

316

Generate predictable trace IDs for testing.

317

318

```typescript

319

import { createTraceId, startObservation } from '@langfuse/tracing';

320

321

describe('Tracing tests', () => {

322

it('should generate consistent trace IDs', async () => {

323

const seed = 'test-seed-123';

324

325

const traceId1 = await createTraceId(seed);

326

const traceId2 = await createTraceId(seed);

327

328

expect(traceId1).toBe(traceId2);

329

});

330

331

it('should create observations with custom trace ID', async () => {

332

const testTraceId = await createTraceId('test-trace');

333

334

const observation = startObservation('test-operation', {

335

input: { test: true }

336

}, {

337

parentSpanContext: {

338

traceId: testTraceId,

339

spanId: '0123456789abcdef',

340

traceFlags: 1

341

}

342

});

343

344

expect(observation.traceId).toBe(testTraceId);

345

observation.end();

346

});

347

});

348

```

349

350

## Implementation Details

351

352

### SHA-256 Hashing

353

354

Deterministic trace IDs are generated using SHA-256 hashing:

355

356

```typescript

357

// Internal implementation (simplified)

358

async function createTraceId(seed?: string): Promise<string> {

359

if (seed) {

360

// Encode seed as UTF-8

361

const data = new TextEncoder().encode(seed);

362

363

// Generate SHA-256 hash

364

const hashBuffer = await crypto.subtle.digest("SHA-256", data);

365

366

// Convert to hex string and take first 32 characters

367

const hashArray = new Uint8Array(hashBuffer);

368

const hexString = Array.from(hashArray)

369

.map(b => b.toString(16).padStart(2, "0"))

370

.join("");

371

372

return hexString.slice(0, 32);

373

}

374

375

// Random generation using crypto.getRandomValues

376

const randomValues = crypto.getRandomValues(new Uint8Array(16));

377

return Array.from(randomValues)

378

.map(b => b.toString(16).padStart(2, "0"))

379

.join("");

380

}

381

```

382

383

### Collision Probability

384

385

Random trace IDs use 128 bits of entropy, making collisions extremely unlikely:

386

387

```typescript

388

// Collision probability calculation

389

// 32 hex characters = 128 bits = 2^128 possible values

390

// Probability of collision: ~1 in 3.4 × 10^38

391

392

const randomId1 = await createTraceId();

393

const randomId2 = await createTraceId();

394

// Virtually guaranteed to be different

395

```

396

397

### Seed Consistency

398

399

The same seed always produces the same trace ID across all platforms:

400

401

```typescript

402

// These will always produce identical trace IDs

403

const nodeTraceId = await createTraceId("my-seed"); // Node.js

404

const browserTraceId = await createTraceId("my-seed"); // Browser

405

const workerTraceId = await createTraceId("my-seed"); // Worker

406

407

// All equal: nodeTraceId === browserTraceId === workerTraceId

408

```

409

410

## Advanced Patterns

411

412

### Hierarchical IDs

413

414

Create hierarchical trace ID structure using seed composition.

415

416

```typescript

417

async function createHierarchicalTrace(

418

organizationId: string,

419

projectId: string,

420

requestId: string

421

) {

422

// Compose seed from hierarchy

423

const seed = `${organizationId}:${projectId}:${requestId}`;

424

const traceId = await createTraceId(seed);

425

426

// All operations with same hierarchy share trace ID

427

return traceId;

428

}

429

430

const traceId = await createHierarchicalTrace(

431

'org-123',

432

'proj-456',

433

'req-789'

434

);

435

```

436

437

### Time-Bucketed Traces

438

439

Group operations by time windows using date-based seeds.

440

441

```typescript

442

async function createTimeBucketedTrace(

443

userId: string,

444

bucketSizeMs: number = 3600000 // 1 hour

445

) {

446

const now = Date.now();

447

const bucket = Math.floor(now / bucketSizeMs);

448

449

// All operations in same time bucket share trace ID

450

const seed = `${userId}:${bucket}`;

451

return await createTraceId(seed);

452

}

453

454

// All operations in same hour share trace ID

455

const traceId = await createTimeBucketedTrace('user-123');

456

```

457

458

### Multi-Tenant Isolation

459

460

Ensure trace ID uniqueness per tenant.

461

462

```typescript

463

async function createTenantTrace(

464

tenantId: string,

465

resourceType: string,

466

resourceId: string

467

) {

468

// Include tenant in seed for isolation

469

const seed = `tenant:${tenantId}:${resourceType}:${resourceId}`;

470

return await createTraceId(seed);

471

}

472

473

const traceId = await createTenantTrace(

474

'tenant-abc',

475

'order',

476

'order-123'

477

);

478

```

479

480

## Best Practices

481

482

### Use Deterministic IDs for Correlation

483

484

Use seeded generation when you need to correlate with external systems.

485

486

```typescript

487

// Good: Deterministic for correlation

488

const externalId = 'payment-12345';

489

const traceId = await createTraceId(externalId);

490

491

// Later, retrieve trace using external ID

492

const sameTraceId = await createTraceId(externalId);

493

```

494

495

### Use Random IDs for Independence

496

497

Use random generation for independent, uncorrelated operations.

498

499

```typescript

500

// Good: Random for independent operations

501

const traceId = await createTraceId();

502

503

const observation = startObservation('one-time-operation', {

504

input: { data: 'value' }

505

}, {

506

parentSpanContext: {

507

traceId: traceId,

508

spanId: '0123456789abcdef',

509

traceFlags: 1

510

}

511

});

512

```

513

514

### Include Context in Seeds

515

516

Make seeds descriptive and include relevant context.

517

518

```typescript

519

// Good: Descriptive seed with context

520

const seed = `user:${userId}:session:${sessionId}:request:${requestId}`;

521

const traceId = await createTraceId(seed);

522

523

// Avoid: Generic seed

524

const traceId = await createTraceId(userId); // May collide across contexts

525

```

526

527

### Validate Seed Uniqueness

528

529

Ensure seeds are unique enough to avoid collisions.

530

531

```typescript

532

// Good: Unique per operation

533

const seed = `${resourceType}:${resourceId}:${timestamp}`;

534

535

// Risky: May collide

536

const seed = resourceId; // If resourceId repeats across types

537

```

538

539

### Document Seed Format

540

541

Document seed formats for consistent regeneration.

542

543

```typescript

544

/**

545

* Creates a trace ID for user session operations.

546

*

547

* Seed format: "session:{sessionId}:user:{userId}"

548

*

549

* @example

550

* const traceId = await createSessionTraceId('sess-123', 'user-456');

551

* // Can regenerate later using same IDs

552

*/

553

async function createSessionTraceId(

554

sessionId: string,

555

userId: string

556

): Promise<string> {

557

return await createTraceId(`session:${sessionId}:user:${userId}`);

558

}

559

```

560

561

### Handle Async Nature

562

563

Remember that `createTraceId()` is async and returns a Promise.

564

565

```typescript

566

// Good: Await the result

567

const traceId = await createTraceId("my-seed");

568

569

// Wrong: Missing await

570

const traceId = createTraceId("my-seed"); // Promise object, not string

571

572

// Good: Use in async context

573

async function createTrace() {

574

const traceId = await createTraceId();

575

return traceId;

576

}

577

```

578

579

### Cache Generated IDs

580

581

Cache deterministic trace IDs to avoid repeated hashing.

582

583

```typescript

584

const traceIdCache = new Map<string, string>();

585

586

async function getCachedTraceId(seed: string): Promise<string> {

587

if (traceIdCache.has(seed)) {

588

return traceIdCache.get(seed)!;

589

}

590

591

const traceId = await createTraceId(seed);

592

traceIdCache.set(seed, traceId);

593

return traceId;

594

}

595

596

// Faster for repeated calls with same seed

597

const traceId1 = await getCachedTraceId('session-123');

598

const traceId2 = await getCachedTraceId('session-123'); // From cache

599

```

600