Revision 80a8fa62 mininet/log.py

View differences:

mininet/log.py
1
'''Logging functions for Mininet.'''
1
"Logging functions for Mininet."
2 2

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

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

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

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

  
19 19

  
20 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
        '''
21
class StreamHandlerNoNewline( logging.StreamHandler ):
22
    """StreamHandler that doesn't print newlines by default.
23
       Since StreamHandler automatically adds newlines, define a mod to more
24
       easily support interactive mode when we want it, or errors-only logging
25
       for running unit tests."""
26

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

  
55 50

  
56
class Singleton(type):
57
    '''Singleton pattern from Wikipedia
51
class Singleton( type ):
52
    """Singleton pattern from Wikipedia
53
       See http://en.wikipedia.org/wiki/SingletonPattern#Python
58 54

  
59
    See http://en.wikipedia.org/wiki/Singleton_pattern#Python
55
       Intended to be used as a __metaclass_ param, as shown for the class
56
       below.
60 57

  
61
    Intended to be used as a __metaclass_ param, as shown for the class below.
58
       Changed cls first args to mcs to satisfy pylint."""
62 59

  
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_)
60
    def __init__( mcs, name, bases, dict_ ):
61
        super( Singleton, mcs ).__init__( name, bases, dict_ )
68 62
        mcs.instance = None
69 63

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

  
75 69

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

  
79
    Enable each mininet .py file to with one import:
70
class MininetLogger( Logger, object ):
71
    """Mininet-specific logger
72
       Enable each mininet .py file to with one import:
80 73

  
81 74
       from mininet.log import lg
82 75

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

  
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:
79
       Inherit from object to ensure that we have at least one new-style base
80
       class, and can then use the __metaclass__ directive, to prevent this
81
       error:
87 82

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

  
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.
86
       If Python2.5/logging/__init__.py defined Filterer as a new-style class,
87
       via Filterer( object ): rather than Filterer, we wouldn't need this.
88

  
89
       Use singleton pattern to ensure only one logger is ever created."""
93 90

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

  
98
    def __init__(self):
93
    def __init__( self ):
99 94

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

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

  
111
        self.set_loglevel()
104
        self.addHandler( ch )
112 105

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

  
116
        Convenience function to support lowercase names.
108
    def setLogLevel( self, levelname=None ):
109
        """Setup loglevel.
110
           Convenience function to support lowercase names.
117 111

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

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

  
130 123

  
131 124
lg = MininetLogger()

Also available in: Unified diff