In this post, we discuss how to use the Python logging facilities in your code.
TL;DR¶
h.stream.fileno()
import logging
logger = logging.getLogger()
h = logging.StreamHandler(os.fdopen(1, "w"))
logger.log?
import logging
import time
from contextlib import contextmanager
# Not exactly sure why this works, but here we add a handler
# to send output to the main console.
# https://stackoverflow.com/a/39331977/1088938
logger = logging.getLogger()
handler = None
for h in logger.handlers:
if hasattr(h, 'stream') and h.stream.fileno() == 1:
handler = h
break
if not handler:
handler = logging.StreamHandler(os.fdopen(1, "w"))
logger.addHandler(handler)
formatter = logging.Formatter(
fmt="[{levelname[0]} {asctime} {name}] {message}\n {filename}:{lineno}",
datefmt="%H:%M:%S",
style="{")
class MyFormatter(logging.Formatter):
def __init__(self):
logging.Formatter.__init__(
self,
fmt="[{levelname[0]} {asctime} {name}] {message}",
datefmt="%H:%M:%S",
style="{")
def format(self, record):
if record.levelno >= logging.WARNING:
_fmt = ("\n" + " "*14).join([self._fmt, "{filename}:{lineno}"])
else:
_fmt = self._fmt
self._fmt = self._style._fmt = _fmt
return logging.Formatter.format(self, record)
handler.setFormatter(MyFormatter())
handler.setLevel('DEBUG')
logger.setLevel('DEBUG')
class A(object):
def __init__(self):
self._level = 0
self.logger.info("Initialized")
@property
def logger(self):
"""Return the logger."""
# Get the logger each time so that it will have all
# properties set by the user.
return logging.getLogger(self.__class__.__name__)
@contextmanager
def task(self, msg):
indent = " "*self._level
msg = indent + msg
self.logger.info(msg + "...")
try:
self._level += 2
yield
self.logger.info(msg + ". Done.")
except:
self.logger.error(msg + ". Failed!")
raise
finally:
self._level -= 2
def run(self):
with self.task("Running"):
time.sleep(1.0)
with self.task("Sprinting"):
time.sleep(0.1)
raise Exception()
def debug_logger(logger):
# Example from https://www.electricmonk.nl/log/2017/08/06/understanding-pythons-logging-module/
while logger is not None:
print("level: {}, name: {}, handlers: {}".format(
logger.level, logger.name, logger.handlers))
logger = logger.parent
#logging.getLogger().addHandler(logging.StreamHandler(os.fdopen(1, "w")))
a = A()
a.run()
handler.formatter._style._fmt
import IPython
ip = IPython.get_ipython()
f = os.fdopen(1, "w")
f.write("JOIJQW")
f.write("JOIJQW")
import sys
sys.stderr.write("Hi")
logging.getLogger().handlers
%config Application.log_level="INFO"
Recomendations¶
-
Setup the loggers at the point of use, not at the start of a module etc. Getting the logger too early makes it difficult for the user to configure the logging attributes:
References¶