or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bound-loggers.mdconfiguration.mdcontext-management.mddevelopment-tools.mdexception-handling.mdindex.mdlogger-creation.mdoutput-loggers.mdprocessors.mdstdlib-integration.mdtesting.md

stdlib-integration.mddocs/

0

# Standard Library Integration

1

2

Complete integration with Python's standard logging module, including stdlib-compatible loggers, formatters, and processors for bridging structlog with existing logging infrastructure. This integration allows structlog to work seamlessly with existing Python logging configurations.

3

4

## Capabilities

5

6

### Standard Library BoundLogger

7

8

BoundLogger implementation that integrates with Python's standard logging module, providing both structlog's structured logging capabilities and compatibility with stdlib logging.

9

10

```python { .api }

11

class BoundLogger(BoundLoggerBase):

12

"""

13

Standard library compatible bound logger.

14

15

Provides both structlog context methods and standard logging methods,

16

making it compatible with existing stdlib logging code.

17

"""

18

19

# Standard logging methods

20

def debug(self, event=None, **kw) -> None: ...

21

def info(self, event=None, **kw) -> None: ...

22

def warning(self, event=None, **kw) -> None: ...

23

def warn(self, event=None, **kw) -> None: ... # Deprecated alias

24

def error(self, event=None, **kw) -> None: ...

25

def critical(self, event=None, **kw) -> None: ...

26

def fatal(self, event=None, **kw) -> None: ... # Alias for critical

27

def exception(self, event=None, **kw) -> None: ...

28

def log(self, level, event=None, **kw) -> None: ...

29

30

# Async logging methods

31

def adebug(self, event=None, **kw) -> None: ...

32

def ainfo(self, event=None, **kw) -> None: ...

33

def awarning(self, event=None, **kw) -> None: ...

34

def awarn(self, event=None, **kw) -> None: ...

35

def aerror(self, event=None, **kw) -> None: ...

36

def acritical(self, event=None, **kw) -> None: ...

37

def afatal(self, event=None, **kw) -> None: ...

38

def aexception(self, event=None, **kw) -> None: ...

39

def alog(self, level, event=None, **kw) -> None: ...

40

41

# Standard logging properties

42

@property

43

def name(self) -> str: ...

44

@property

45

def level(self) -> int: ...

46

@property

47

def parent(self) -> logging.Logger: ...

48

@property

49

def propagate(self) -> bool: ...

50

@property

51

def handlers(self) -> list[logging.Handler]: ...

52

@property

53

def disabled(self) -> bool: ...

54

55

# Standard logging methods

56

def setLevel(self, level) -> None: ...

57

def findCaller(self, stack_info=False, stacklevel=1) -> tuple: ...

58

def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None) -> logging.LogRecord: ...

59

def handle(self, record) -> None: ...

60

def addHandler(self, hdlr) -> None: ...

61

def removeHandler(self, hdlr) -> None: ...

62

def hasHandlers(self) -> bool: ...

63

def callHandlers(self, record) -> None: ...

64

def getEffectiveLevel(self) -> int: ...

65

def isEnabledFor(self, level) -> bool: ...

66

def getChild(self, suffix) -> logging.Logger: ...

67

```

68

69

### Async Bound Logger

70

71

Async wrapper around BoundLogger that exposes logging methods as async versions, allowing non-blocking logging in async applications.

72

73

