summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/logging.rst64
-rw-r--r--Lib/logging/__init__.py29
-rw-r--r--Lib/test/test_logging.py10
-rw-r--r--Misc/NEWS2
4 files changed, 87 insertions, 18 deletions
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
index 1850cbb..018b16f 100644
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -750,6 +750,19 @@ functions.
# ... override behaviour here
+.. function:: getLogRecordFactory()
+
+ Return a callable which is used to create a :class:`LogRecord`.
+
+ .. versionadded:: 3.2
+
+ This function has been provided, along with :func:`setLogRecordFactory`,
+ to allow developers more control over how the :class:`LogRecord`
+ representing a logging event is constructed.
+
+ See :func:`setLogRecordFactory` for more information about the how the
+ factory is called.
+
.. function:: debug(msg, *args, **kwargs)
Logs a message with level :const:`DEBUG` on the root logger. The *msg* is the
@@ -973,6 +986,34 @@ functions.
function is typically called before any loggers are instantiated by applications
which need to use custom logger behavior.
+.. function:: setLogRecordFactory(factory)
+
+ Set a callable which is used to create a :class:`LogRecord`.
+
+ :param factory: The factory callable to be used to instantiate a log record.
+
+ .. versionadded:: 3.2
+
+ This function has been provided, along with :func:`getLogRecordFactory`, to
+ allow developers more control over how the :class:`LogRecord` representing
+ a logging event is constructed.
+
+ The factory has the following signature.
+
+ factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, \*\*kwargs)
+
+ :name: The logger name.
+ :level: The logging level (numeric).
+ :fn: The full pathname of the file where the logging call was made.
+ :lno: The line number in the file where the logging call was made.
+ :msg: The logging message.
+ :args: The arguments for the logging message.
+ :exc_info: An exception tuple, or None.
+ :func: The name of the function or method which invoked the logging
+ call.
+ :sinfo: A stack traceback such as is provided by
+ :func:`traceback.print_stack`, showing the call hierarchy.
+ :kwargs: Additional keyword arguments.
.. seealso::
@@ -3244,6 +3285,29 @@ wire).
messages, whose ``__str__`` method can return the actual format string to
be used.
+ .. versionchanged:: 3.2
+ The creation of a ``LogRecord`` has been made more configurable by
+ providing a factory which is used to create the record. The factory can be
+ set using :func:`getLogRecordFactory` and :func:`setLogRecordFactory`
+ (see this for the factory's signature).
+
+ This functionality can be used to inject your own values into a
+ LogRecord at creation time. You can use the following pattern::
+
+ old_factory = logging.getLogRecordFactory()
+
+ def record_factory(*args, **kwargs):
+ record = old_factory(*args, **kwargs)
+ record.custom_attribute = 0xdecafbad
+ return record
+
+ logging.setLogRecordFactory(record_factory)
+
+ With this pattern, multiple factories could be chained, and as long
+ as they don't overwrite each other's attributes or unintentionally
+ overwrite the standard attributes listed above, there should be no
+ surprises.
+
.. _logger-adapter:
LoggerAdapter Objects
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index c4229e9..5256f95 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -33,7 +33,7 @@ __all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
'captureWarnings', 'critical', 'debug', 'disable', 'error',
'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass',
'info', 'log', 'makeLogRecord', 'setLoggerClass', 'warn', 'warning',
- 'getLogRecordClass', 'setLogRecordClass']
+ 'getLogRecordFactory', 'setLogRecordFactory']
try:
import codecs
@@ -238,7 +238,7 @@ class LogRecord(object):
information to be logged.
"""
def __init__(self, name, level, pathname, lineno,
- msg, args, exc_info, func=None, sinfo=None):
+ msg, args, exc_info, func=None, sinfo=None, **kwargs):
"""
Initialize a logging record with interesting information.
"""
@@ -322,21 +322,24 @@ class LogRecord(object):
#
# Determine which class to use when instantiating log records.
#
-_logRecordClass = LogRecord
+_logRecordFactory = LogRecord
-def setLogRecordClass(cls):
+def setLogRecordFactory(factory):
"""
Set the class to be used when instantiating a log record.
+
+ :param factory: A callable which will be called to instantiate
+ a log record.
"""
- global _logRecordClass
- _logRecordClass = cls
+ global _logRecordFactory
+ _logRecordFactory = factory
-def getLogRecordClass():
+def getLogRecordFactory():
"""
Return the class to be used when instantiating a log record.
"""
- return _logRecordClass
+ return _logRecordFactory
def makeLogRecord(dict):
"""
@@ -345,7 +348,7 @@ def makeLogRecord(dict):
a socket connection (which is sent as a dictionary) into a LogRecord
instance.
"""
- rv = _logRecordClass(None, None, "", 0, "", (), None, None)
+ rv = _logRecordFactory(None, None, "", 0, "", (), None, None)
rv.__dict__.update(dict)
return rv
@@ -1056,7 +1059,7 @@ class Manager(object):
self.emittedNoHandlerWarning = 0
self.loggerDict = {}
self.loggerClass = None
- self.logRecordClass = None
+ self.logRecordFactory = None
def getLogger(self, name):
"""
@@ -1100,12 +1103,12 @@ class Manager(object):
+ klass.__name__)
self.loggerClass = klass
- def setLogRecordClass(self, cls):
+ def setLogRecordFactory(self, factory):
"""
Set the class to be used when instantiating a log record with this
Manager.
"""
- self.logRecordClass = cls
+ self.logRecordFactory = factory
def _fixupParents(self, alogger):
"""
@@ -1305,7 +1308,7 @@ class Logger(Filterer):
A factory method which can be overridden in subclasses to create
specialized LogRecords.
"""
- rv = _logRecordClass(name, level, fn, lno, msg, args, exc_info, func,
+ rv = _logRecordFactory(name, level, fn, lno, msg, args, exc_info, func,
sinfo)
if extra is not None:
for key in extra:
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 01c3336..cd8cdbd 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -1799,7 +1799,7 @@ class ChildLoggerTest(BaseTest):
class DerivedLogRecord(logging.LogRecord):
pass
-class LogRecordClassTest(BaseTest):
+class LogRecordFactoryTest(BaseTest):
def setUp(self):
class CheckingFilter(logging.Filter):
@@ -1817,17 +1817,17 @@ class LogRecordClassTest(BaseTest):
BaseTest.setUp(self)
self.filter = CheckingFilter(DerivedLogRecord)
self.root_logger.addFilter(self.filter)
- self.orig_cls = logging.getLogRecordClass()
+ self.orig_factory = logging.getLogRecordFactory()
def tearDown(self):
self.root_logger.removeFilter(self.filter)
BaseTest.tearDown(self)
- logging.setLogRecordClass(self.orig_cls)
+ logging.setLogRecordFactory(self.orig_factory)
def test_logrecord_class(self):
self.assertRaises(TypeError, self.root_logger.warning,
self.next_message())
- logging.setLogRecordClass(DerivedLogRecord)
+ logging.setLogRecordFactory(DerivedLogRecord)
self.root_logger.error(self.next_message())
self.assert_log_lines([
('root', 'ERROR', '2'),
@@ -2015,7 +2015,7 @@ def test_main():
ConfigFileTest, SocketHandlerTest, MemoryTest,
EncodingTest, WarningsTest, ConfigDictTest, ManagerTest,
FormatterTest,
- LogRecordClassTest, ChildLoggerTest, QueueHandlerTest,
+ LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest,
RotatingFileHandlerTest,
#TimedRotatingFileHandlerTest
)
diff --git a/Misc/NEWS b/Misc/NEWS
index 7de6838..7796b2f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -33,6 +33,8 @@ Core and Builtins
Library
-------
+- logging: Added getLogRecordFactory/setLogRecordFactory with docs and tests.
+
- Issue #10549: Fix pydoc traceback when text-documenting certain classes.
- Issue #2001: New HTML server with enhanced Web page features. Patch by Ron