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
```