API Reference

Logging

logstruct.getLogger(name)[source]

Retrieve or get a StructuredLogger instance.

getLogger(None) will produce a StructuredLogger delegating to the root logger.

Parameters:

name (str | None)

Return type:

StructuredLogger

class logstruct.StructuredLogger(name)[source]

A structured logger forwarding log calls to an underlying stdlib logger with the same name.

The core difference over the stdlib is passing kwargs as the extra dict. It isn’t necessary to use this class to make use of the structured formatter.

Not all methods are proxied. Use the StructuredLogger.logger attribute to reach the stdlib logger.

Parameters:

name (str | None)

__init__(name)[source]

Initialise the underlying stdlib logger.

Parameters:

name (str | None) – Underlying stdlib logger name, None means the root logger.

Return type:

None

logger: Logger

Underlying stdlib logger.

property name: str

Get the name of the underlying logger.

property level: int

Get the log level of the underlying logger.

setLevel(level)[source]

Set log level of the underlying logger.

Parameters:

level (int)

Return type:

None

getEffectiveLevel()[source]

Get the effective log level of the underlying logger.

Return type:

int

isEnabledFor(level)[source]

Check if the underlying logger is enabled for this method.

Parameters:

level (int)

Return type:

bool

property parent: Logger | None

Get the parent of the underlying stdlib logger.

property handlers: list[Handler]

Get handlers of the underlying stdlib logger.

debug(msg, *args, exc_info=None, stack_info=False, stacklevel=1, extra=None, **kwargs)[source]

Delegate a debug call to the underlying logger, merging leftover kwargs into extra.

Parameters:
Return type:

None

info(msg, *args, exc_info=None, stack_info=False, stacklevel=1, extra=None, **kwargs)[source]

Delegate a info call to the underlying logger, merging leftover kwargs into extra.

Parameters:
Return type:

None

warning(msg, *args, exc_info=None, stack_info=False, stacklevel=1, extra=None, **kwargs)[source]

Delegate a warning call to the underlying logger, merging leftover kwargs into extra.

Parameters:
Return type:

None

error(msg, *args, exc_info=None, stack_info=False, stacklevel=1, extra=None, **kwargs)[source]

Delegate an error call to the underlying logger, merging leftover kwargs into extra.

Parameters:
Return type:

None

exception(msg, *args, exc_info=True, stack_info=False, stacklevel=1, extra=None, **kwargs)[source]

Call error with exc_info=True.

Parameters:
Return type:

None

critical(msg, *args, exc_info=None, stack_info=False, stacklevel=1, extra=None, **kwargs)[source]

Delegate a critical call to the underlying logger, merging leftover kwargs into extra.

Parameters:
Return type:

None

log(level, msg, *args, exc_info=None, stack_info=False, stacklevel=1, extra=None, **kwargs)[source]

Delegate a log call to the underlying logger, merging leftover kwargs into extra.

Parameters:
Return type:

None

Context

logstruct.context_scope(**kwargs)[source]

Push variables to the context on enter, restore context on exit.

>>> from logstruct import context_scope, get_context
>>> with context_scope(a=11, b=22):
...     print(get_context())
...
...     with context_scope(a=222, c=33):
...         print(get_context())
...     print(get_context())
{'a': 11, 'b': 22}
{'a': 222, 'c': 33, 'b': 22}
{'a': 11, 'b': 22}
Parameters:

kwargs (object)

Return type:

Iterator[None]

logstruct.add_context(**kwargs)[source]

Associate context key-value pairs with the current scope.

If running without a scope, key-value pairs will be associated with the global scope. They will remain there until cleared.

Parameters:

kwargs (object)

Return type:

None

logstruct.remove_context(*keys)[source]

Disassociate keys from the current scope, leaving other scopes unaffected.

Parameters:

keys (str)

Return type:

None

logstruct.clear_scope()[source]

Clear the current context scope, leaving enclosing scopes unaffected.

Return type:

None

logstruct.get_context()[source]

Get current context as dict, topmost keys win over later keys.

Return type:

dict[str, Any]

Formatting

class logstruct.StructuredFormatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None, structured_formatter_config=None, **kwargs)[source]

