Skip to content

Commit 1475ed9

Browse files
authored
stdlib: add callsite collection support for async methods (#618)
* stdlib: add callsite collection support for async methods fixes #615 * Put change notices where people notice them
1 parent 0a93f82 commit 1475ed9

File tree

3 files changed

+29
-11
lines changed

3 files changed

+29
-11
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/
2323
- The `structlog.processors.CallsiteParameterAdder` can now be pickled.
2424
[#603](https://github.com/hynek/structlog/pull/603)
2525

26+
- `structlog.processors.CallsiteParameterAdder` now also works with `structlog.stdlib.BoundLogger`'s non-standard async methods (`ainfo()`, and so forth)
27+
[#618](https://github.com/hynek/structlog/pull/618)
28+
2629

2730
### Changed
2831

src/structlog/stdlib.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ class BoundLogger(BoundLoggerBase):
144144
145145
.. versionadded:: 23.1.0
146146
Async variants `alog()`, `adebug()`, `ainfo()`, and so forth.
147+
148+
.. versionchanged:: 24.2.0
149+
Callsite parameters are now also collected by
150+
`structlog.processors.CallsiteParameterAdder` for async log methods.
147151
"""
148152

149153
_logger: logging.Logger
@@ -393,12 +397,16 @@ async def _dispatch_to_sync(
393397
"""
394398
Merge contextvars and log using the sync logger in a thread pool.
395399
"""
400+
scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back.f_back) # type: ignore[union-attr, arg-type, unused-ignore]
396401
ctx = contextvars.copy_context()
397402

398-
await asyncio.get_running_loop().run_in_executor(
399-
None,
400-
lambda: ctx.run(lambda: meth(event, *args, **kw)),
401-
)
403+
try:
404+
await asyncio.get_running_loop().run_in_executor(
405+
None,
406+
lambda: ctx.run(lambda: meth(event, *args, **kw)),
407+
)
408+
finally:
409+
_ASYNC_CALLING_STACK.reset(scs_token)
402410

403411
async def adebug(self, event: str, *args: Any, **kw: Any) -> None:
404412
"""
@@ -499,6 +507,8 @@ class AsyncBoundLogger:
499507
.. versionchanged:: 20.2.0 fix _dispatch_to_sync contextvars usage
500508
.. deprecated:: 23.1.0
501509
Use the regular `BoundLogger` with its a-prefixed methods instead.
510+
.. versionchanged:: 23.3.0
511+
Callsite parameters are now also collected for async log methods.
502512
"""
503513

504514
__slots__ = ("sync_bl", "_loop")
@@ -594,8 +604,6 @@ async def _dispatch_to_sync(
594604
) -> None:
595605
"""
596606
Merge contextvars and log using the sync logger in a thread pool.
597-
.. versionchanged:: 23.3.0
598-
Callsite parameters are now also collected under asyncio.
599607
"""
600608
scs_token = _ASYNC_CALLING_STACK.set(sys._getframe().f_back.f_back) # type: ignore[union-attr, arg-type, unused-ignore]
601609
ctx = contextvars.copy_context()

tests/processors/test_processors.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -298,28 +298,35 @@ def test_all_parameters(self) -> None:
298298
assert self.parameter_strings == self.get_callsite_parameters().keys()
299299

300300
@pytest.mark.asyncio()
301-
async def test_async(self) -> None:
301+
@pytest.mark.parametrize(
302+
("wrapper_class", "method_name"),
303+
[
304+
(structlog.stdlib.BoundLogger, "ainfo"),
305+
(structlog.stdlib.AsyncBoundLogger, "info"),
306+
],
307+
)
308+
async def test_async(self, wrapper_class, method_name) -> None:
302309
"""
303310
Callsite information for async invocations are correct.
304311
"""
305312
string_io = StringIO()
306313

307-
class StingIOLogger(structlog.PrintLogger):
314+
class StringIOLogger(structlog.PrintLogger):
308315
def __init__(self):
309316
super().__init__(file=string_io)
310317

311318
processor = self.make_processor(None, ["concurrent", "threading"])
312319
structlog.configure(
313320
processors=[processor, JSONRenderer()],
314-
logger_factory=StingIOLogger,
315-
wrapper_class=structlog.stdlib.AsyncBoundLogger,
321+
logger_factory=StringIOLogger,
322+
wrapper_class=wrapper_class,
316323
cache_logger_on_first_use=True,
317324
)
318325

319326
logger = structlog.stdlib.get_logger()
320327

321328
callsite_params = self.get_callsite_parameters()
322-
await logger.info("baz")
329+
await getattr(logger, method_name)("baz")
323330
logger_params = json.loads(string_io.getvalue())
324331

325332
# These are different when running under async

0 commit comments

Comments
 (0)