--- created: 2024-03-17 description: Python logging with ✨pretty colors🌸 --- ## Logging > print Logging is useful, because all python code can use the same standard, allowing you to centrally control: - Which messages you wish to see - Every debug message, for local development - Disable debug messages, by changing 1 line e.g. for end user deployment - How to format them - Do you wish to see which module and line of code this message originated from - Where they should end up - Printed to [STDOUT](https://en.wikipedia.org/wiki/Standard_streams) (terminal) - A log file - A log server - Maybe a notification should be triggered on CRITICAL errors > A python [*"module"*](https://docs.python.org/3/tutorial/modules.html) is simply just the name for a .py file. > e.g. the file `database_handler.py` is a module called `database_handler` ```py import logging class ColorFormatter(logging.Formatter): grey = "\x1b[90;20m" cyan = "\x1b[96;20m" yellow = "\x1b[33;20m" red = "\x1b[31;20m" bold_red = "\x1b[31;1m" reset = "\x1b[0m" format = "%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s" FORMATS = { logging.DEBUG: grey + format + reset, logging.INFO: cyan + format + reset, logging.WARNING: yellow + format + reset, logging.ERROR: red + format + reset, logging.CRITICAL: bold_red + format + reset } def format(self, record): log_fmt = self.FORMATS.get(record.levelno) formatter = logging.Formatter(log_fmt) return formatter.format(record) logger = logging.getLogger(__name__) # Instantiate a logger to be used in this module # Display every message Change this to INFO to see INFO and above (filter out DEBUG) # See: https://docs.python.org/3/howto/logging.html#logging-levels logger.root.setLevel(logging.DEBUG) stream_handler = logging.StreamHandler() # This catches and handles log messages on the root handler stream_handler.setFormatter(ColorFormatter()) logger.root.addHandler(stream_handler) logger.debug("debug message") logger.info("info message") logger.warning("warning message") logger.error("error message") logger.critical("critical message") ``` > Code snippet is modified, but based on: > [stackoverflow.com - How can I color Python logging output?](https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output#answer-56944256). > Used and credited as per [stackoverflow.com - CC BY-SA 4.0 content license](https://stackoverflow.com/help/licensing)
$ python /tmp/1.py
2024-03-17 14:09:06,411,411 DEBUG    [1.py:37] debug message
2024-03-17 14:09:06,411,411 INFO     [1.py:38] info message
2024-03-17 14:09:06,411,411 WARNING  [1.py:39] warning message
2024-03-17 14:09:06,411,411 ERROR    [1.py:40] error messagep>
2024-03-17 14:09:06,411,411 CRITICAL [1.py:41] critical message
In subsequent modules, do the following: ```py import logging logger = logging.getLogger(__name__) # Set the logger name, to the name of the module logger.debug("debug message") logger.info("info message") logger.warning("warning message") logger.error("error message") logger.critical("critical message") ``` > Wish to change the colors? > Color codes can be found here: [wikipedia.org - ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit) Okay, but why do we need to do it this way? Because logging is hieratical, these 2 loggers will be siblings under the root logger (see following tree structure). Therefore we set a handler on the root logger which ensures all logging will hit our formatting code.
$ root
├──  main
└──  module_a
You can set a breakpoint and inspect `logger.parent` to see this structure: ```pycon >>> logger.parent ``` Read more: [docs.python.org - Logging HOWTO](https://docs.python.org/3/howto/logging.html)