From d3fa93a711387d09e2604844c890ed52bfa34c6d Mon Sep 17 00:00:00 2001 From: liuyunrui123 <1753668086@qq.com> Date: Fri, 20 Aug 2021 18:41:22 +0800 Subject: [PATCH] python-stdlib/logging: Add Record to log file Signed-off-by: liuyunrui123 <1753668086@qq.com> --- python-stdlib/logging/example_logging.py | 44 +++++--- python-stdlib/logging/logging.py | 133 ++++++++++++++++++++--- python-stdlib/logging/metadata.txt | 2 +- 3 files changed, 148 insertions(+), 31 deletions(-) mode change 100644 => 100755 python-stdlib/logging/example_logging.py mode change 100644 => 100755 python-stdlib/logging/logging.py mode change 100644 => 100755 python-stdlib/logging/metadata.txt diff --git a/python-stdlib/logging/example_logging.py b/python-stdlib/logging/example_logging.py old mode 100644 new mode 100755 index e81308859..61f17f996 --- a/python-stdlib/logging/example_logging.py +++ b/python-stdlib/logging/example_logging.py @@ -1,24 +1,34 @@ import logging -logging.basicConfig(level=logging.INFO) -log = logging.getLogger("test") -log.debug("Test message: %d(%s)", 100, "foobar") -log.info("Test message2: %d(%s)", 100, "foobar") -log.warning("Test message3: %d(%s)") -log.error("Test message4") -log.critical("Test message5") -logging.info("Test message6") +# Example 1: Simple use, print to standard output +def example1(): + logging.debug('debug message') + logging.info('info message') + logging.warning('warn message') + logging.error('error message') + logging.critical('critical message') -try: - 1 / 0 -except: - log.exception("Some trouble (%s)", "expected") +# Example 2: Log to a log file +def example2(): + logging.basicConfig(level=logging.DEBUG,filename='/logger.log',format='%(asctime)s : %(message)s') + logging.debug('debug message should go to the log file') + logging.info('info message should go to the log file') + logging.warning('warn message should go to the log file') + logging.error('error message should go to the log file') + logging.critical('critical message should go to the log file') +# Example 3: Record to a log file and print to standard output at the same time +def example3(): + logger=logging.getLogger() -class MyHandler(logging.Handler): - def emit(self, record): - print("levelname=%(levelname)s name=%(name)s message=%(message)s" % record.__dict__) + fh = logging.FileHandler('/logger.log') + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + fh.setFormatter(formatter) + logger.setLevel(level = logging.DEBUG) + logger.addHandler(fh) + logger.debug('debug message') + logger.info('info message') -logging.getLogger().addHandler(MyHandler()) -logging.info("Test message7") +if __name__ == "__main__": + example3() \ No newline at end of file diff --git a/python-stdlib/logging/logging.py b/python-stdlib/logging/logging.py old mode 100644 new mode 100755 index 79bd61c71..8eee554ef --- a/python-stdlib/logging/logging.py +++ b/python-stdlib/logging/logging.py @@ -1,4 +1,5 @@ import sys +import utime CRITICAL = 50 ERROR = 40 @@ -15,12 +16,17 @@ DEBUG: "DEBUG", } -_stream = sys.stderr class LogRecord: def __init__(self): self.__dict__ = {} + ct = utime.time() + self.message = "" + self.asctime = None + self.exc_info = None + self.exc_text = None + self.created = ct def __getattr__(self, key): return self.__dict__[key] @@ -28,11 +34,44 @@ def __getattr__(self, key): class Handler: def __init__(self): - pass + self.formatter = Formatter() + + def setFormatter(self, fmt): + self.formatter = fmt + +class StreamHandler(Handler): + def __init__(self, stream=None): + self._stream = stream or sys.stderr + self.terminator = "\n" + self.formatter = Formatter() + + def emit(self, record): + self._stream.write(self.formatter.format(record) + self.terminator) - def setFormatter(self, fmtr): + def flush(self): pass +class FileHandler(Handler): + def __init__(self, filename, mode="a", encoding=None, delay=False): + super().__init__() + + self.encoding = encoding + self.mode = mode + self.delay = delay + self.terminator = "\n" + self.filename = filename + self._f = None + + + def emit(self, record): + + self._f = open(self.filename, self.mode) + self._f.write(self.formatter.format(record) + self.terminator) + + def close(self): + if self._f is not None: + self._f.close() + class Logger: @@ -67,6 +106,7 @@ def log(self, level, msg, *args): d["message"] = msg d["name"] = self.name for h in self.handlers: + self.record.message = msg h.emit(self.record) else: print(levelname, ":", self.name, ":", msg, sep="", file=_stream) @@ -96,6 +136,57 @@ def exception(self, msg, *args): def addHandler(self, hndlr): self.handlers.append(hndlr) +class Formatter: + def __init__(self, fmt=None, datefmt=None, style="%"): + self.fmt = fmt or "%(message)s" + self.datefmt = datefmt + + if style not in ("%", "{"): + raise ValueError("Style must be one of: %, {") + + self.style = style + + def usesTime(self): + if self.style == "%": + return "%(asctime)" in self.fmt + elif self.style == "{": + return "{asctime" in self.fmt + + def format(self, record): + # If the formatting string contains '(asctime)', formatTime() is called to + # format the event time. + if self.usesTime(): + record.asctime = self.formatTime(record, self.datefmt) + record.__dict__["asctime"] = record.asctime + + # If there is exception information, it is formatted using formatException() + # and appended to the message. The formatted exception information is cached + # in attribute exc_text. + if record.exc_info is not None: + record.exc_text += self.formatException(record.exc_info) + record.message += "\n" + record.exc_text + + # The record’s attribute dictionary is used as the operand to a string + # formatting operation. + if self.style == "%": + return self.fmt % record.__dict__ + elif self.style == "{": + return self.fmt.format(**record.__dict__) + else: + raise ValueError( + "Style {0} is not supported by logging.".format(self.style) + ) + + def formatTime(self, record, datefmt=None): + assert datefmt is None # datefmt is not supported + ct = utime.localtime(record.created) + return "{0}-{1}-{2} {3}:{4}:{5}".format(*ct) + + def formatException(self, exc_info): + raise NotImplementedError() + + def formatStack(self, stack_info): + raise NotImplementedError() _level = INFO _loggers = {} @@ -104,25 +195,41 @@ def addHandler(self, hndlr): def getLogger(name="root"): if name in _loggers: return _loggers[name] - l = Logger(name) + if name == "root": + l = Logger(name) + sh = StreamHandler() + sh.formatter = Formatter() + l.addHandler(sh) + else: + l = Logger(name) _loggers[name] = l return l +def critical(msg, *args): + getLogger().critical(msg, *args) + +def error(msg, *args): + getLogger().error(msg, *args) + +def warning(msg, *args): + getLogger().warning(msg, *args) + def info(msg, *args): getLogger().info(msg, *args) - def debug(msg, *args): getLogger().debug(msg, *args) -def basicConfig(level=INFO, filename=None, stream=None, format=None): - global _level, _stream +def basicConfig(level=INFO, filename=None, stream=None, format=None, style="%"): + global _level _level = level - if stream: - _stream = stream - if filename is not None: - print("logging.basicConfig: filename arg is not supported") - if format is not None: - print("logging.basicConfig: format arg is not supported") + if filename: + h = FileHandler(filename) + else: + h = StreamHandler(stream) + h.setFormatter(Formatter(format, style=style)) + root = getLogger() + root.handlers.clear() + root.addHandler(h) diff --git a/python-stdlib/logging/metadata.txt b/python-stdlib/logging/metadata.txt old mode 100644 new mode 100755 index a1ff78f65..980e21f52 --- a/python-stdlib/logging/metadata.txt +++ b/python-stdlib/logging/metadata.txt @@ -1,3 +1,3 @@ srctype = micropython-lib type = module -version = 0.3 +version = 0.4