This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: More easily extensible logging module
Type: Stage:
Components: Library (Lib) Versions:
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: vinay.sajip Nosy List: dvarrazzo, vinay.sajip
Priority: normal Keywords: patch

Created on 2006-01-22 13:47 by dvarrazzo, last changed 2022-04-11 14:56 by admin. This issue is now closed.

File name Uploaded Description Edit
logging-r42136.patch dvarrazzo, 2006-01-22 13:47 Patch for for easier subclassing
Messages (2)
msg49379 - (view) Author: Daniele Varrazzo (dvarrazzo) * Date: 2006-01-22 13:47
The Python logging.Logger class is supposed being
extensible by overriding the makeRecord() method. 

This is not completely true because the public logging
method (log(), debug(), info()...) call the less public
_log(), which in turn call makeRecord(). While the
public methods have a signature such:

    def info(self, msg, *args, **kwargs):
        apply(self._log, (INFO, msg, args), kwargs)

thus leaving room for expansion, the _log() method is
not so much flexible:

    def _log(self, level, msg, args, exc_info=None):
        # ...interesting stuff here...
        record = self.makeRecord(, level, fn,
lno, msg, args, exc_info)

The makeRecord signature is:

    def makeRecord(self, name, level, fn, lno, msg,
args, exc_info):

So if anybody wants to add a keyword to makeRecord, he
also needs to re-implement the "interesting stuff" in
the supposed private _log (finding the source row,
reading the stack trace...).

The attached patch should leave the _log behavior
unchanged but all unknown keyword arguments are passed
to makeRecord.

If a wrong parameter is passed to any public method,
the logger as before raises an exception, which is
raised on the makeRecord() call instead of _log()'s.

With the patch on, use case for an user that want to
log extra keywords is:

    import logging
    # Logger customization

    class MyLogRecord(logging.LogRecord):
        """Add a foo to a log record."""
        def __init__(self, name, level, pathname, 
                     lineno, msg, args, exc_info, foo):
            logging.LogRecord.__init__(self, name,
level, pathname,
                                       lineno, msg,
args, exc_info)
   = foo
    class MyLogger(logging.Logger):
        """Can log foos too."""
        def makeRecord(self, name, level, fn, 
                       lno, msg, args, exc_info, foo):
            return MyLogRecord(name, level, fn, 
                               lno, msg, args,
exc_info, foo)
    class MyHandler(logging.Handler):
        """Can handle foo records."""
        def emit(self, record):
            if isinstance(record, MyLogRecord):
                print self.format(record),
    # Logger configuration

    logger = logging.getLogger('test')
    hndl = MyHandler(level=logging.INFO)
        logging.Formatter("%(message)s at line
    # Logger usage"Message", foo='pippo')
    # prints something like "Message at line #40 pippo"
msg49380 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2006-02-28 00:27
Logged In: YES 

The requirement has been covered in the latest checkin to
Subversion: all logging calls take an extra optional keyword
parameter called "extra" which is meant to be a dictionary
containing additional attributes to add to the LogRecord. See

The dictionary should not contain keys which class with
"built-in" attributes of the LogRecord.

N.B. Off-topic: The LogRecord also now contains the name of
the function from which the logging call was made - in the
funcName attribute.

Date User Action Args
2022-04-11 14:56:15adminsetgithub: 42819
2006-01-22 13:47:54dvarrazzocreate