summary refs log tree commit diff
diff options
context:
space:
mode:
authoruser <user@node5.net>2024-03-17 15:24:19 +0100
committeruser <user@node5.net>2024-03-17 15:24:19 +0100
commitc0cfc6cbb35b8b3d0d13849c381b398ba4c565b2 (patch)
tree83efff39a6118fde3c59295defb667eda483230b
parent551f267641336f1ed298e7d047d22cb6ca83c8a3 (diff)
python logging how to
-rw-r--r--How-to/Python/Logging.md112
1 files changed, 112 insertions, 0 deletions
diff --git a/How-to/Python/Logging.md b/How-to/Python/Logging.md
new file mode 100644
index 0000000..6297819
--- /dev/null
+++ b/How-to/Python/Logging.md
@@ -0,0 +1,112 @@
+---
+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
+    - Just information, for an 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 (terminal)
+    - A log file
+    - A log server
+
+> A python *"module"* is simply just the name for a .py file
+
+```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)
+
+<pre>
+$ python /tmp/1.py
+<span style="color:grey">2024-03-17 14:09:06,411,411 DEBUG    [1.py:37] debug message</span>
+<span style="color:var(--main-color)">2024-03-17 14:09:06,411,411 INFO     [1.py:38] info message</span>
+<span style="color:yellow">2024-03-17 14:09:06,411,411 WARNING  [1.py:39] warning message</span>
+<span style="color:red">2024-03-17 14:09:06,411,411 ERROR    [1.py:40] error message</span>p>
+<span style="font-weight: bold; color:red">2024-03-17 14:09:06,411,411 CRITICAL [1.py:41] critical message</span>
+</pre>
+
+
+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.
+
+<pre>
+$ root
+├── <span class="devicons devicons-python"></span> main
+└── <span class="devicons devicons-python"></span> module_a
+</pre>
+
+You can set a breakpoint and inspect `logger.parent` to see this structure:
+```pycon
+>>> logger.parent
+<RootLogger root (DEBUG)>
+```
+
+Read more: [docs.python.org - Logging HOWTO](https://docs.python.org/3/howto/logging.html)