A logging formatter that turns LogRecords into structured data.

Parameters:
usesTime()[source]

Check if “asctime” should be assigned to the incoming log record.

Unlike logging.Formatter.formatTime, which checks if “asctime” is used in the line format string, StructuredFormatter doesn’t use format strings, so StructuredFormatterConfig.uses_time is returned.

Return type:

bool

format(record)[source]

Format the specified record according to the config.

Key-value pairs are discovered in the log record, the context (unless disabled), and the extra dict passed to the log call. They are merged into a single dict with precedence: extras, context, record.

Mostly a clone of logging.Formatter.format but writes structured data. The self.formatMessage, method, which normally produces a log line prefix, is not called since record attributes are included as data instead. The message itself is still formatted by calling record.getMessage() if enabled by the config.

The reason for mutating the record is compatibility with logging.Formatter which does the same thing.

Parameters:

record (LogRecord)

Return type:

str

class logstruct.StructuredFormatterConfig(format_message=True, uses_time=True, log_fields=(LogField(source='asctime', dest='time', condition=<class 'bool'>), LogField(source='name', dest='logger', condition=None), LogField(source='levelname', dest='level', condition=None), LogField(source='funcName', dest='func', condition=None), LogField(source='lineno', dest='line', condition=None), LogField(source='message', dest='message', condition=None), LogField(source='exc_text', dest='exc_text', condition=<class 'bool'>), LogField(source='stack_info', dest='stack_info', condition=<class 'bool'>)), get_context_fn=<function get_context>, dumps_fn=functools.partial(<function dumps>, default=<built-in function repr>))[source]

Config struct defining all logstruct-specific StructuredFormatter configuration.

It allows to control stdlib conventions:

  • format_message: whether log message formatting should take place

  • uses_time: whether current time should be assigned to LogRecord.asctime

It defines the way the structured log message is built:

  • log_fields: how LogRecord attributes are mapped to produced key-vals.

  • get_context_fn: the function to pull context variables from, which get merged with produced key-vals.

  • dumps_fn: function to serialise produced key-vals into a string

There is no way to prevent StructuredLogger.log call keyword args from being merged into the produced key-vals.

Parameters:
format_message: bool = True

If True, take the message from record.getMessage() otherwise record.msg (unformatted).

uses_time: bool = True

If True, current time will be assigned to LogRecord.asctime. In logging, this depends on the attached “Formatter style” (e.g. logging.PercentStyle), which isn’t useful in structured logging, and is therefore ignored.

log_fields: Sequence[LogField] = (LogField(source='asctime', dest='time', condition=<class 'bool'>), LogField(source='name', dest='logger', condition=None), LogField(source='levelname', dest='level', condition=None), LogField(source='funcName', dest='func', condition=None), LogField(source='lineno', dest='line', condition=None), LogField(source='message', dest='message', condition=None), LogField(source='exc_text', dest='exc_text', condition=<class 'bool'>), LogField(source='stack_info', dest='stack_info', condition=<class 'bool'>))

log_fields configure how logging.LogRecord attributes map to the produced key-vals.

A major difference from structlog is that by default the log message goes to the “message” key rather than “event”.

For example, this configuration:

(
    LogField("asctime", "time", bool),
    LogField(lambda log_record: f"{log_record.pathname}:{log_record.lineno}", "loc"),
    LogField("message", "message"),
)

produces logs that look like (excluding formatting):

{
    "time": "2025-02-09 19:03:56",
    "loc": "/path/to/file.py:30",
    "message": "A message"
}
get_context_fn()

Provides context variables.

Return type:

dict[str, Any]

dumps_fn(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=<built-in function repr>, sort_keys=False, **kw)

By default dumps_fn is json.dumps() which will apply repr() to otherwise unserialisable objects, however any serialiser func can be used.

class logstruct.LogField(source: str | Callable[[LogRecord], Any] | None, dest: str | None, condition: Callable[[Any], bool] | None = None)[source]
class logstruct.LogField(*, log_record_attr: str | Callable[[LogRecord], Any], struct_key: str, condition: Callable[[Any], bool] | None = None)
class logstruct.LogField(source: str | Callable[[LogRecord], Any], *, struct_key: str, condition: Callable[[Any], bool] | None = None)

