Add color to Python logging output

Use colorlog or a custom logging formatter for terminal colors, while keeping redirected output and file logs free of ANSI escape sequences.

Best practices
Python programming and application logging

Add color in the console handler's formatter. Keep a separate plain formatter for file logs so terminal escape sequences do not enter log files or downstream parsers.

Use colorlog

Install the formatter in your application's environment:

python -m pip install colorlog
import logging
import sys
import colorlog

handler = logging.StreamHandler(sys.stderr)
if sys.stderr.isatty():
    formatter = colorlog.ColoredFormatter(
        "%(log_color)s%(levelname)s%(reset)s: %(message)s",
        log_colors={
            "DEBUG": "cyan", "INFO": "green", "WARNING": "yellow",
            "ERROR": "red", "CRITICAL": "bold_red",
        },
    )
else:
    formatter = logging.Formatter("%(levelname)s: %(message)s")
handler.setFormatter(formatter)

logger = logging.getLogger("colored_example")
logger.setLevel(logging.INFO)
logger.propagate = False
logger.addHandler(handler)
logger.error("Connection failed")

Configure this once at startup. Running the setup repeatedly adds handlers and can duplicate messages. The terminal check disables color when stderr is redirected, although a TTY alone does not guarantee ANSI support in every environment.

Write a formatter without an extra dependency

This is an alternative to the formatter above:

class ColorFormatter(logging.Formatter):
    COLORS = {"WARNING": "\033[33m", "ERROR": "\033[31m"}

    def format(self, record):
        message = super().format(record)
        color = self.COLORS.get(record.levelname)
        return f"{color}{message}\033[0m" if color else message

if sys.stderr.isatty():
    handler.setFormatter(ColorFormatter("%(levelname)s: %(message)s"))

This formats the message without modifying the shared LogRecord, so another handler can use its own formatting.

Keep file output plain

file_handler = logging.FileHandler("app.log", encoding="utf-8")
file_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
logger.addHandler(file_handler)

Do not put escape codes directly into the logged message; that would affect both handlers. For machine-readable output, use consistent structured fields rather than color as the only indication of severity.

What about Windows terminals?

Modern Windows terminals commonly support ANSI colors. Colorlog uses Colorama for Windows support; when writing raw ANSI yourself, use an appropriate Colorama setup or fall back to plain text on terminals that do not support it.

References

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting