pythonloggingcolorslog-level

How to configure python simple "logging" with different colors for different levels


I have created simple python script:

import logging
import sys

if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG)
    print("This is a normal print statement", file=sys.stdout)
    logging.debug("debug message")
    logging.info("info message")
    logging.warning("warning message")

I would expect that the color for the "INFO" level will be same as sysout or at least some neuetral color. But the output of the run of my script is:

enter image description here

I would like the "INFO" logs to be in at least same color as the one coming from "print". I have tried to add config like this:

logging.basicConfig(level=logging.DEBUG,  format="%(asctime)s - %(levelname)s - %(message)s")

But this did not help. I do not want to setup "loggers" for my project because using simple "logging" is more convienient for me.

In the real project which I am developing I have several classes where I use all the levels and many log messages, so this RED info logs makes the whole logs very unreadable.

I cannot believe that its normal for the INFO log to be red, but as you see I dont have any special configs. How I can easily configre the "logging" to have proper colouring?


Solution

  • Here are some examples for log config using VT100 control codes for the colors without any dependencies:

    import logging
    
    RESET = "\033[0m"
    INVERSE = "\033[7m"
    GREEN = "\033[32m"
    RED_BG = "\033[41m"
    
    
    # Set up general logging using green. you can try other colors here.
    # changing colors again for all messages like this might require
    # rerunning the script to take effect
    
    logging.basicConfig(
        level=logging.INFO,
        format=f"{GREEN}%(asctime)s %(message)s{RESET}",
        datefmt="%y-%m-%d %H:%M:%S"
    )
    
    
    logger = logging.getLogger(__name__) 
    logger.setLevel(logging.INFO)
    
    logger.info("This is an info message")
    

    This will cause logs to be on red background. You can use the other VT100 codes for different effects. See Microsoft page on vt100 as a starting point for more info.




    Edit: I saw your comment about avoiding loggers. Essentially what you want to do to keep things simple is to have the logging set up in your __init__.py or such to keep it in one place. Then in the other files:

    logger = logging.getLogger(__name__)  # Config loaded from __init__.
    logger.info("This is an info message")
    

    The getlogger based on a given name avoids circular imports that might otherwise cause problems when attempting to import your logging from a central place.




    Here is one more example that is a bit more complex. We set only the info messages to have a specific color. You can still use the above presented style for getlogger to get the logger in other files

    import logging
    
    RESET = "\033[0m"
    GREEN = "\033[32m"
    
    # Custom formatter to apply green only to INFO messages
    class InfoColorFormatter(logging.Formatter):
        def format(self, record):
            message = super().format(record)
            if record.levelname == "INFO":
                return f"{GREEN}{message}{RESET}"
            return message
    
    # Configure logging
    logging.basicConfig(
        level=logging.DEBUG,  # Capture all log levels
        format="%(asctime)s %(levelname)s: %(message)s",
        datefmt="%y-%m-%d %H:%M:%S"
    )
    
    # Apply custom formatter to the root logger's handlers
    handler = logging.getLogger().handlers[0]
    handler.setFormatter(InfoColorFormatter("%(asctime)s %(levelname)s: %(message)s"))
    
    # Logger usage
    logger = logging.getLogger(__name__) 
    logger.debug("This is a debug message")
    logger.info("This is an info message")  # Will be green
    logger.warning("This is a warning message")
    logger.error("This is an error message")
    logger.critical("This is a critical message")