or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-logging.mdindex.mdinstrumentation.mdintegrations.mdmetrics.mdspans-tracing.md

spans-tracing.mddocs/

0

# Spans and Tracing

1

2

Manual span creation and management for tracking operations, creating distributed traces, and organizing observability data hierarchically. Spans represent units of work in distributed systems and provide the foundation for distributed tracing.

3

4

## Capabilities

5

6

### Span Creation

7

8

Create spans to track operations, measure performance, and organize related events hierarchically.

9

10

```python { .api }

11

def span(msg_template: str, /, *,

12

_tags: Sequence[str] | None = None,

13

_span_name: str | None = None,

14

_level: LevelName | int | None = None,

15

_links: Sequence = (),

16

**attributes) -> LogfireSpan:

17

"""

18

Create a span context manager for tracking an operation.

19

20

Parameters:

21

- msg_template: Message template with {} placeholders for attributes

22

- _tags: Optional sequence of tags to apply to this span

23

- _span_name: Custom span name (defaults to msg_template)

24

- _level: Log level for the span

25

- _links: Sequence of links to other spans

26

- **attributes: Key-value attributes for structured data and template substitution

27

28

Returns: LogfireSpan context manager

29

"""

30

```

31

32

**Usage Examples:**

33

34

```python

35

import logfire

36

37

# Basic span usage

38

with logfire.span('Processing user data', user_id=123):

39

# Work happens here, all logs are associated with this span

40

logfire.info('Validating user input')

41

# ... processing logic

42

logfire.info('Processing complete')

43

44

# Nested spans for hierarchical tracking

45

with logfire.span('HTTP Request', method='POST', endpoint='/users'):

46

with logfire.span('Authentication', user_id=123):

47

# Auth logic

48

pass

49

50

with logfire.span('Database Query', table='users'):

51

# DB query logic

52

pass

53

54

with logfire.span('Response Generation'):

55

# Response building

56

pass

57

58

# Custom span name and level

59

with logfire.span('Calculating metrics for {user_id}',

60

_span_name='metric_calculation',

61

_level='debug',

62

user_id=456, calculation_type='advanced'):

63

# Calculation logic

64

pass

65

```

66

67

### LogfireSpan Class

68

69

The LogfireSpan class provides methods for dynamically modifying spans during execution.

70

71

```python { .api }

72

class LogfireSpan:

73

"""

74

Context manager for spans with additional functionality.

75

"""

76

77

@property

78

def message_template(self) -> str:

79

"""The message template for this span (read-only)."""

80

81

@property

82

def tags(self) -> tuple[str, ...]:

83

"""Tuple of tags for this span (read/write)."""

84

85

@tags.setter

86

def tags(self, value: Sequence[str]) -> None: ...

87

88

@property

89

def message(self) -> str:

90

"""The formatted message for this span (read/write)."""

91

92

@message.setter

93

def message(self, value: str) -> None: ...

94

95

def set_attribute(self, key: str, value: Any) -> None:

96

"""

97

Set an attribute on the span.

98

99

Parameters:

100

- key: Attribute key

101

- value: Attribute value (will be converted to string if needed)

102

"""

103

104

def set_attributes(self, attributes: dict[str, Any]) -> None:

105

"""

106

Set multiple attributes on the span.

107

108

Parameters:

109

- attributes: Dictionary of key-value attribute pairs

110

"""

111

112

def add_link(self, context: SpanContext, attributes: dict[str, Any] | None = None) -> None:

113

"""

114

Add a link to another span.

115

116

Parameters:

117

- context: SpanContext of the span to link to

118

- attributes: Optional attributes for the link

119

"""

120

121

def record_exception(self, exception: BaseException, *,

122

attributes: dict[str, Any] | None = None,

123

timestamp: int | None = None,

124

escaped: bool = False) -> None:

125

"""

126

Record an exception on the span.

127

128

Parameters:

129

- exception: Exception instance to record

130

- attributes: Optional attributes associated with the exception

131

- timestamp: Optional timestamp (nanoseconds since epoch)

132

- escaped: Whether the exception was handled/escaped

133

"""

134

135

def is_recording(self) -> bool:

136

"""

137

Check if the span is currently recording.

138

139

Returns: True if the span is recording, False otherwise

140

"""

141

142

def set_level(self, level: LevelName | int) -> None:

143

"""

144

Set the log level of the span.

145

146

Parameters:

147

- level: Log level name or integer value

148

"""

149

```

150

151

**Usage Examples:**

152

153

```python

154

import logfire

155

156

# Dynamic span modification

157

with logfire.span('Processing request') as span:

158

span.set_attribute('start_time', time.time())

159

160

try:

161

# Processing logic

162

result = process_data()

163

span.set_attributes({

164

'result_count': len(result),

165

'success': True

166

})

167

except Exception as e:

168

span.record_exception(e, escaped=True)

169

span.set_attribute('error_handled', True)

170

# Handle error

171

172

# Update span message

173

span.message = f'Processed {len(result)} items'

174

175

# Linking spans across services

176

with logfire.span('External API call') as span:

177

# Get context from current span to link from remote service

178

current_context = span.get_span_context()

179

180

# In remote service, create linked span

181

with logfire.span('Remote processing') as remote_span:

182

remote_span.add_link(current_context, {'service': 'external-api'})

183

```

