From a0c0e68db9adc405d65fd529a7e17c0c026a85af Mon Sep 17 00:00:00 2001 From: Samuel Henrique Date: Sun, 27 Jun 2021 14:25:52 +0100 Subject: [PATCH] bpo-32732: Don't override extra keys on LoggerAdapter --- Doc/howto/logging-cookbook.rst | 8 ++++++-- Doc/library/logging.rst | 5 +++++ Lib/logging/__init__.py | 2 +- Lib/test/test_logging.py | 37 ++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 5777a4c503..c50c3496d7 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -593,8 +593,12 @@ and keyword arguments of the logging call, and it passes back (potentially) modified versions of these to use in the call to the underlying logger. The default implementation of this method leaves the message alone, but inserts an 'extra' key in the keyword argument whose value is the dict-like object -passed to the constructor. Of course, if you had passed an 'extra' keyword -argument in the call to the adapter, it will be silently overwritten. +passed to the constructor. + +.. versionadded:: 3.11 +:meth:`~LoggerAdapter.process` has been changed to not erase any 'extra' keys +provided to :func:`log`. In case of a conlfict of keys, the ones passed to +:func:`log` will take precedence. The advantage of using 'extra' is that the values in the dict-like object are merged into the :class:`LogRecord` instance's __dict__, allowing you to use diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 313cff4ff9..748d5466b3 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -900,6 +900,11 @@ interchangeably. :meth:`~Logger.setLevel` and :meth:`~Logger.hasHandlers` methods were added to :class:`LoggerAdapter`. These methods delegate to the underlying logger. +.. versionadded:: 3.11 +:meth:`~LoggerAdapter.process` has been changed to not erase any 'extra' keys +provided to :func:`log`. In case of a conlfict of keys, the ones passed to +:func:`log` will take precedence. + Thread Safety ------------- diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 3538f0670a..29004895a8 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -1817,7 +1817,7 @@ def process(self, msg, kwargs): Normally, you'll only need to override this one method in a LoggerAdapter subclass for your specific needs. """ - kwargs["extra"] = self.extra + kwargs["extra"] = (self.extra or {}) | (kwargs.get("extra") or {}) return msg, kwargs # diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 48ed2eb2fc..20e3b62e89 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4932,6 +4932,43 @@ def process(self, msg, kwargs): self.assertIs(adapter.manager, orig_manager) self.assertIs(self.logger.manager, orig_manager) + def test_extra(self): + + # Adapter with empty extra + adapter = logging.LoggerAdapter(logger=self.logger) + self.assertEqual( + adapter.process( + msg="", kwargs={"extra": {"log_key": "log_value"}} + ), + ("", {"extra": {"log_key": "log_value"}}), + ) + + # Apend process' extra to Adapter's + # Reset adapter's extra, as it was changed by previous process call + adapter.extra = {"adapter_key": "adapter_value"} + self.assertEqual( + adapter.process( + msg="", kwargs={"extra": {"log_key": "log_value"}} + ), + ( + "", + { + "extra": { + "adapter_key": "adapter_value", + "log_key": "log_value", + } + }, + ), + ) + + # Override adapter value on process' + self.assertEqual( + adapter.process( + msg="", kwargs={"extra": {"adapter_key": "overriden_value"}} + ), + ("", {"extra": {"adapter_key": "overriden_value"}}), + ) + class LoggerTest(BaseTest, AssertErrorMessage): -- 2.30.2