Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b414392

Browse files
logging: Improve the logging module.
* Add support for all format specifiers, support for `datefmt` using strftime, and support for Stream and File handlers. * Ports/boards that need to use `FileHandlers` should enable `MICROPY_PY_SYS_ATEXIT`, and enabled `MICROPY_PY_SYS_EXC_INFO` if using `logging.exception()`.
1 parent 038b4ac commit b414392

File tree

4 files changed

+214
-104
lines changed

4 files changed

+214
-104
lines changed

‎python-stdlib/logging/__init__.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from .logging import Logger
2+
from .logging import Handler
3+
from .logging import Formatter
4+
from .logging import FileHandler
5+
from .logging import StreamHandler
6+
from .logging import DEBUG, INFO, WARNING, ERROR, CRITICAL
7+
from .logging import debug, info, warning, error, critical
8+
from .logging import exception
9+
from .logging import shutdown
10+
from .logging import getLogger
11+
from .logging import basicConfig
12+
13+
try
14+
# Import extra handlers if any.
15+
from logging_handlers import *
16+
except ImportError:
17+
pass
18+
19+
import sys
20+
21+
if hasattr(sys, "atexit"):
22+
sys.atexit(shutdown)
Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
11
import logging
22

3-
logging.basicConfig(level=logging.INFO)
4-
log = logging.getLogger("test")
5-
log.debug("Test message: %d(%s)", 100, "foobar")
6-
log.info("Test message2: %d(%s)", 100, "foobar")
7-
log.warning("Test message3: %d(%s)")
8-
log.error("Test message4")
9-
log.critical("Test message5")
10-
logging.info("Test message6")
3+
# Create logger
4+
logger = logging.getLogger(__name__)
5+
logger.setLevel(logging.DEBUG)
116

12-
try:
13-
1 / 0
14-
except:
15-
log.exception("Some trouble (%s)", "expected")
7+
# Create console handler and set level to debug
8+
stream_handler = logging.StreamHandler()
9+
stream_handler.setLevel(logging.DEBUG)
10+
11+
# Create file handler and set level to error
12+
file_handler = logging.FileHandler("error.log", mode="w")
13+
file_handler.setLevel(logging.ERROR)
1614

15+
# Create a formatter
16+
formatter = logging.Formatter("%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - %(message)s")
1717

18-
classMyHandler(logging.Handler):
19-
defemit(self, record):
20-
print("levelname=%(levelname)s name=%(name)s message=%(message)s"%record.__dict__)
18+
# Add formatter to the handlers
19+
stream_handler.setFormatter(formatter)
20+
file_handler.setFormatter(formatter)
2121

22+
# Add hadlers to logger
23+
logger.addHandler(stream_handler)
24+
logger.addHandler(file_handler)
2225

23-
logging.getLogger().addHandler(MyHandler())
24-
logging.info("Test message7")
26+
# Lapplication' code
27+
logger.debug("debug message")
28+
logger.info("info message")
29+
logger.warning("warn message")
30+
logger.error("error message")
31+
logger.critical("critical message")
32+
logger.info("message %s %d", "arg", 5)
33+
logger.info("message %(foo)s %(bar)s", {"foo": 1, "bar": 20})
34+
35+
try:
36+
1 / 0
37+
except:
38+
logger.exception("Some trouble (%s)", "expected")

‎python-stdlib/logging/logging.py‎

Lines changed: 160 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,202 @@
11
import sys
2+
import time
23

3-
CRITICAL = 50
4-
ERROR = 40
5-
WARNING = 30
6-
INFO = 20
7-
DEBUG = 10
84
NOTSET = 0
5+
DEBUG = 10
6+
INFO = 20
7+
WARNING = 30
8+
ERROR = 40
9+
CRITICAL = 50
910

10-
_level_dict = {
11-
CRITICAL: "CRIT",
12-
ERROR: "ERROR",
13-
WARNING: "WARN",
14-
INFO: "INFO",
11+
levelname = {
12+
NOTSET: "NOTSET",
1513
DEBUG: "DEBUG",
14+
INFO: "INFO",
15+
WARNING: "WARNING",
16+
ERROR: "ERROR",
17+
CRITICAL: "CRITICAL",
1618
}
1719

18-
_stream = sys.stderr
20+
loggers = {}
21+
default_fmt = "%(levelname)s:%(name)s:%(message)s"
22+
default_datefmt = "%Y-%m-%d %H:%M:%S"
1923

2024

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
2429

25-
def __getattr__(self, key):
26-
returnself.__dict__[key]
30+
def close(self):
31+
pass
2732

33+
def setLevel(self, level):
34+
self.level = level
2835

29-
class Handler:
30-
def __init__(self):
31-
pass
36+
def setFormatter(self, formatter):
37+
self.formatter = formatter
3238

33-
def setFormatter(self, fmtr):
34-
pass
39+
def format(self, record):
40+
returnself.formatter.format(record)
3541

3642

37-
class Logger:
43+
class StreamHandler(Handler):
44+
def __init__(self, stream=sys.stderr):
45+
self.stream = stream
46+
self.terminator = "\n"
3847

39-
level=NOTSET
40-
handlers= []
41-
record=LogRecord()
48+
defclose(self):
49+
ifhasattr(self.stream, "flush"):
50+
self.stream.flush()
4251

43-
def __init__(self, name):
52+
def emit(self, record):
53+
if record.level >= 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 Record:
67+
def set(self, name, level, message):
4468
self.name = name
69+
self.level = level
70+
self.message = message
71+
self.ts = time.time()
72+
self.msecs = int((self.ts - int(self.ts)) * 1000)
73+
74+
75+
class Formatter:
76+
def __init__(self, fmt=default_fmt, datefmt=default_datefmt):
77+
self.fmt = fmt
78+
self.datefmt = datefmt
79+
80+
def formatTime(self, datefmt):
81+
if hasattr(time, "strftime"):
82+
return time.strftime(datefmt, time.localtime())
83+
return ""
84+
85+
def format(self, record):
86+
return self.fmt % {
87+
"name": record.name,
88+
"message": record.message,
89+
"msecs": record.msecs,
90+
"asctime": self.formatTime(self.datefmt),
91+
"levelname": levelname[record.level],
92+
}
4593

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
94+
95+
class Logger:
96+
def __init__(self, name):
97+
self.name = name
98+
self.level = NOTSET
99+
self.handlers = []
100+
self.record = Record()
51101

52102
def setLevel(self, level):
53103
self.level = level
54104

55-
def isEnabledFor(self, level):
56-
returnlevel>= (self.levelor_level)
105+
def addHandler(self, handler):
106+
self.handlers.append(handler)
57107

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)
108+
def hasHandlers(self):
109+
return len(self.handlers) > 0
73110

