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