|
9 | 9 |
|
10 | 10 | from __future__ import annotations
|
11 | 11 |
|
12 |
| -import asyncio |
13 |
| -import contextvars |
14 | 12 | import logging
|
15 |
| -import sys |
16 | 13 |
|
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 |
22 | 15 |
|
23 | 16 |
|
24 | 17 | # Adapted from the stdlib
|
@@ -71,209 +64,3 @@ def add_log_level(
|
71 | 64 | event_dict["level"] = method_name
|
72 | 65 |
|
73 | 66 | 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