logging: Added getLogRecordFactory/setLogRecordFactory with docs and tests.

This commit is contained in:
Vinay Sajip 2010-12-03 11:50:38 +00:00
parent 97cbb76ee3
commit 615615291f
4 changed files with 88 additions and 19 deletions

View File

@ -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

View File

@ -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.
"""
global _logRecordClass
_logRecordClass = cls
def getLogRecordClass():
:param factory: A callable which will be called to instantiate
a log record.
"""
global _logRecordFactory
_logRecordFactory = factory
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:

View File

@ -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
)

View File

@ -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