Goal
Create a logger for a python library that results in terminal output like this:
The library
yippy
has its own color, the logger has different colors for INFO
, WARNING
, ERROR
, etc statements, and the logger’s level can be set by the user on a per-library basis. To do this we will use ANSI escape codes and a custom logger built with the standard Python logging
library.
ANSI escape codes
An ANSI escape code is a sequence of characters used to control the formatting, color, and other output options on text terminals that support ANSI standards. These codes are used to add color, move the cursor, and alter text appearance in terminal outputs.
Format of an ANSI Escape Code
An ANSI escape code typically starts with the escape character (\033
or \x1b
) followed by a bracket ([
), and then a series of numerical values that specify the formatting options, followed by an ending character such as m
for text formatting.
For coloring, the code looks something like this:
|
|
\033
: The escape character that signals the terminal to interpret the following characters as a special instruction.[
: Indicates the beginning of the sequence.<code>
: Numeric codes that determine the text color or style (e.g., bold, underlined).m
: Marks the end of the code and applies the formatting.
Example of Common Codes
- Foreground (Text) Colors:
- Black:
\033[30m
- Red:
\033[31m
- Green:
\033[32m
- Yellow:
\033[33m
- Black:
- Background Colors (similar to text colors but starting with 40–47):
- Red Background:
\033[41m
- Red Background:
- Reset/Normal Text:
- To reset formatting:
\033[0m
- To reset formatting:
Example in Code
|
|
This will display the text “This text is red!” in red, and then reset the color back to normal with \033[0m
.
Further information
The best resource I’ve found is this graphic: ANSI Escape Codes · GitHub
Logger.py
My typical logger.py file looks like this:
|
|
The colors can be adjusted by changing the ColorCodes class, the ColorFormatter class applies the colors to the messages (and identifies the library with the custom “LIB” color), and the code at the end creates a shell logger and a log file (if you’re dumping to a debug.log file or something). The format of the log messages is different for the shell and log file, as seen in the shell_fmt
and file_fmt
strings. The file_fmt
includes more debug information such as the filename, function name, and line number of the log statement. For example, are the log statements in debug.log from the same call as in the screenshot at the start of this tutorial
|
|
Using the logger
In your library you’ll want to modify the logger (e.g. change lib_name
, lib_color
, shell_fmt
, and file_fmt
) and save it as something like logger.py
and add the necessary info to the relevant __init__.py
files to make it importable. I typically have it saved as src/package_name/logger.py
so that in my files I can run
|
|
Adding log statements
After importing your logger
you can add statements like
|
|
Please make it shut up
Say you’re working on a project that relies on your library, but you don’t want to get a million INFO
statements in your terminal from your library. In your project script/driver file you can import the logger from your overly-talkative library and shut it up with
|
|
This also can be done by a library, so for example if my coronagraphoto
library relies on yippy
but doesn’t need the INFO
statements I can run yippy_logger.setLevel(logging.WARNING)
at the point that coronagraphoto
needs to use yippy
. That can then be overruled by the driver script as well.
TL;DR
- Copy the
logger.py
code to your library (e.g.src/my_library/logger.py
) - Adjust the
lib_color
(choose one of these colors) andlib_name
(to your library’s name) - Change your
src/my_library/__init__.py
file to includelogger
in__all__
and add a linefrom .logger import logger
- Import the logger in your library files (
from my_library.logger import logger
) - Add log statements to your code (
logger.info("This is an info message")
)