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

This helper function simplifies the difficult task of setting up and maintaining a logging system. Changes to a logging system can cause unanticipated consequences such as lost messages or duplicates. Debugging a logging hierarchy can be a tedious task. This function overrides the internal __repr__ functions of the internal classes and allows a print statement to generate the complete logger hierarchy with its associated internals. It allows easy debugging a logger and allows changes to be easily detected.

Python, 96 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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import logging
import logging.handlers

    
def enable_logger_print():
    def _logger_str(self):
        s = ''
        if self.parent != None:
            s =  _logger_str(self.parent)
        s += """\n%s\n""" % (self.name)
        for name,value in self.__dict__.items():
            if name == 'parent': value = value and value.name or 'None'
            if name == 'level': value = '%s (%s)' %(value,logging.getLevelName(value))
            s += '    %s = %s\n' % (name,value)
        return s

    def _handler_repr(handlername):
        def __repr__(self):
            s = '\n\t%s\n' % (handlername)
            for name,value in self.__dict__.items():
                if name == 'level': value = '%s (%s)' %(value,logging.getLevelName(value))
                s += '\t    %s = %s\n' % (name,value)
            s += '\t'
            return s
        return __repr__

    def _formatter_repr(self):
        s = ""
        for name,value in self.__dict__.items():
            s += '\n\t\t%s = %s' % (name,value)
        return s

    def _manager_repr(self):
        s = ""
        for name,value in self.__dict__.items():
            if name == 'root': value = value.name
            if name == 'loggerDict': value = _logger_list(); name='loggerDict keys'
            s += '\n        %s = %s' % (name,value)
        return s

    def _filter_repr(self):
        return self.name

    def _logger_list():
        return sorted([name for name in logging.Logger.manager.loggerDict])

    for name in dir():
        if name.endswith('Handler'):
            logging.__dict__[name].__repr__ = _handler_repr(name)

    for name in dir(logging):
        if name.endswith('Handler'):
            logging.__dict__[name].__repr__ = _handler_repr(name)

    for name in dir(logging.handlers):
        if name.endswith('Handler'):
            logging.handlers.__dict__[name].__repr__ = _handler_repr(name)

    logging.Logger.__str__ = _logger_str
    logging.Formatter.__repr__ = _formatter_repr
    logging.Filter.__repr__ = _filter_repr
    logging.Manager.__repr__ = _manager_repr
        

if __name__ == '__main__':
    logging.basicConfig( level=logging.INFO)

    logger = logging.getLogger('')
    logger1 = logging.getLogger('a.b.c')
    logger2 = logging.getLogger('x.a')

    rootLogger = logging.getLogger()
    rootLogger.setLevel(logging.DEBUG)

    streamHandler = logging.StreamHandler()
    streamHandler.name = 'Stream Server'
    frmt = logging.Formatter("%(filename)s - %(name)s - %(levelname)s - %(message)s")
    streamHandler.setFormatter(frmt)
    fltr = logging.Filter('x')
    streamHandler.addFilter(fltr)
    logger.addHandler(streamHandler)

    print '='*80
    print '\n*** print logger2 BEFORE enable_logger_print() ***\n'
    print logger2
    print '='*80

    enable_logger_print() # allows printing logger internals

    print '\n*** print logger2 AFTER enable_logger_print() ***\n'
    print logger2
    print '='*80

    logger.info('Help Me (root)')
    logger1.info('Help Me (a.b.c)')
    logger2.info('Help Me (x)')

Executing the program generates the following output:

================================================================================

*** print logger2 BEFORE enable_logger_print() ***

<logging.Logger object at 0x027983F0>
================================================================================

*** print logger2 AFTER enable_logger_print() ***


root
    name = root
    parent = None
    handlers = [
        StreamHandler
            stream = <idlelib.rpc.RPCProxy object at 0x02754790>
            level = 0 (NOTSET)
            lock = <_RLock owner=None count=0>
            _name = None
            filters = []
            formatter = 
                datefmt = None
                _fmt = %(levelname)s:%(name)s:%(message)s
        , 
        StreamHandler
            stream = <idlelib.rpc.RPCProxy object at 0x02754790>
            level = 0 (NOTSET)
            lock = <_RLock owner=None count=0>
            _name = Stream Server
            filters = [x]
            formatter = 
                datefmt = None
                _fmt = %(filename)s - %(name)s - %(levelname)s - %(message)s
        ]
    level = 10 (DEBUG)
    disabled = 0
    propagate = 1
    filters = []

x.a
    name = x.a
    parent = root
    handlers = []
    level = 0 (NOTSET)
    disabled = 0
    manager = 
        emittedNoHandlerWarning = 0
        disable = 0
        root = root
        loggerDict keys = ['a', 'a.b', 'a.b.c', 'x', 'x.a']
        loggerClass = None
    propagate = 1
    filters = []

================================================================================
INFO:root:Help Me (root)
INFO:a.b.c:Help Me (a.b.c)
INFO:x.a:Help Me (x)
log_test.py - x.a - INFO - Help Me (x)

Both StreamHandlers generated Help Me (x) which, for this example, is a mistake. The call to basicConfig created a default StreamHandler and a default formatter. The second StreamHandler was added to the root logger with the defined formatter and a filter for x messages. All x messages are sent to both stream handlers which duplicates the message. The StreamHandler should have been added to logger2 and not the root logger. The logger2 propagate should also have been set false to keep x messages from propogating to the root logger. This would display only one x message per record, as expected.

replace:

logger.addHandler(streamHandler)

with:

logger2.addHandler(streamHandler)
logger2.propagate = 0

to fix the problem