11import sys
2+ import time
3+ 4+ if hasattr (time , "strftime" ):
5+ from time import strftime
26
37CRITICAL = 50
48ERROR = 40
812NOTSET = 0
913
1014_level_dict = {
11- CRITICAL : "CRIT " ,
15+ CRITICAL : "CRITICAL " ,
1216 ERROR : "ERROR" ,
13- WARNING : "WARN " ,
17+ WARNING : "WARNING " ,
1418 INFO : "INFO" ,
1519 DEBUG : "DEBUG" ,
20+ NOTSET : "NOTSET" ,
1621}
1722
23+ _loggers = {}
1824_stream = sys .stderr
25+ _level = INFO
26+ _default_fmt = "%(levelname)s:%(name)s:%(message)s"
27+ _default_datefmt = "%Y-%m-%d %H:%M:%S"
1928
2029
2130class 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
2739
2840
2941class Handler :
30- def __init__ (self ):
31- pass
42+ def __init__ (self , level = NOTSET ):
43+ self .level = level
44+ self .formatter = None
3245
33- def setFormatter (self , fmtr ):
46+ def close (self ):
3447 pass
3548
49+ def setLevel (self , level ):
50+ self .level = level
3651
37- class Logger :
52+ def setFormatter (self , formatter ):
53+ self .formatter = formatter
3854
39- level = NOTSET
40- handlers = []
41- record = LogRecord ()
55+ def format (self , record ):
56+ return self .formatter .format (record )
4257
43- def __init__ (self , name ):
44- self .name = name
4558
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 = _stream ):
61+ self .stream = 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 = _default_fmt , datefmt = _default_datefmt ):
84+ self .fmt = fmt
85+ self .datefmt = 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 ()
51113
52114 def setLevel (self , level ):
53115 self .level = level
@@ -57,19 +119,16 @@ def isEnabledFor(self, level):
57119
58120 def log (self , level , msg , * args ):
59121 if self .isEnabledFor (level ):
60- levelname = self ._level_str (level )
61122 if args :
123+ if isinstance (args [0 ], dict ):
124+ args = args [0 ]
62125 msg = msg % args
63126 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
69127 for h in self .handlers :
128+ self .record .set (self .name , level , msg )
70129 h .emit (self .record )
71130 else :
72- print (levelname , ":" , self .name , ":" , msg , sep = "" , file = _stream )
131+ print (_level_dict [ level ] , ":" , self .name , ":" , msg , sep = "" , file = _stream )
73132
74133 def debug (self , msg , * args ):
75134 self .log (DEBUG , msg , * args )
@@ -86,43 +145,98 @@ def error(self, msg, *args):
86145 def critical (self , msg , * args ):
87146 self .log (CRITICAL , msg , * args )
88147
89- def exc (self , e , msg , * args ):
148+ def exception (self , msg , * args ):
90149 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 )
92152
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 )
95155
96- def addHandler (self , hndlr ):
97- self .handlers . append ( hndlr )
156+ def hasHandlers (self ):
157+ return len ( self .handlers ) > 0
98158
99159
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+ 102169
170+ def log (level , msg , * args ):
171+ getLogger ().log (level , msg , * args )
103172
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 )
110176
111177
112178def info (msg , * args ):
113179 getLogger ().info (msg , * args )
114180
115181
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 = _default_fmt ,
213+ datefmt = _default_datefmt ,
214+ level = WARNING ,
215+ stream = _stream ,
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 )
118239
119240
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