184

185

### Function Instrumentation

186

187

Automatically instrument functions to create spans for their execution with configurable parameter and return value capture.

188

189

```python { .api }

190

def instrument(msg_template: str | None = None, *,

191

span_name: str | None = None,

192

extract_args: bool = True,

193

record_return: bool = False,

194

allow_generator: bool = False):

195

"""

196

Decorator to instrument functions with automatic span creation.

197

198

Parameters:

199

- msg_template: Optional message template for the span

200

- span_name: Optional custom span name

201

- extract_args: Whether to automatically log function arguments as attributes

202

- record_return: Whether to log the return value as an attribute

203

- allow_generator: Allow instrumenting generator functions

204

205

Returns: Decorator function

206

"""

207

```

208

209

**Usage Examples:**

210

211

```python

212

import logfire

213

214

# Basic function instrumentation

215

@logfire.instrument

216

def calculate_total(items):

217

return sum(item.price for item in items)

218

219

# Custom message and span name

220

@logfire.instrument(

221

msg_template='Computing metrics for {period}',

222

span_name='metric_computation'

223

)

224

def compute_metrics(period, data_source):

225

# Computation logic

226

return {'avg': 10, 'count': 100}

227

228

# Record return values

229

@logfire.instrument(record_return=True)

230

def fetch_user_data(user_id):

231

# Returns user data that will be logged as span attribute

232

return {'id': user_id, 'name': 'John', 'email': 'john@example.com'}

233

234

# Instrument without argument extraction (for sensitive data)

235

@logfire.instrument(extract_args=False)

236

def process_payment(credit_card_info):

237

# Credit card info won't be logged automatically

238

return payment_result

239

240

# Generator function instrumentation

241

@logfire.instrument(allow_generator=True)

242

def process_large_dataset():

243

for batch in large_dataset:

244

yield process_batch(batch)

245

```

246

247

### Auto-Tracing

248

249

Automatically instrument modules or functions based on patterns for comprehensive observability without manual decoration.

250

251

```python { .api }

252

def install_auto_tracing(modules: Sequence[str] | Callable[[AutoTraceModule], bool], *,

253

min_duration: float,

254

check_imported_modules: Literal['error', 'warn', 'ignore'] = 'error') -> None:

255

"""

256

Install automatic tracing for specified modules.

257

258

Parameters:

259

- modules: Module names to trace, or a predicate function

260

- min_duration: Minimum execution duration (seconds) to create spans

261

- check_imported_modules: How to handle already-imported modules

262

"""

263

264

def no_auto_trace(func):

265

"""

266

Decorator to exclude a function from auto-tracing.

267

268

Parameters:

269

- func: Function to exclude from auto-tracing

270

271

Returns: Original function with auto-trace exclusion marker

272

"""

273

```

274

275

**Usage Examples:**

276

277

```python

278

import logfire

279

280

# Auto-trace specific modules

281

logfire.install_auto_tracing(

282

modules=['myapp.services', 'myapp.models'],

283

min_duration=0.01 # Only trace functions taking > 10ms

284

)

285

286

# Auto-trace with predicate function using AutoTraceModule

287

def should_trace(module: AutoTraceModule):

288

return (module.name.startswith('myapp.') and

289

not module.name.endswith('.tests') and

290

module.filename is not None)

291

292

logfire.install_auto_tracing(

293

modules=should_trace,

294

min_duration=0.005

295

)

296

297

# Exclude specific functions from auto-tracing

298

@logfire.no_auto_trace

299

def internal_helper_function():

300

# This won't be auto-traced even if module is included

301

pass

302

```

303

304

### Async Support

305

306

Logfire spans work seamlessly with async/await code and provide utilities for monitoring async operations.

307

308

```python { .api }

309

def log_slow_async_callbacks(slow_duration: float = 0.1) -> AbstractContextManager[None]:

310

"""

311

Context manager that logs warnings for slow asyncio callbacks.

312

313

Parameters:

314

- slow_duration: Threshold in seconds for considering callbacks slow

315

316

Returns: Context manager for monitoring async callback performance

317

"""

318

```

319

320

**Usage Examples:**

321

322

```python

323

import asyncio

324

import logfire

325

326

# Async spans work automatically

327

async def async_operation():

328

with logfire.span('Async database query', query_type='SELECT'):

329

await asyncio.sleep(0.1) # Simulated async work

330

return {'results': []}

331

332

# Monitor slow async callbacks

333

async def main():

334

with logfire.log_slow_async_callbacks(slow_duration=0.05):

335

# Any callback taking > 50ms will be logged as warning

336

await async_operation()

337

await another_async_operation()

338

339

# Async function instrumentation

340

@logfire.instrument

341

async def fetch_user_async(user_id):

342

with logfire.span('Database lookup', user_id=user_id):

343

# Async database call

344

return await db.fetch_user(user_id)

345

```

346

347

### Span Scoping and Context

