Welcome, guest | Sign In | My Account | Store | Cart

The logging package offers the "extra" keyword argument in Logger.log to add user-defined attributes to the log record. LoggerAdaptors make it easy to use extras that are constant for a given logger; then simply use logger.debug, logger.info, ecc. But this won't support variable extra arguments.

The present recipe makes it easy to use "extra" attributes that are not constant but variables passed to the (modified) logging methods ('debug', 'info', ...)

Python, 77 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python

import logging

def processArgs(self, *args):
    msg = args[-1]
    args = args[:-1]
    # the following allows logging even in case of problems!
    if not (len(args) == len(self.extras)):
        noArgs = len(self.extras)
        l = list(' ' * noArgs)
        l[:len(args)] = args[:len(l)]
        print "WARNING: wrong number of logging arguments"
        args = l
    extras = dict(zip(self.extras, args))
    return (msg, extras)

def myLog(self, level, *args):
    if self.isEnabledFor(level):
        msg, extras = self.processArgs(*args)
        self._log(level, msg, [], extra=extras)

def myDebug(self, *args):
    self.log(logging.DEBUG, *args)

def myInfo(self, *args):
    self.log(logging.INFO, *args)

def myWarning(self, *args):
    self.log(logging.WARNING, *args)

def myError(self, *args):
    self.log(logging.ERROR, *args)

def myCritical(self, *args):
    self.log(logging.CRITICAL, *args)

def setLoggerExtras(logger, extras):
    logger.extras = extras
    logger.__class__.processArgs = processArgs
    logger.__class__.log = myLog
    logger.__class__.debug = myDebug
    logger.__class__.info = myInfo
    logger.__class__.warning = myWarning
    logger.__class__.error = myError
    logger.__class__.critical = myCritical

#-------------------------------------------------
if __name__ == '__main__':

    import logging.handlers

    def getRotFileLogger(name, filePath, maxBytes, maxCount, 
        logLevel=logging.DEBUG, format=None):
        format = format or '%(asctime)s - %(levelname)s - %(message)s'
        my_logger = logging.getLogger(name)
        my_logger.setLevel(logLevel)
        # Add the log message handler to the logger
        handler = logging.handlers.RotatingFileHandler(
                      filePath, maxBytes=maxBytes, backupCount=maxCount)
        formatter = logging.Formatter(format)
        handler.setFormatter(formatter)
        my_logger.addHandler(handler)
        return my_logger

    format = '%(asctime)s - %(levelname)s - %(extra1)s - %(extra2)s - %(message)s'
    logger = getRotFileLogger('test', 'test.log', 1000, 10, format=format)
    
    # simply set the extras
    setLoggerExtras(logger, ['extra1', 'extra2'])

    # and then log without explicit "extra" dict
    logger.debug('xx1', 'xx2', 'debug')
    logger.info('xx1', 'info')  #missing arg
    logger.warning('xx1', 'xx2', 'xx3', 'hello, a warning') #too many args
    logger.error('some error')
    logger.critical('some critical')
    
Created by Bud P. Bruegger on Tue, 2 Nov 2010 (BSD)
Python recipes (4591)
Bud P. Bruegger's recipes (2)

Required Modules

  • (none specified)

Other Information and Tasks