Logger¶
The Logger class is the primary interface for creating log records. In most
cases you use the pre-configured module-level instance.
Getting a Logger¶
The module-level logger is a Logger bound to the global Core singleton
with name "root". It is automatically configured on import — by default
it uses the "default" profile (writes to stdout).
Prefer creating one child logger per module with logger.new() (it
auto-detects the module name); the root logger is mainly the shared entry
point and a factory for child loggers.
Basic Logging¶
from plainlog import logger
log = logger.new() # auto-named after the current module
log.debug("debug message")
log.info("info message")
log.warning("warning message")
log.error("error message")
log.critical("critical message")
Each level method accepts a message and optional keyword arguments that are
merged into the log record as top-level fields (for example record["user"]).
Log with a specific level¶
from plainlog import logger
log = logger.new()
log.log("INFO", "explicit level")
log.log(20, "level as int")
Callable form¶
A Logger is also callable. log(level, msg, **kwargs) behaves like
log.log() but returns a bool: True if the record was accepted by
the Core's processor pipeline, False if it was dropped (no processors
configured, or below the minimum level).
from plainlog import logger
log = logger.new()
accepted = log("INFO", "positional form")
also_accepted = log(level="WARNING", msg="keyword form")
Log with exception info¶
from plainlog import logger
log = logger.new()
try:
1 / 0
except ZeroDivisionError:
log.exception("something went wrong")
Configuration¶
Using a profile¶
from plainlog import configure_log, logger
configure_log(profile="develop", level="DEBUG")
log = logger.new()
log.info("now with colors and caller info")
Direct processor setup¶
from plainlog import configure_log
from plainlog.processors import SimpleFormatter, Stream
configure_log(processors=[SimpleFormatter(), Stream()])
See Processors, Formatters & Handlers for everything available.
Binding Variables¶
Use bind() to create a child logger with
additional static key-value pairs attached to every record.
from plainlog import logger
log = logger.new().bind(user="alice", request_id="abc-123")
log.info("user action")
Use unbind() to remove keys.
from plainlog import logger
log = logger.new().bind(user="alice", request_id="abc-123")
log2 = log.unbind("request_id")
log2.info("without request_id")
Context Variables¶
Use contextualize() to attach variables for the
duration of a block.
from plainlog import logger
log = logger.new()
with log.contextualize(request_id="xyz"):
log.info("inside context")
The context is thread-safe (backed by ContextVar) and works correctly in
async code.
For manual control, context() sets the variables and returns a token that
reset_context() restores:
from plainlog import logger
log = logger.new()
token = log.context(request_id="xyz")
try:
log.info("inside context")
finally:
log.reset_context(token)
log.info("after context")
Child Loggers¶
Use new() to create a child logger. The name
is auto-detected from the caller's module and function.
To explicitly derive the logger name from the current module, pass
__name__:
from plainlog import logger
log = logger.new(__name__)
log.info("logged with the module name as logger name")
Flushing¶
Records are processed on a background thread. flush() blocks until every
record queued so far has been processed — useful before reading output.
API Reference¶
Logger¶
Logger that sends structured log records to a shared Core.
Each Logger is tied to a single Core instance, a name, and a set
of static key-value pairs (passed as keyword arguments) that are
attached to every record as top-level fields.
Use bind() / unbind() to derive a new logger with
additional or fewer fields. Use new() to create a child
logger (optionally with an auto-detected name).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
core
|
Core
|
The shared Core this logger writes to. |
required |
name
|
str
|
Logger name (e.g. |
required |
**kwargs
|
Any
|
Static key-value pairs attached to every record. |
{}
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Logger name (e.g. |
__call__(level=LEVEL_DEBUG, msg='', **kwargs)
¶
Callable interface: logger(level, msg, **kwargs).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
str | int
|
Log level as int or str. Defaults to DEBUG. |
LEVEL_DEBUG
|
msg
|
Msg
|
The message to log. Defaults to |
''
|
**kwargs
|
Any
|
Additional record fields. |
{}
|
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
dropped (no processors configured or below the minimum level). |
bind(**kwargs)
¶
Return a new logger with additional fields.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Key-value pairs to merge into the logger's fields. |
{}
|
Returns:
| Type | Description |
|---|---|
'Logger'
|
A new Logger with the combined fields. |
context(**kwargs)
staticmethod
¶
contextualize(**kwargs)
staticmethod
¶
Context manager that sets kwargs as context variables.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Key-value pairs to set as context variables. |
{}
|
Yields:
| Type | Description |
|---|---|
Generator[Token[Dict[str, Any]]]
|
The token returned by |
Example
with logger.contextualize(request_id="abc"): logger.info("handling request")
critical(msg, **kwargs)
¶
Log msg at CRITICAL level.
debug(msg, **kwargs)
¶
Log msg at DEBUG level.
error(msg, **kwargs)
¶
Log msg at ERROR level.
exception(msg, **kwargs)
¶
Log msg at ERROR level and attach exception info.
If exc_info is not already set it defaults to True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
msg
|
Msg
|
The message to log. |
required |
**kwargs
|
Any
|
Additional record fields. |
{}
|
flush(timeout=None)
¶
Block until every queued record has been processed.
Records are handled on the background Core thread. Call this before reading side effects such as captured records or written files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Maximum seconds to wait. |
None
|
info(msg, **kwargs)
¶
Log msg at INFO level.
log(level, msg, **kwargs)
¶
new(name=None, **kwargs)
¶
reset_context(token)
staticmethod
¶
unbind(*args)
¶
Return a new logger with the given fields removed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Any
|
Field keys to remove. |
()
|
Returns:
| Type | Description |
|---|---|
'Logger'
|
A new Logger without the specified fields. |
warning(msg, **kwargs)
¶
Log msg at WARNING level.
Module-Level Instance¶
Module-level Logger convenience instance.
Usage::
from plainlog import logger
logger.info("hello world")
configure_log¶
Configure the global Core and optionally apply a named profile.
Keyword-only entry point for configuring processors and level; replaces
the removed per-logger configure() method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
profile
|
Optional[str]
|
Optional profile name. When set, the profile function is
called with kwargs and the processors it returns are applied. A
profile returning |
None
|
processors
|
Optional[Iterable[UniversalProcessorProtocol]]
|
Explicit processors to install. When both processors and a profile are given, the profile's processors are appended. |
None
|
level
|
Optional[Union[str, int]]
|
Minimum log level. |
None
|
close_before_configure
|
bool
|
Close the currently registered processors
before installing the new pipeline. Ignored when nothing is being
installed (for example a profile that returns |
False
|
**kwargs
|
Any
|
Extra arguments forwarded to the profile function. |
{}
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If profile is not a valid profile name. |