348

349

Control span visibility and manage OpenTelemetry contexts for fine-grained tracing control.

350

351

```python { .api }

352

def suppress_scopes(*scopes: str) -> None:

353

"""

354

Prevent span and metric creation for specified OpenTelemetry scopes.

355

356

Parameters:

357

- *scopes: OpenTelemetry scope names to suppress

358

"""

359

```

360

361

**Usage Examples:**

362

363

```python

364

import logfire

365

366

# Suppress spans from specific instrumentation

367

logfire.suppress_scopes('opentelemetry.instrumentation.requests')

368

369

# Now requests won't create spans, but other instrumentation still works

370

import requests

371

requests.get('https://api.example.com') # No span created

372

373

# Custom instrumentation still works

374

with logfire.span('Custom operation'):

375

requests.get('https://api.example.com') # Still no request span, but custom span exists

376

```

377

378

### Distributed Tracing

379

380

Support for distributed tracing across services with context propagation and baggage management.

381

382

```python { .api }

383

def get_baggage() -> dict[str, str]:

384

"""

385

Get current OpenTelemetry baggage (key-value pairs propagated across service boundaries).

386

387

Returns: Dictionary of baggage key-value pairs

388

"""

389

390

def set_baggage(baggage: dict[str, str]) -> Token:

391

"""

392

Set OpenTelemetry baggage for context propagation.

393

394

Parameters:

395

- baggage: Dictionary of key-value pairs to propagate

396

397

Returns: Token for context restoration

398

"""

399

```

400

401

**Usage Examples:**

402

403

```python

404

import logfire

405

406

# Set baggage for cross-service correlation

407

token = logfire.set_baggage({

408

'user_id': '123',

409

'session_id': 'abc-def-456',

410

'feature_flag': 'new_checkout_enabled'

411

})

412

413

# Baggage is automatically propagated in HTTP headers

414

with logfire.span('Service A operation'):

415

# Make HTTP call - baggage is automatically included in headers

416

response = requests.post('https://service-b/process')

417

418

# In Service B, retrieve baggage

419

current_baggage = logfire.get_baggage()

420

user_id = current_baggage.get('user_id')

421

feature_enabled = current_baggage.get('feature_flag') == 'new_checkout_enabled'

422

```

423

424

### Performance and Resource Management

425

426

Tools for managing span lifecycle and ensuring proper resource cleanup.

427

428

```python { .api }

429

def force_flush(timeout_millis: int = 3000) -> bool:

430

"""

431

Force flush all pending spans to configured exporters.

432

433

Parameters:

434

- timeout_millis: Maximum time to wait for flush completion

435

436

Returns: True if flush completed within timeout

437

"""

438

439

def shutdown(timeout_millis: int = 30000, flush: bool = True) -> bool:

440

"""

441

Shutdown span processors and exporters.

442

443

Parameters:

444

- timeout_millis: Maximum time to wait for shutdown

445

- flush: Whether to flush pending spans before shutdown

446

447

Returns: True if shutdown completed within timeout

448

"""

449

```

450

451

**Usage Examples:**

452

453

```python

454

import logfire

455

import atexit

456

457

# Ensure spans are flushed on application exit

458

def cleanup():

459

logfire.force_flush(timeout_millis=5000)

460

logfire.shutdown(timeout_millis=10000)

461

462

atexit.register(cleanup)

463

464

# Manual flush at critical points

465

def handle_request():

466

with logfire.span('Handle request'):

467

# Process request

468

pass

469

470

# Ensure this request's spans are sent before continuing

471

logfire.force_flush(timeout_millis=1000)

472

```

473

474

### Type Definitions

475

476

```python { .api }

477

# OpenTelemetry types used in span operations

478

from opentelemetry.trace import SpanContext, SpanKind

479

from opentelemetry.util.types import AttributeValue

480

481

# Logfire-specific types

482

LevelName = Literal['trace', 'debug', 'info', 'notice', 'warn', 'warning', 'error', 'fatal']

483

484

# Auto-tracing types

485

@dataclass

486

class AutoTraceModule:

487

"""

488

Information about a module being imported that should maybe be traced automatically.

489

490

This object will be passed to a function that should return True if the module should be traced.

491

Used with install_auto_tracing() as the modules argument.

492

"""

493

494

name: str

495

"""Fully qualified absolute name of the module being imported."""

496

497

filename: str | None

498

"""Filename of the module being imported."""

499

500

def parts_start_with(self, prefix: str | Sequence[str]) -> bool:

501

"""

502

Return True if the module name starts with any of the given prefixes, using dots as boundaries.

503

504

For example, if the module name is 'foo.bar.spam', then parts_start_with('foo') will return True,

505

but parts_start_with('bar') or parts_start_with('foo_bar') will return False.

506

507

If a prefix contains any characters other than letters, numbers, and dots,

508

then it will be treated as a regular expression.

509

510

Parameters:

511

- prefix: String or sequence of strings to match against module name

512

513

Returns: True if module name matches any prefix

514

"""

515

516

# Context management

517

from contextvars import Token

518

from typing import AbstractContextManager

519

```