```python { .api }

74

class AsyncBoundLogger:

75

"""

76

Wraps a BoundLogger & exposes its logging methods as async versions.

77

78

Instead of blocking the program, logging operations are run asynchronously

79

in a thread pool executor. This means more computational overhead per log

80

call but prevents processor chains and I/O from blocking async applications.

81

82

.. versionadded:: 20.2.0

83

.. deprecated:: 23.1.0 Use async methods on BoundLogger instead

84

"""

85

86

def __init__(

87

self,

88

logger,

89

processors=None,

90

context=None,

91

_sync_bl=None,

92

_loop=None

93

): ...

94

95

# Context management methods

96

def bind(self, **new_values) -> AsyncBoundLogger: ...

97

def unbind(self, *keys) -> AsyncBoundLogger: ...

98

def try_unbind(self, *keys) -> AsyncBoundLogger: ...

99

def new(self, **new_values) -> AsyncBoundLogger: ...

100

101

# Async logging methods

102

async def adebug(self, event: str, *args, **kw) -> None:

103

"""Log using debug(), but asynchronously in a separate thread."""

104

105

async def ainfo(self, event: str, *args, **kw) -> None:

106

"""Log using info(), but asynchronously in a separate thread."""

107

108

async def awarning(self, event: str, *args, **kw) -> None:

109

"""Log using warning(), but asynchronously in a separate thread."""

110

111

async def aerror(self, event: str, *args, **kw) -> None:

112

"""Log using error(), but asynchronously in a separate thread."""

113

114

async def acritical(self, event: str, *args, **kw) -> None:

115

"""Log using critical(), but asynchronously in a separate thread."""

116

117

async def afatal(self, event: str, *args, **kw) -> None:

118

"""Log using critical(), but asynchronously in a separate thread."""

119

120

async def aexception(self, event: str, *args, **kw) -> None:

121

"""Log using exception(), but asynchronously in a separate thread."""

122

123

async def alog(self, level, event: str, *args, **kw) -> None:

124

"""Log using log(), but asynchronously in a separate thread."""

125

```

126

127

### Logger Factory

128

129

Factory for creating standard library logger instances that work with structlog.

130

131

```python { .api }

132

class LoggerFactory:

133

"""Factory for creating stdlib logger instances."""

134

135

def __call__(self, *args) -> logging.Logger:

136

"""

137

Create a stdlib logger instance.

138

139

Args:

140

*args: Arguments passed to logging.getLogger()

141

142

Returns:

143

logging.Logger: Standard library logger instance

144

"""

145

```

146

147

### Formatter Integration

148

149

ProcessorFormatter allows structlog processors to be used within the standard logging framework.

150

151

```python { .api }

152

class ProcessorFormatter(logging.Formatter):

153

"""

154

Logging formatter that processes log records through structlog processors.

155

156

Bridges stdlib logging and structlog by converting LogRecord objects

157

to structlog event dictionaries and processing them through processors.

158

"""

159

160

def __init__(

161

self,

162

processor,

163

foreign_pre_chain=None,

164

keep_exc_info=False,

165

keep_stack_info=False

166

):

167

"""

168

Args:

169

processor (callable): Final processor to render the log record

170

foreign_pre_chain (list, optional): Processors to run before main processor

171

keep_exc_info (bool): Keep exc_info in record after processing

172

keep_stack_info (bool): Keep stack_info in record after processing

173

"""

174

175

def format(self, record) -> str: ...

176

```

177

178

### Argument Processing

179

180

Processors for handling stdlib-style logging arguments and record attributes.

181

182

```python { .api }

183

class PositionalArgumentsFormatter:

184

"""Handle stdlib-style positional arguments in log messages."""

185

186

def __call__(self, logger, name, event_dict) -> EventDict:

187

"""

188

Process positional arguments like stdlib logging.

189

190

Handles cases where event_dict contains positional args

191

that need to be formatted into the message string.

192

"""

193

194

class ExtraAdder:

195

"""Add logging record's extra fields to structlog event dictionary."""

196

197

def __init__(self, names):

198

"""

199

Args:

200

names (set): Set of field names to extract from LogRecord.extra

201

"""

202

203

def __call__(self, logger, name, event_dict) -> EventDict: ...

204

```

205

206

### Integration Functions

207

208

Functions for working with standard library logging integration.

209

210

```python { .api }

211

def recreate_defaults(*, log_level=logging.NOTSET) -> None:

212

"""

213

Recreate structlog defaults using stdlib logging.

214

215

Sets up structlog to work with Python's standard logging module

216

by configuring appropriate defaults.

217

218

Args:

219

log_level: Minimum log level for filtering

220

"""

221

222

def get_logger(name=None) -> BoundLogger:

223

"""

224

Get a stdlib-based structlog logger.

225

226

Args:

227

name (str, optional): Logger name for stdlib logger hierarchy

228

229

Returns:

230

BoundLogger: Stdlib-compatible structlog logger

231

"""

232

```

