Commit 61561529 authored by Vinay Sajip's avatar Vinay Sajip

logging: Added getLogRecordFactory/setLogRecordFactory with docs and tests.

parent 97cbb76e
......@@ -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
......
......@@ -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:
......
......@@ -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
)
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment