Skip to content

python-stdlib/logging: Add Record to log file #441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 27 additions & 17 deletions python-stdlib/logging/example_logging.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -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()
133 changes: 120 additions & 13 deletions python-stdlib/logging/logging.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import sys
import utime

CRITICAL = 50
ERROR = 40
Expand All @@ -15,24 +16,62 @@
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]


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:

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 = {}
Expand All @@ -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)
2 changes: 1 addition & 1 deletion python-stdlib/logging/metadata.txt
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
srctype = micropython-lib
type = module
version = 0.3
version = 0.4