233

234

### Standard Library Processors

235

236

Processors specifically designed for stdlib logging integration.

237

238

```python { .api }

239

def add_log_level(logger, method_name, event_dict) -> EventDict:

240

"""

241

Add log level name to event dictionary.

242

243

Adds 'level' key with the log level name (debug, info, warning, etc.)

244

based on the method name used to call the logger.

245

"""

246

247

def add_log_level_number(logger, method_name, event_dict) -> EventDict:

248

"""

249

Add numeric log level to event dictionary.

250

251

Adds 'level' key with the numeric log level (10=DEBUG, 20=INFO, etc.)

252

based on the method name used to call the logger.

253

"""

254

255

def add_logger_name(logger, method_name, event_dict) -> EventDict:

256

"""

257

Add logger name to event dictionary.

258

259

Adds 'logger' key with the name of the stdlib logger instance.

260

"""

261

262

def filter_by_level(logger, method_name, event_dict) -> EventDict:

263

"""

264

Filter log events by log level.

265

266

Drops events that don't meet the minimum log level threshold

267

by raising DropEvent exception.

268

"""

269

270

def render_to_log_kwargs(logger, method_name, event_dict) -> dict[str, Any]:

271

"""

272

Render event dict to stdlib logging keyword arguments.

273

274

Converts structlog event dictionary to kwargs suitable for

275

passing to stdlib logging methods.

276

"""

277

278

def render_to_log_args_and_kwargs(logger, method_name, event_dict) -> tuple[tuple[Any, ...], dict[str, Any]]:

279

"""

280

Render event dict to stdlib logging args and kwargs.

281

282

Converts structlog event dictionary to positional args and kwargs

283

suitable for stdlib logging methods.

284

"""

285

```

286

287

## Usage Examples

288

289

### Basic Stdlib Integration

290

291

```python

292

import logging

293

import structlog

294

from structlog import stdlib

295

296

# Configure Python logging

297

logging.basicConfig(

298

level=logging.INFO,

299

format="%(message)s",

300

)

301

302

# Configure structlog to use stdlib

303

structlog.configure(

304

processors=[

305

stdlib.add_log_level,

306

structlog.processors.TimeStamper(fmt="iso"),

307

structlog.processors.JSONRenderer()

308

],

309

wrapper_class=stdlib.BoundLogger,

310

logger_factory=stdlib.LoggerFactory(),

311

context_class=dict,

312

cache_logger_on_first_use=True,

313

)

314

315

# Get a logger

316

logger = structlog.get_logger("myapp")

317

318

# Use both structlog and stdlib features

319

logger.info("Application started", version="1.0.0")

320

logger.bind(user_id=123).warning("User action", action="delete")

321

```

322

323

### ProcessorFormatter Usage

324

325

```python

326

import logging

327

import structlog

328

from structlog import stdlib, processors

329

330

# Set up a stdlib handler with ProcessorFormatter

331

handler = logging.StreamHandler()

332

handler.setFormatter(

333

stdlib.ProcessorFormatter(

334

processor=processors.JSONRenderer(),

335

foreign_pre_chain=[

336

processors.TimeStamper(),

337

stdlib.add_log_level,

338

],

339

)

340

)

341

342

# Configure stdlib logging

343

root = logging.getLogger()

344

root.addHandler(handler)

345

root.setLevel(logging.INFO)

346

347

# Configure structlog to forward to stdlib

348

structlog.configure(

349

processors=[

350

stdlib.render_to_log_kwargs,

351

],

352

wrapper_class=stdlib.BoundLogger,

353

logger_factory=stdlib.LoggerFactory(),

354

cache_logger_on_first_use=True,

355

)

356

357

logger = structlog.get_logger("myapp")

358

logger.info("Processed through stdlib", count=42)

359

```

360

361

### Mixed Logging Setup

362

363

