From 7a12eae6d0edafcb88b02c81a5bea01bfec2f148 Mon Sep 17 00:00:00 2001 From: Alex Couper Date: Sat, 15 Jul 2023 11:48:27 +0000 Subject: [PATCH] Allow positional args in `exception` --- src/structlog/_log_levels.py | 12 ++++++++---- tests/test_log_levels.py | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/structlog/_log_levels.py b/src/structlog/_log_levels.py index d3863a02..8a3a384f 100644 --- a/src/structlog/_log_levels.py +++ b/src/structlog/_log_levels.py @@ -80,13 +80,17 @@ async def _anop(self: Any, event: str, *args: Any, **kw: Any) -> Any: return None -def exception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: +def exception( + self: FilteringBoundLogger, event: str, *args: Any, **kw: Any +) -> Any: kw.setdefault("exc_info", True) - return self.error(event, **kw) + return self.error(event, *args, **kw) -async def aexception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: +async def aexception( + self: FilteringBoundLogger, event: str, *args: Any, **kw: Any +) -> Any: # Exception info has to be extracted this early, because it is no longer # available once control is passed to the executor. if kw.get("exc_info", True) is True: @@ -95,7 +99,7 @@ async def aexception(self: FilteringBoundLogger, event: str, **kw: Any) -> Any: ctx = contextvars.copy_context() return await asyncio.get_running_loop().run_in_executor( None, - lambda: ctx.run(lambda: self.error(event, **kw)), + lambda: ctx.run(lambda: self.error(event, *args, **kw)), ) diff --git a/tests/test_log_levels.py b/tests/test_log_levels.py index fb4075af..f04e5103 100644 --- a/tests/test_log_levels.py +++ b/tests/test_log_levels.py @@ -195,6 +195,24 @@ async def test_async_exception(self, bl, cl): assert isinstance(cl.calls[0][2]["exc_info"], tuple) assert exc == cl.calls[0][2]["exc_info"][1] + def test_exception_positional_args(self, bl, cl): + """ + exception allows for positional args + """ + bl.exception("%s %s", "boom", "bastic") + + assert [ + ("error", (), {"event": "boom bastic", "exc_info": True}) + ] == cl.calls + + async def test_aexception_positional_args(self, bl, cl): + """ + aexception allows for positional args + """ + await bl.aexception("%s %s", "boom", "bastic") + assert 1 == len(cl.calls) + assert "boom bastic" == cl.calls[0][2]["event"] + async def test_async_exception_true(self, bl, cl): """ aexception replaces exc_info with current exception info, if exc_info