Skip to content

Commit 683c70f

Browse files
committed
Move native loggers into a separate, named module
1 parent d3150de commit 683c70f

File tree

4 files changed

+238
-216
lines changed

4 files changed

+238
-216
lines changed

src/structlog/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
wrap_logger,
3030
)
3131
from structlog._generic import BoundLogger
32-
from structlog._log_levels import make_filtering_bound_logger
32+
from structlog._native import make_filtering_bound_logger
3333
from structlog._output import (
3434
BytesLogger,
3535
BytesLoggerFactory,

src/structlog/_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from typing import Any, Callable, Iterable, Sequence, Type, cast
1717

18-
from ._log_levels import make_filtering_bound_logger
18+
from ._native import make_filtering_bound_logger
1919
from ._output import PrintLoggerFactory
2020
from .contextvars import merge_contextvars
2121
from .dev import ConsoleRenderer, _has_colors, set_exc_info

src/structlog/_log_levels.py

Lines changed: 1 addition & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,9 @@
99

1010
from __future__ import annotations
1111

12-
import asyncio
13-
import contextvars
1412
import logging
15-
import sys
1613

17-
from typing import Any, Callable
18-
19-
from ._base import BoundLoggerBase
20-
from .contextvars import _ASYNC_CALLING_STACK
21-
from .typing import EventDict, FilteringBoundLogger
14+
from .typing import EventDict
2215

2316

2417
# Adapted from the stdlib
@@ -71,209 +64,3 @@ def add_log_level(
7164
event_dict["level"] = method_name
7265

7366
return event_dict
74-
75-
76-
def _nop(self: Any, event: str, *args: Any, **kw: Any) -> Any:
77-
return None
78-
79-
80-
async def _anop(self: Any, event: str, *args: Any, **kw: Any) -> Any:
81-
return None
82-
83-
84-
def exception(
85-
self: FilteringBoundLogger, event: str, *args: Any, **kw: Any
86-
) -> Any:
87-
kw.setdefault("exc_info", True)
88-
89-
return self.error(event, *args, **kw)
90-
91-
92-
async def aexception(
93-
self: FilteringBoundLogger, event: str, *args: Any, **kw: Any
94-
) -> Any:
95-
"""
96-
.. versionchanged:: 23.3.0
97-
Callsite parameters are now also collected under asyncio.
98-
"""
99-
# Exception info has to be extracted this early, because it is no longer
100-
# available once control is passed to the executor.
101-
if kw.get("exc_info", True) is True:
102-
kw["exc_info"] = sys.exc_info()
103-
104-
scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type]
105-
ctx = contextvars.copy_context()
106-
try:
107-
runner = await asyncio.get_running_loop().run_in_executor(
108-
None,
109-
lambda: ctx.run(lambda: self.error(event, *args, **kw)),
110-
)
111-
finally:
112-
_ASYNC_CALLING_STACK.reset(scs_token)
113-
114-
return runner
115-
116-
117-
def make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]:
118-
"""
119-
Create a new `FilteringBoundLogger` that only logs *min_level* or higher.
120-
121-
The logger is optimized such that log levels below *min_level* only consist
122-
of a ``return None``.
123-
124-
All familiar log methods are present, with async variants of each that are
125-
prefixed by an ``a``. Therefore, the async version of ``log.info("hello")``
126-
is ``await log.ainfo("hello")``.
127-
128-
Additionally it has a ``log(self, level: int, **kw: Any)`` method to mirror
129-
`logging.Logger.log` and `structlog.stdlib.BoundLogger.log`.
130-
131-
Compared to using *structlog*'s standard library integration and the
132-
`structlog.stdlib.filter_by_level` processor:
133-
134-
- It's faster because once the logger is built at program start; it's a
135-
static class.
136-
- For the same reason you can't change the log level once configured. Use
137-
the dynamic approach of `standard-library` instead, if you need this
138-
feature.
139-
- You *can* have (much) more fine-grained filtering by :ref:`writing a
140-
simple processor <finer-filtering>`.
141-
142-
Args:
143-
min_level:
144-
The log level as an integer. You can use the constants from
145-
`logging` like ``logging.INFO`` or pass the values directly. See
146-
`this table from the logging docs
147-
<https://docs.python.org/3/library/logging.html#levels>`_ for
148-
possible values.
149-
150-
.. versionadded:: 20.2.0
151-
.. versionchanged:: 21.1.0 The returned loggers are now pickleable.
152-
.. versionadded:: 20.1.0 The ``log()`` method.
153-
.. versionadded:: 22.2.0
154-
Async variants ``alog()``, ``adebug()``, ``ainfo()``, and so forth.
155-
"""
156-
157-
return _LEVEL_TO_FILTERING_LOGGER[min_level]
158-
159-
160-
def _make_filtering_bound_logger(min_level: int) -> type[FilteringBoundLogger]:
161-
"""
162-
Create a new `FilteringBoundLogger` that only logs *min_level* or higher.
163-
164-
The logger is optimized such that log levels below *min_level* only consist
165-
of a ``return None``.
166-
"""
167-
168-
def make_method(
169-
level: int,
170-
) -> tuple[Callable[..., Any], Callable[..., Any]]:
171-
if level < min_level:
172-
return _nop, _anop
173-
174-
name = _LEVEL_TO_NAME[level]
175-
176-
def meth(self: Any, event: str, *args: Any, **kw: Any) -> Any:
177-
if not args:
178-
return self._proxy_to_logger(name, event, **kw)
179-
180-
return self._proxy_to_logger(name, event % args, **kw)
181-
182-
async def ameth(self: Any, event: str, *args: Any, **kw: Any) -> Any:
183-
"""
184-
.. versionchanged:: 23.3.0
185-
Callsite parameters are now also collected under asyncio.
186-
"""
187-
if args:
188-
event = event % args
189-
190-
scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type]
191-
ctx = contextvars.copy_context()
192-
try:
193-
await asyncio.get_running_loop().run_in_executor(
194-
None,
195-
lambda: ctx.run(
196-
lambda: self._proxy_to_logger(name, event, **kw)
197-
),
198-
)
199-
finally:
200-
_ASYNC_CALLING_STACK.reset(scs_token)
201-
202-
meth.__name__ = name
203-
ameth.__name__ = f"a{name}"
204-
205-
return meth, ameth
206-
207-
def log(self: Any, level: int, event: str, *args: Any, **kw: Any) -> Any:
208-
if level < min_level:
209-
return None
210-
name = _LEVEL_TO_NAME[level]
211-
212-
if not args:
213-
return self._proxy_to_logger(name, event, **kw)
214-
215-
return self._proxy_to_logger(name, event % args, **kw)
216-
217-
async def alog(
218-
self: Any, level: int, event: str, *args: Any, **kw: Any
219-
) -> Any:
220-
"""
221-
.. versionchanged:: 23.3.0
222-
Callsite parameters are now also collected under asyncio.
223-
"""
224-
if level < min_level:
225-
return None
226-
name = _LEVEL_TO_NAME[level]
227-
if args:
228-
event = event % args
229-
230-
scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back) # type: ignore[arg-type]
231-
ctx = contextvars.copy_context()
232-
try:
233-
runner = await asyncio.get_running_loop().run_in_executor(
234-
None,
235-
lambda: ctx.run(
236-
lambda: self._proxy_to_logger(name, event, **kw)
237-
),
238-
)
239-
finally:
240-
_ASYNC_CALLING_STACK.reset(scs_token)
241-
return runner
242-
243-
meths: dict[str, Callable[..., Any]] = {"log": log, "alog": alog}
244-
for lvl, name in _LEVEL_TO_NAME.items():
245-
meths[name], meths[f"a{name}"] = make_method(lvl)
246-
247-
meths["exception"] = exception
248-
meths["aexception"] = aexception
249-
meths["fatal"] = meths["error"]
250-
meths["afatal"] = meths["aerror"]
251-
meths["warn"] = meths["warning"]
252-
meths["awarn"] = meths["awarning"]
253-
meths["msg"] = meths["info"]
254-
meths["amsg"] = meths["ainfo"]
255-
256-
return type(
257-
"BoundLoggerFilteringAt%s"
258-
% (_LEVEL_TO_NAME.get(min_level, "Notset").capitalize()),
259-
(BoundLoggerBase,),
260-
meths,
261-
)
262-
263-
264-
# Pre-create all possible filters to make them pickleable.
265-
BoundLoggerFilteringAtNotset = _make_filtering_bound_logger(NOTSET)
266-
BoundLoggerFilteringAtDebug = _make_filtering_bound_logger(DEBUG)
267-
BoundLoggerFilteringAtInfo = _make_filtering_bound_logger(INFO)
268-
BoundLoggerFilteringAtWarning = _make_filtering_bound_logger(WARNING)
269-
BoundLoggerFilteringAtError = _make_filtering_bound_logger(ERROR)
270-
BoundLoggerFilteringAtCritical = _make_filtering_bound_logger(CRITICAL)
271-
272-
_LEVEL_TO_FILTERING_LOGGER = {
273-
CRITICAL: BoundLoggerFilteringAtCritical,
274-
ERROR: BoundLoggerFilteringAtError,
275-
WARNING: BoundLoggerFilteringAtWarning,
276-
INFO: BoundLoggerFilteringAtInfo,
277-
DEBUG: BoundLoggerFilteringAtDebug,
278-
NOTSET: BoundLoggerFilteringAtNotset,
279-
}

0 commit comments

Comments
 (0)