Coverage for stlog/adapter.py: 94%
35 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-21 07:31 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-21 07:31 +0000
1from __future__ import annotations
3import collections
4import logging
5import typing
7from stlog.base import (
8 RESERVED_ATTRS,
9 STLOG_EXTRA_KEY,
10 check_json_types_or_raise,
11)
12from stlog.context import LogContext
15# ligthly adapted from https://github.com/Mergifyio/daiquiri/blob/main/daiquiri/__init__.py
16class _KeywordArgumentAdapter(logging.LoggerAdapter):
17 """Logger adapter to add keyword arguments to log record's extra data.
19 Keywords passed to the log call are added to the "extra"
20 dictionary passed to the underlying logger so they are emitted
21 with the log message and available to the format string.
22 """
24 def process(
25 self, msg: typing.Any, kwargs: collections.abc.MutableMapping[str, typing.Any]
26 ) -> tuple[typing.Any, collections.abc.MutableMapping[str, typing.Any]]:
27 # Make a new extra dictionary combining the values we were
28 # given when we were constructed and anything from kwargs.
29 if self.extra is not None:
30 # kvs passed during getLogger() call
31 check_json_types_or_raise(self.extra)
32 extra = dict(self.extra)
33 if kwargs.get("extra"):
34 # when you use the "extra" standard kwargs at log() time
35 extra.update(kwargs.pop("extra"))
36 # Move any unknown keyword arguments into the extra
37 # dictionary.
38 for name in list(kwargs.keys()):
39 if name in RESERVED_ATTRS:
40 continue
41 extra[name] = kwargs.pop(name)
42 extra[STLOG_EXTRA_KEY] = set(extra.keys())
43 kwargs["extra"] = extra
44 return msg, kwargs
47class StLogLoggerAdapter(_KeywordArgumentAdapter):
48 """stlog `LoggerAdapter` with `stlog.LogContext` support."""
50 def __init__(self, logger, extra, ignore_global_logging_context: bool = False):
51 self.ignore_global_logging_context = ignore_global_logging_context
52 super().__init__(logger, extra)
54 def process(
55 self, msg: typing.Any, kwargs: collections.abc.MutableMapping[str, typing.Any]
56 ) -> tuple[typing.Any, collections.abc.MutableMapping[str, typing.Any]]:
57 if self.ignore_global_logging_context:
58 new_kwargs = dict(kwargs)
59 else:
60 new_kwargs = {**LogContext._get(), **kwargs}
61 return super().process(msg, new_kwargs)
63 def addFilter(self, filter): # noqa: N802
64 self.logger.addFilter(filter)
66 def removeFilter(self, filter): # noqa: N802
67 self.logger.removeFilter(filter)
70def getLogger(name: str | None = None, **kwargs) -> StLogLoggerAdapter: # noqa: N802
71 """Return a standard logger (adapted for `stlog` and `stlog.LogContext` support).
73 You can pass some context key/values in `**kwargs` which will be specific to this logger.
75 If you want to set more globally available context, use `stlog.LogContext` class.
77 Args:
78 name: logger name.
79 """
80 return StLogLoggerAdapter(logging.getLogger(name), kwargs)