```python

364

import logging

365

import structlog

366

from structlog import stdlib, processors

367

368

# Configure stdlib for file output

369

file_handler = logging.FileHandler("app.log")

370

file_handler.setFormatter(

371

stdlib.ProcessorFormatter(

372

processor=processors.JSONRenderer(),

373

foreign_pre_chain=[

374

processors.TimeStamper(fmt="iso"),

375

stdlib.add_log_level,

376

stdlib.add_logger_name,

377

]

378

)

379

)

380

381

# Configure stdlib for console output

382

console_handler = logging.StreamHandler()

383

console_handler.setFormatter(

384

stdlib.ProcessorFormatter(

385

processor=structlog.dev.ConsoleRenderer(colors=True)

386

)

387

)

388

389

# Set up root logger

390

logging.basicConfig(

391

level=logging.INFO,

392

handlers=[file_handler, console_handler]

393

)

394

395

# Configure structlog

396

structlog.configure(

397

processors=[

398

stdlib.render_to_log_kwargs,

399

],

400

wrapper_class=stdlib.BoundLogger,

401

logger_factory=stdlib.LoggerFactory(),

402

cache_logger_on_first_use=True,

403

)

404

405

logger = structlog.get_logger("myapp.service")

406

logger.info("Service started", port=8080)

407

# Logs to both file (JSON) and console (colored)

408

```

409

410

### Level Filtering

411

412

```python

413

import logging

414

import structlog

415

from structlog import stdlib, processors

416

417

# Configure with level filtering

418

structlog.configure(

419

processors=[

420

stdlib.filter_by_level, # Filter by level first

421

processors.TimeStamper(),

422

stdlib.add_log_level,

423

processors.JSONRenderer()

424

],

425

wrapper_class=stdlib.BoundLogger,

426

logger_factory=stdlib.LoggerFactory(),

427

cache_logger_on_first_use=True,

428

)

429

430

# Set logging level

431

logging.basicConfig(level=logging.WARNING)

432

433

logger = structlog.get_logger()

434

logger.debug("Debug message") # Filtered out

435

logger.info("Info message") # Filtered out

436

logger.warning("Warning message") # Shown

437

logger.error("Error message") # Shown

438

```

439

440

### Legacy Integration

441

442

```python

443

import logging

444

import structlog

445

from structlog import stdlib

446

447

# Existing stdlib logging configuration

448

logging.basicConfig(

449

level=logging.INFO,

450

format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'

451

)

452

453

# Add structlog on top

454

stdlib.recreate_defaults(log_level=logging.INFO)

455

456

# Get logger that works with existing setup

457

logger = stdlib.get_logger("legacy.module")

458

459

# Works with existing handlers and formatters

460

logger.info("Legacy integration working", module="auth")

461

```

462

463

### Custom Logger Names

464

465

```python

466

import structlog

467

from structlog import stdlib

468

469

structlog.configure(

470

processors=[

471

stdlib.add_logger_name,

472

stdlib.add_log_level,

473

structlog.processors.JSONRenderer()

474

],

475

wrapper_class=stdlib.BoundLogger,

476

logger_factory=stdlib.LoggerFactory(),

477

)

478

479

# Create loggers with specific names

480

auth_logger = structlog.get_logger("myapp.auth")

481

db_logger = structlog.get_logger("myapp.database")

482

api_logger = structlog.get_logger("myapp.api")

483

484

auth_logger.info("User authenticated")

485

db_logger.info("Query executed", table="users")

486

api_logger.info("Request processed", endpoint="/users")

487

# Each includes the logger name in output

488

```

489

490

### Async Logging Methods

491

492

```python

493

import asyncio

494

import structlog

495

from structlog import stdlib

496

497

structlog.configure(

498

processors=[

499

stdlib.add_log_level,

500

structlog.processors.JSONRenderer()

501

],

502

wrapper_class=stdlib.BoundLogger,

503

logger_factory=stdlib.LoggerFactory(),

504

)

505

506

async def async_operation():

507

logger = structlog.get_logger()

508

509

# Use async logging methods

510

await logger.ainfo("Async operation started")

511

512

# Simulate async work

513

await asyncio.sleep(0.1)

514

515

await logger.ainfo("Async operation completed", duration="0.1s")

516

517

# Run async operation

518

asyncio.run(async_operation())

519

```