Statistics
| Branch: | Tag: | Revision:

mininet / mininet / log.py @ 80a8fa62

History | View | Annotate | Download (3.98 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
LOGLEVELDEFAULT = logging.WARNING
15

    
16
#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
17
LOGMSGFORMAT = '%(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
       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."""
34
        try:
35
            msg = self.format( record )
36
            fs = '%s' # was '%s\n'
37
            if not hasattr( types, 'UnicodeType' ): #if no unicode support...
38
                self.stream.write( fs % msg )
39
            else:
40
                try:
41
                    self.stream.write( fs % msg )
42
                except UnicodeError:
43
                    self.stream.write( fs % msg.encode( 'UTF-8' ) )
44
            self.flush()
45
        except ( KeyboardInterrupt, SystemExit ):
46
            raise
47
        except:
48
            self.handleError( record )
49

    
50

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

55
       Intended to be used as a __metaclass_ param, as shown for the class
56
       below.
57

58
       Changed cls first args to mcs to satisfy pylint."""
59

    
60
    def __init__( mcs, name, bases, dict_ ):
61
        super( Singleton, mcs ).__init__( name, bases, dict_ )
62
        mcs.instance = None
63

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

    
69

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

74
       from mininet.log import lg
75

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

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:
82

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

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."""
90

    
91
    __metaclass__ = Singleton
92

    
93
    def __init__( self ):
94

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

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

    
106
        self.setLogLevel()
107

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

112
           levelName: level name from LEVELS"""
113
        level = LOGLEVELDEFAULT
114
        if levelname != None:
115
            if levelname not in LEVELS:
116
                raise Exception( 'unknown loglevel seen in set_loglevel' )
117
            else:
118
                level = LEVELS.get( levelname, level )
119

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

    
123

    
124
lg = MininetLogger()