A mapping of a single logging.LogRecord attribute or callable to its corresponding output dict key.

Warning

  • log_record_attr is deprecated in favour of source

  • struct_key is deprecated in favour of dest

Please use source and dest names if creating LogFields from kwargs. The deprecated keyword args will remain supported till 1.0.

May contain an optional inclusion condition.

Parameters:
source: str | Callable[[LogRecord], Any]

LogRecord attr or callable taking LogRecord and returning a string.

dest: str

Output dict key.

condition: Callable[[Any], bool] | None = None

Optional condition - if supplied, receives the value produced according to the source attribute and decides whether to include the produced key-val in the output dict.

logstruct.make_friendly_dump_fn(level_key='level', logger_name_key='logger', line_key='line', time_key='time', func_key='func', message_key='message', exc_text_key='exc_text', stack_info_key='stack_info', dumps_fn=functools.partial(<function dumps>, default=<built-in function repr>), colours=False)[source]

Build a function serialising structured data in a developer-friendly way.

Default values for *_key parameters correspond to default formatter config.

A typical message looks like:

2024-08-07 23:10:06,605 INFO     __main__:<module>:35 A message {"key": "val"}

This is not meant to be the only way to serialise logged data in development. Users can supply their own friendly dump function.

Parameters:
Return type:

Callable[[dict[str, object]], str]

logstruct.CONFIG_FORMATTED_MESSAGE

Default configuration that includes most relevant LogRecord fields in produced “structured” logs.

logstruct.StructuredFormatterConfig(
    format_message=True,
    uses_time=True,
    log_fields=(
        logstruct.LogField(source="asctime", dest="time", condition=bool),
        logstruct.LogField(source="name", dest="logger", condition=None),
        logstruct.LogField(source="levelname", dest="level", condition=None),
        logstruct.LogField(source="funcName", dest="func", condition=None),
        logstruct.LogField(source="lineno", dest="line", condition=None),
        logstruct.LogField(source="message", dest="message", condition=None),
        logstruct.LogField(source="exc_text", dest="exc_text", condition=bool),
        logstruct.LogField(source="stack_info", dest="stack_info", condition=bool),
    ),
    get_context_fn=logstruct.get_context,
    dumps_fn=functools.partial(json.dumps, default=repr),
)
logstruct.CONFIG_RAW_MESSAGE

A variant of the default config that preserves the raw message and adds an extra "positional_args" key.

logstruct.StructuredFormatterConfig(
    format_message=False,
    uses_time=True,
    log_fields=(
        logstruct.LogField(source="asctime", dest="time", condition=bool),
        logstruct.LogField(source="name", dest="logger", condition=None),
        logstruct.LogField(source="levelname", dest="level", condition=None),
        logstruct.LogField(source="funcName", dest="func", condition=None),
        logstruct.LogField(source="lineno", dest="line", condition=None),
        logstruct.LogField(source="message", dest="message", condition=None),
        logstruct.LogField(source="exc_text", dest="exc_text", condition=bool),
        logstruct.LogField(source="stack_info", dest="stack_info", condition=bool),
        logstruct.LogField(source="args", dest="positional_args", condition=bool),
    ),
    get_context_fn=logstruct.get_context,
    dumps_fn=functools.partial(json.dumps, default=repr),
)
logstruct.DEFAULT_DUMPS_FN
functools.partial(json.dumps, default=repr)
logstruct.DEFAULT_LOG_FIELDS

log_fields used in CONFIG_FORMATTED_MESSAGE.

(
    logstruct.LogField(source="asctime", dest="time", condition=bool),
    logstruct.LogField(source="name", dest="logger", condition=None),
    logstruct.LogField(source="levelname", dest="level", condition=None),
    logstruct.LogField(source="funcName", dest="func", condition=None),
    logstruct.LogField(source="lineno", dest="line", condition=None),
    logstruct.LogField(source="message", dest="message", condition=None),
    logstruct.LogField(source="exc_text", dest="exc_text", condition=bool),
    logstruct.LogField(source="stack_info", dest="stack_info", condition=bool),
)