74-
def debug(self, msg, *args):
75-
self.log(DEBUG, msg, *args)
111+
def debug(self, message, *args, **kwargs):
112+
self.log(DEBUG, message, *args, **kwargs)
76113

77-
def info(self, msg, *args):
78-
self.log(INFO, msg, *args)
114+
def info(self, message, *args, **kwargs):
115+
self.log(INFO, message, *args, **kwargs)
79116

80-
def warning(self, msg, *args):
81-
self.log(WARNING, msg, *args)
117+
def warning(self, message, *args, **kwargs):
118+
self.log(WARNING, message, *args, **kwargs)
82119

83-
def error(self, msg, *args):
84-
self.log(ERROR, msg, *args)
120+
def error(self, message, *args, **kwargs):
121+
self.log(ERROR, message, *args, **kwargs)
85122

86-
def critical(self, msg, *args):
87-
self.log(CRITICAL, msg, *args)
123+
def critical(self, message, *args, **kwargs):
124+
self.log(CRITICAL, message, *args, **kwargs)
88125

89-
def exc(self, e, msg, *args):
90-
self.log(ERROR, msg, *args)
91-
sys.print_exception(e, _stream)
126+
def exception(self, message, *args, **kwargs):
127+
self.log(ERROR, message, *args, **kwargs)
128+
if hasattr(sys, "exc_info"):
129+
for h in filter(lambda h: isinstance(h, StreamHandler), self.handlers):
130+
sys.print_exception(sys.exc_info()[1], h.stream)
92131

93-
def exception(self, msg, *args):
94-
self.exc(sys.exc_info()[1], msg, *args)
132+
def log(self, level, message, *args, **kwargs):
133+
if level >= self.level:
134+
if args and isinstance(args[0], dict):
135+
args = args[0]
136+
for h in self.handlers:
137+
self.record.set(self.name, level, message % args)
138+
h.emit(self.record)
95139

96-
def addHandler(self, hndlr):
97-
self.handlers.append(hndlr)
98140

141+
def debug(message, *args, **kwargs):
142+
getLogger().log(DEBUG, message, *args, **kwargs)
99143

100-
_level = INFO
101-
_loggers = {}
102144

145+
def info(message, *args, **kwargs):
146+
getLogger().log(INFO, message, *args, **kwargs)
103147

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
148+
149+
def warning(message, *args, **kwargs):
150+
getLogger().log(WARNING, message, *args, **kwargs)
110151

111152

112-
def info(msg, *args):
113-
getLogger().info(msg, *args)
153+
def error(message, *args, **kwargs):
154+
getLogger().log(ERROR, message, *args, **kwargs)
114155

115156

116-
def debug(msg, *args):
117-
getLogger().debug(msg, *args)
157+
def critical(message, *args, **kwargs):
158+
getLogger().log(CRITICAL, message, *args, **kwargs)
118159

119160

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")
161+
def exception(message, *args, **kwargs):
162+
getLogger().exception(message, *args, **kwargs)
163+
164+
165+
def shutdown():
166+
for k, logger in loggers.items():
167+
for h in logger.handlers:
168+
h.close()
169+
loggers.pop(logger, None)
170+
171+
172+
def getLogger(name="root"):
173+
if name not in loggers:
174+
loggers[name] = Logger(name)
175+
return loggers[name]
176+
177+
178+
def basicConfig(
179+
filename=None,
180+
filemode="a",
181+
format=default_fmt,
182+
datefmt=default_datefmt,
183+
level=WARNING,
184+
stream=sys.stderr,
185+
encoding="UTF-8",
186+
force=False,
187+
):
188+
logger = getLogger()
189+
if force or not logger.handlers:
190+
for h in logger.handlers:
191+
h.close()
192+
193+
if filename is None:
194+
handler = StreamHandler(stream)
195+
else:
196+
handler = FileHandler(filename, filemode, encoding)
197+
198+
handler.setLevel(level)
199+
handler.setFormatter(Formatter(format, datefmt))
200+
201+
logger.setLevel(level)
202+
logger.addHandler(handler)

‎python-stdlib/logging/manifest.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
metadata(version="0.3")
1+
metadata(version="0.4")
22

33
module("logging.py")

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /