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