diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3a072a..2fc744e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,10 @@ So please make sure to **always** properly configure your applications. [#392](https://github.com/hynek/structlog/pull/392) - Monkeypatched `sys.stdout`s are now handled more gracefully by `ConsoleRenderer` (that's used by default). [#404](https://github.com/hynek/structlog/pull/404) +- `structlog.stdlib.render_to_log_kwargs()` now correctly handles the presence of `exc_info`, `stack_info`, and `stackLevel` in the event dictionary. + They are transformed into proper keyword arguments instead of putting them into the `extra` dictionary. + [#424](https://github.com/hynek/structlog/issues/424), + [#427](https://github.com/hynek/structlog/issues/427) ## [21.5.0](https://github.com/hynek/structlog/compare/21.4.0...21.5.0) - 2021-12-16 diff --git a/conftest.py b/conftest.py index d48e530e..10cb5834 100644 --- a/conftest.py +++ b/conftest.py @@ -41,8 +41,8 @@ def _sio(): return StringIO() -@pytest.fixture -def event_dict(): +@pytest.fixture(name="event_dict") +def _event_dict(): """ An example event dictionary with multiple value types w/o the event itself. """ diff --git a/src/structlog/stdlib.py b/src/structlog/stdlib.py index 34a257e5..f6ad2b12 100644 --- a/src/structlog/stdlib.py +++ b/src/structlog/stdlib.py @@ -738,8 +738,18 @@ def render_to_log_kwargs( This allows you to defer formatting to `logging`. .. versionadded:: 17.1.0 + .. versionchanged:: 22.1.0 ``exc_info``, ``stack_info``, and ``stackLevel`` + are passed as proper kwargs and not put into ``extra``. """ - return {"msg": event_dict.pop("event"), "extra": event_dict} + return { + "msg": event_dict.pop("event"), + "extra": event_dict, + **{ + kw: event_dict.pop(kw) + for kw in ("exc_info", "stack_info", "stackLevel") + if kw in event_dict + }, + } class ProcessorFormatter(logging.Formatter): diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py index 4847b4d2..ac09f4bb 100644 --- a/tests/test_stdlib.py +++ b/tests/test_stdlib.py @@ -624,6 +624,34 @@ def test_add_extra_event_dict(self, event_dict): assert {"msg": "message", "extra": event_dict} == d + def test_handles_special_kw(self, event_dict): + """ + "exc_info", "stack_info", and "stackLevel" aren't passed as extras. + + Cf. https://github.com/hynek/structlog/issues/424 + """ + del event_dict["a"] # needs a repr + event_dict["event"] = "message" + + event_dict["exc_info"] = True + event_dict["stack_info"] = False + event_dict["stackLevel"] = 1 + + d = render_to_log_kwargs(None, None, event_dict) + + assert { + "msg": "message", + "exc_info": True, + "stack_info": False, + "stackLevel": 1, + "extra": { + "b": [3, 4], + "x": 7, + "y": "test", + "z": (1, 2), + }, + } == d + @pytest.fixture(name="configure_for_processor_formatter") def _configure_for_processor_formatter():