1
1
import sys
2
+ import time
2
3
3
4
CRITICAL = 50
4
5
ERROR = 40
8
9
NOTSET = 0
9
10
10
11
_level_dict = {
11
- CRITICAL : "CRIT " ,
12
+ CRITICAL : "CRITICAL " ,
12
13
ERROR : "ERROR" ,
13
- WARNING : "WARN " ,
14
+ WARNING : "WARNING " ,
14
15
INFO : "INFO" ,
15
16
DEBUG : "DEBUG" ,
17
+ NOTSET : "NOTSET" ,
16
18
}
17
19
20
+ _loggers = {}
18
21
_stream = sys .stderr
22
+ _default_fmt = "%(levelname)s:%(name)s:%(message)s"
23
+ _default_datefmt = "%Y-%m-%d %H:%M:%S"
19
24
20
25
21
26
class LogRecord :
22
- def __init__ (self ):
23
- self .__dict__ = {}
24
-
25
- def __getattr__ (self , key ):
26
- return self .__dict__ [key ]
27
+ def set (self , name , level , message ):
28
+ self .name = name
29
+ self .levelno = level
30
+ self .levelname = _level_dict [level ]
31
+ self .message = message
32
+ self .ct = time .time ()
33
+ self .msecs = int ((self .ct - int (self .ct )) * 1000 )
34
+ self .asctime = None
27
35
28
36
29
37
class Handler :
30
- def __init__ (self ):
31
- pass
38
+ def __init__ (self , level = NOTSET ):
39
+ self .level = level
40
+ self .formatter = None
32
41
33
- def setFormatter (self , fmtr ):
42
+ def close (self ):
34
43
pass
35
44
45
+ def setLevel (self , level ):
46
+ self .level = level
47
+
48
+ def setFormatter (self , formatter ):
49
+ self .formatter = formatter
36
50
37
- class Logger :
51
+ def format (self , record ):
52
+ return self .formatter .format (record )
53
+
54
+
55
+ class StreamHandler (Handler ):
56
+ def __init__ (self , stream = _stream ):
57
+ self .stream = stream
58
+ self .terminator = "\n "
59
+
60
+ def close (self ):
61
+ if hasattr (self .stream , "flush" ):
62
+ self .stream .flush ()
38
63
39
- level = NOTSET
40
- handlers = []
41
- record = LogRecord ( )
64
+ def emit ( self , record ):
65
+ if record . levelno >= self . level :
66
+ self . stream . write ( self . format ( record ) + self . terminator )
42
67
68
+
69
+ class FileHandler (StreamHandler ):
70
+ def __init__ (self , filename , mode = "a" , encoding = "UTF-8" ):
71
+ super ().__init__ (stream = open (filename , mode = mode , encoding = encoding ))
72
+
73
+ def close (self ):
74
+ super ().close ()
75
+ self .stream .close ()
76
+
77
+
78
+ class Formatter :
79
+ def __init__ (self , fmt = _default_fmt , datefmt = _default_datefmt ):
80
+ self .fmt = fmt
81
+ self .datefmt = datefmt
82
+
83
+ def usesTime (self ):
84
+ return "asctime" in self .fmt
85
+
86
+ def formatTime (self , datefmt , record ):
87
+ if hasattr (time , "strftime" ):
88
+ return time .strftime (datefmt , time .localtime (record .ct ))
89
+ return ""
90
+
91
+ def format (self , record ):
92
+ if self .usesTime ():
93
+ record .asctime = self .formatTime (self .datefmt , record )
94
+ return self .fmt % {
95
+ "name" : record .name ,
96
+ "message" : record .message ,
97
+ "msecs" : record .msecs ,
98
+ "asctime" : record .asctime ,
99
+ "levelname" : record .levelname ,
100
+ }
101
+
102
+
103
+ class Logger :
43
104
def __init__ (self , name ):
44
105
self .name = name
45
-
46
- def _level_str (self , level ):
47
- l = _level_dict .get (level )
48
- if l is not None :
49
- return l
50
- return "LVL%s" % level
106
+ self .level = NOTSET
107
+ self .handlers = []
108
+ self .record = LogRecord ()
51
109
52
110
def setLevel (self , level ):
53
111
self .level = level
54
112
55
113
def isEnabledFor (self , level ):
56
- return level >= ( self .level or _level )
114
+ return level >= self .level
57
115
58
116
def log (self , level , msg , * args ):
59
- if self .isEnabledFor (level ):
60
- levelname = self ._level_str (level )
61
- if args :
62
- msg = msg % args
63
- if self .handlers :
64
- d = self .record .__dict__
65
- d ["levelname" ] = levelname
66
- d ["levelno" ] = level
67
- d ["message" ] = msg
68
- d ["name" ] = self .name
69
- for h in self .handlers :
70
- h .emit (self .record )
71
- else :
72
- print (levelname , ":" , self .name , ":" , msg , sep = "" , file = _stream )
117
+ if self .isEnabledFor (level ) and self .handlers :
118
+ if args and isinstance (args [0 ], dict ):
119
+ args = args [0 ]
120
+ for h in self .handlers :
121
+ self .record .set (self .name , level , msg % args )
122
+ h .emit (self .record )
123
+ elif not self .handlers :
124
+ print (msg , sep = "" , file = _stream )
73
125
74
126
def debug (self , msg , * args ):
75
127
self .log (DEBUG , msg , * args )
@@ -86,27 +138,17 @@ def error(self, msg, *args):
86
138
def critical (self , msg , * args ):
87
139
self .log (CRITICAL , msg , * args )
88
140
89
- def exc (self , e , msg , * args ):
90
- self .log (ERROR , msg , * args )
91
- sys .print_exception (e , _stream )
92
-
93
141
def exception (self , msg , * args ):
94
- self .exc (sys .exc_info ()[1 ], msg , * args )
95
-
96
- def addHandler (self , hndlr ):
97
- self .handlers .append (hndlr )
98
-
99
-
100
- _level = INFO
101
- _loggers = {}
142
+ self .log (ERROR , msg , * args )
143
+ if hasattr (sys , "exc_info" ):
144
+ for h in filter (lambda h : isinstance (h , StreamHandler ), self .handlers ):
145
+ sys .print_exception (sys .exc_info ()[1 ], h .stream )
102
146
147
+ def addHandler (self , handler ):
148
+ self .handlers .append (handler )
103
149
104
- def getLogger (name = "root" ):
105
- if name in _loggers :
106
- return _loggers [name ]
107
- l = Logger (name )
108
- _loggers [name ] = l
109
- return l
150
+ def hasHandlers (self ):
151
+ return len (self .handlers ) > 0
110
152
111
153
112
154
def info (msg , * args ):
@@ -117,12 +159,71 @@ def debug(msg, *args):
117
159
getLogger ().debug (msg , * args )
118
160
119
161
120
- def basicConfig (level = INFO , filename = None , stream = None , format = None ):
121
- global _level , _stream
122
- _level = level
123
- if stream :
124
- _stream = stream
125
- if filename is not None :
126
- print ("logging.basicConfig: filename arg is not supported" )
127
- if format is not None :
128
- print ("logging.basicConfig: format arg is not supported" )
162
+ def warning (msg , * args ):
163
+ getLogger ().warning (msg , * args )
164
+
165
+
166
+ def error (msg , * args ):
167
+ getLogger ().error (msg , * args )
168
+
169
+
170
+ def critical (msg , * args ):
171
+ getLogger ().critical (msg , * args )
172
+
173
+
174
+ def exception (msg , * args ):
175
+ getLogger ().exception (msg , * args )
176
+
177
+
178
+ def shutdown ():
179
+ for k , logger in _loggers .items ():
180
+ for h in logger .handlers :
181
+ h .close ()
182
+ _loggers .pop (logger , None )
183
+
184
+
185
+ if hasattr (sys , "atexit" ):
186
+ sys .atexit (shutdown )
187
+
188
+
189
+ def addLevelName (level , name ):
190
+ _level_dict [level ] = name
191
+
192
+
193
+ def log (level , msg , * args ):
194
+ getLogger ().log (level , msg , * args )
195
+
196
+
197
+ def getLogger (name = "root" ):
198
+ if name not in _loggers :
199
+ _loggers [name ] = Logger (name )
200
+ if name == "root" :
201
+ basicConfig ()
202
+ return _loggers [name ]
203
+
204
+
205
+ def basicConfig (
206
+ filename = None ,
207
+ filemode = "a" ,
208
+ format = _default_fmt ,
209
+ datefmt = _default_datefmt ,
210
+ level = WARNING ,
211
+ stream = _stream ,
212
+ encoding = "UTF-8" ,
213
+ force = False ,
214
+ ):
215
+ logger = getLogger ()
216
+ if force or not logger .handlers :
217
+ for h in logger .handlers :
218
+ h .close ()
219
+
220
+ if filename is None :
221
+ handler = StreamHandler (stream )
222
+ else :
223
+ handler = FileHandler (filename , filemode , encoding )
224
+
225
+ handler .setLevel (level )
226
+ handler .setFormatter (Formatter (format , datefmt ))
227
+
228
+ logger .setLevel (level )
229
+ logger .addHandler (handler )
0 commit comments