mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-138162: Fix logging.LoggerAdapter with merge_extra=True and without the extra argument (GH-140511)
This commit is contained in:
parent
622d97b8bb
commit
327dbbedff
4 changed files with 50 additions and 11 deletions
|
|
@ -1082,12 +1082,13 @@ LoggerAdapter Objects
|
||||||
information into logging calls. For a usage example, see the section on
|
information into logging calls. For a usage example, see the section on
|
||||||
:ref:`adding contextual information to your logging output <context-info>`.
|
:ref:`adding contextual information to your logging output <context-info>`.
|
||||||
|
|
||||||
.. class:: LoggerAdapter(logger, extra, merge_extra=False)
|
.. class:: LoggerAdapter(logger, extra=None, merge_extra=False)
|
||||||
|
|
||||||
Returns an instance of :class:`LoggerAdapter` initialized with an
|
Returns an instance of :class:`LoggerAdapter` initialized with an
|
||||||
underlying :class:`Logger` instance, a dict-like object (*extra*), and a
|
underlying :class:`Logger` instance, an optional dict-like object (*extra*),
|
||||||
boolean (*merge_extra*) indicating whether or not the *extra* argument of
|
and an optional boolean (*merge_extra*) indicating whether or not
|
||||||
individual log calls should be merged with the :class:`LoggerAdapter` extra.
|
the *extra* argument of individual log calls should be merged with
|
||||||
|
the :class:`LoggerAdapter` extra.
|
||||||
The default behavior is to ignore the *extra* argument of individual log
|
The default behavior is to ignore the *extra* argument of individual log
|
||||||
calls and only use the one of the :class:`LoggerAdapter` instance
|
calls and only use the one of the :class:`LoggerAdapter` instance
|
||||||
|
|
||||||
|
|
@ -1127,9 +1128,13 @@ information into logging calls. For a usage example, see the section on
|
||||||
Attribute :attr:`!manager` and method :meth:`!_log` were added, which
|
Attribute :attr:`!manager` and method :meth:`!_log` were added, which
|
||||||
delegate to the underlying logger and allow adapters to be nested.
|
delegate to the underlying logger and allow adapters to be nested.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.10
|
||||||
|
|
||||||
|
The *extra* argument is now optional.
|
||||||
|
|
||||||
.. versionchanged:: 3.13
|
.. versionchanged:: 3.13
|
||||||
|
|
||||||
The *merge_extra* argument was added.
|
The *merge_extra* parameter was added.
|
||||||
|
|
||||||
|
|
||||||
Thread Safety
|
Thread Safety
|
||||||
|
|
|
||||||
|
|
@ -1849,9 +1849,9 @@ class LoggerAdapter(object):
|
||||||
|
|
||||||
def __init__(self, logger, extra=None, merge_extra=False):
|
def __init__(self, logger, extra=None, merge_extra=False):
|
||||||
"""
|
"""
|
||||||
Initialize the adapter with a logger and a dict-like object which
|
Initialize the adapter with a logger and an optional dict-like object
|
||||||
provides contextual information. This constructor signature allows
|
which provides contextual information. This constructor signature
|
||||||
easy stacking of LoggerAdapters, if so desired.
|
allows easy stacking of LoggerAdapters, if so desired.
|
||||||
|
|
||||||
You can effectively pass keyword arguments as shown in the
|
You can effectively pass keyword arguments as shown in the
|
||||||
following example:
|
following example:
|
||||||
|
|
@ -1882,8 +1882,9 @@ def process(self, msg, kwargs):
|
||||||
Normally, you'll only need to override this one method in a
|
Normally, you'll only need to override this one method in a
|
||||||
LoggerAdapter subclass for your specific needs.
|
LoggerAdapter subclass for your specific needs.
|
||||||
"""
|
"""
|
||||||
if self.merge_extra and "extra" in kwargs:
|
if self.merge_extra and kwargs.get("extra") is not None:
|
||||||
kwargs["extra"] = {**self.extra, **kwargs["extra"]}
|
if self.extra is not None:
|
||||||
|
kwargs["extra"] = {**self.extra, **kwargs["extra"]}
|
||||||
else:
|
else:
|
||||||
kwargs["extra"] = self.extra
|
kwargs["extra"] = self.extra
|
||||||
return msg, kwargs
|
return msg, kwargs
|
||||||
|
|
|
||||||
|
|
@ -5826,7 +5826,7 @@ def cleanup():
|
||||||
|
|
||||||
self.addCleanup(cleanup)
|
self.addCleanup(cleanup)
|
||||||
self.addCleanup(logging.shutdown)
|
self.addCleanup(logging.shutdown)
|
||||||
self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None)
|
self.adapter = logging.LoggerAdapter(logger=self.logger)
|
||||||
|
|
||||||
def test_exception(self):
|
def test_exception(self):
|
||||||
msg = 'testing exception: %r'
|
msg = 'testing exception: %r'
|
||||||
|
|
@ -5997,6 +5997,18 @@ def test_extra_merged(self):
|
||||||
self.assertEqual(record.foo, '1')
|
self.assertEqual(record.foo, '1')
|
||||||
self.assertEqual(record.bar, '2')
|
self.assertEqual(record.bar, '2')
|
||||||
|
|
||||||
|
self.adapter.critical('no extra') # should not fail
|
||||||
|
self.assertEqual(len(self.recording.records), 2)
|
||||||
|
record = self.recording.records[-1]
|
||||||
|
self.assertEqual(record.foo, '1')
|
||||||
|
self.assertNotHasAttr(record, 'bar')
|
||||||
|
|
||||||
|
self.adapter.critical('none extra', extra=None) # should not fail
|
||||||
|
self.assertEqual(len(self.recording.records), 3)
|
||||||
|
record = self.recording.records[-1]
|
||||||
|
self.assertEqual(record.foo, '1')
|
||||||
|
self.assertNotHasAttr(record, 'bar')
|
||||||
|
|
||||||
def test_extra_merged_log_call_has_precedence(self):
|
def test_extra_merged_log_call_has_precedence(self):
|
||||||
self.adapter = logging.LoggerAdapter(logger=self.logger,
|
self.adapter = logging.LoggerAdapter(logger=self.logger,
|
||||||
extra={'foo': '1'},
|
extra={'foo': '1'},
|
||||||
|
|
@ -6008,6 +6020,25 @@ def test_extra_merged_log_call_has_precedence(self):
|
||||||
self.assertHasAttr(record, 'foo')
|
self.assertHasAttr(record, 'foo')
|
||||||
self.assertEqual(record.foo, '2')
|
self.assertEqual(record.foo, '2')
|
||||||
|
|
||||||
|
def test_extra_merged_without_extra(self):
|
||||||
|
self.adapter = logging.LoggerAdapter(logger=self.logger,
|
||||||
|
merge_extra=True)
|
||||||
|
|
||||||
|
self.adapter.critical('foo should be here', extra={'foo': '1'})
|
||||||
|
self.assertEqual(len(self.recording.records), 1)
|
||||||
|
record = self.recording.records[-1]
|
||||||
|
self.assertEqual(record.foo, '1')
|
||||||
|
|
||||||
|
self.adapter.critical('no extra') # should not fail
|
||||||
|
self.assertEqual(len(self.recording.records), 2)
|
||||||
|
record = self.recording.records[-1]
|
||||||
|
self.assertNotHasAttr(record, 'foo')
|
||||||
|
|
||||||
|
self.adapter.critical('none extra', extra=None) # should not fail
|
||||||
|
self.assertEqual(len(self.recording.records), 3)
|
||||||
|
record = self.recording.records[-1]
|
||||||
|
self.assertNotHasAttr(record, 'foo')
|
||||||
|
|
||||||
|
|
||||||
class PrefixAdapter(logging.LoggerAdapter):
|
class PrefixAdapter(logging.LoggerAdapter):
|
||||||
prefix = 'Adapter'
|
prefix = 'Adapter'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix :class:`logging.LoggerAdapter` with ``merge_extra=True`` and without the
|
||||||
|
*extra* argument.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue