Statistics
| Branch: | Tag: | Revision:

mininet / mininet / logging_mod.py @ 723d068c

History | View | Annotate | Download (3.92 KB)

1
'''Logging functions for Mininet.'''
2

    
3
import logging
4
from logging import Logger
5
import types
6

    
7
LEVELS = {'debug': logging.DEBUG,
8
          'info': logging.INFO,
9
          'warning': logging.WARNING,
10
          'error': logging.ERROR,
11
          'critical': logging.CRITICAL}
12

    
13
# change this to logging.INFO to get printouts when running unit tests
14
LOG_LEVEL_DEFAULT = logging.WARNING
15

    
16
#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
17
LOG_MSG_FORMAT = '%(message)s'
18

    
19

    
20
# Modified from python2.5/__init__.py
21
class StreamHandlerNoNewline(logging.StreamHandler):
22
    '''StreamHandler that doesn't print newlines by default.
23

24
    Since StreamHandler automatically adds newlines, define a mod to more
25
    easily support interactive mode when we want it, or errors-only logging for
26
    running unit tests.
27
    '''
28

    
29
    def emit(self, record):
30
        '''
31
        Emit a record.
32

33
        If a formatter is specified, it is used to format the record.
34
        The record is then written to the stream with a trailing newline
35
        [N.B. this may be removed depending on feedback]. If exception
36
        information is present, it is formatted using
37
        traceback.print_exception and appended to the stream.
38
        '''
39
        try:
40
            msg = self.format(record)
41
            fs = '%s' # was '%s\n'
42
            if not hasattr(types, 'UnicodeType'): #if no unicode support...
43
                self.stream.write(fs % msg)
44
            else:
45
                try:
46
                    self.stream.write(fs % msg)
47
                except UnicodeError:
48
                    self.stream.write(fs % msg.encode('UTF-8'))
49
            self.flush()
50
        except (KeyboardInterrupt, SystemExit):
51
            raise
52
        except:
53
            self.handleError(record)
54

    
55

    
56
class Singleton(type):
57
    '''Singleton pattern from Wikipedia
58

59
    See http://en.wikipedia.org/wiki/Singleton_pattern#Python
60

61
    Intended to be used as a __metaclass_ param, as shown for the class below.
62

63
    Changed cls first args to mcs to satsify pylint.
64
    '''
65

    
66
    def __init__(mcs, name, bases, dict_):
67
        super(Singleton, mcs).__init__(name, bases, dict_)
68
        mcs.instance = None
69

    
70
    def __call__(mcs, *args, **kw):
71
        if mcs.instance is None:
72
            mcs.instance = super(Singleton, mcs).__call__(*args, **kw)
73
            return mcs.instance
74

    
75

    
76
class MininetLogger(Logger, object):
77
    '''Mininet-specific logger
78

79
    Enable each mininet .py file to with one import:
80

81
       from mininet.logging_mod import lg
82

83
    ...get a default logger that doesn't require one newline per logging call.
84

85
    Inherit from object to ensure that we have at least one new-style base
86
    class, and can then use the __metaclass__ directive, to prevent this error:
87

88
      TypeError: Error when calling the metaclass bases
89
       a new-style class can't have only classic bases
90

91
    If Python2.5/logging/__init__.py defined Filterer as a new-style class,
92
    via Filterer(object): rather than Filterer, we wouldn't need this.
93

94
    Use singleton pattern to ensure only one logger is ever created.
95
    '''
96
    __metaclass__ = Singleton
97

    
98
    def __init__(self):
99

    
100
        Logger.__init__(self, "mininet")
101

    
102
        # create console handler
103
        ch = StreamHandlerNoNewline()
104
        # create formatter
105
        formatter = logging.Formatter(LOG_MSG_FORMAT)
106
        # add formatter to ch
107
        ch.setFormatter(formatter)
108
        # add ch to lg
109
        self.addHandler(ch)
110

    
111
        self.set_loglevel()
112

    
113
    def set_loglevel(self, levelname = None):
114
        '''Setup loglevel.
115

116
        Convenience function to support lowercase names.
117

118
        @param level_name level name from LEVELS
119
        '''
120
        level = LOG_LEVEL_DEFAULT
121
        if levelname != None:
122
            if levelname not in LEVELS:
123
                raise Exception('unknown loglevel seen in set_loglevel')
124
            else:
125
                level = LEVELS.get(levelname, level)
126

    
127
        self.setLevel(level)
128
        self.handlers[0].setLevel(level)
129

    
130

    
131
lg = MininetLogger()