mrkeyoor.com_
Sun 20 Sept 15:55 UTC
PyPICLI & Toolingupdated 20 Sept 2026

colorlog review

colorlog 6.12.0 is a formatter layer for Python's standard `logging` module. It supplies ANSI escape-code fields such as `%(log_color)s`, `%(reset)s`, and secondary level-based colors while leaving logger creation, handlers, filters, and routing to `logging`. The release fixes `LevelFormatter` so a custom or unmapped level uses its fallback format instead of raising `KeyError`. Our sandbox install was pure Python, included `py.typed`, and imported successfully, which makes it a narrow typed addition rather than a replacement logging stack.

Verdict

colorlog 6.12.0 installed in 0.2 seconds, left 1 package and 1 MB in our sandbox, imported in 0.14 seconds, and produced 0 audit findings. Install it for colored standard-logging output; skip it when the destination expects structured events or the terminal needs more than a formatter.

We installed it

Lab card: what happened when we installed colorlogScreenshot of colorlog documentation
Install✓ · 0.2s1 package on disk · 1 MB
Importimport colorlog in 0.14s · pure Python · py.typed · requires Python >=3.6
Known vulns0(pip-audit)

Answers from our run

Does colorlog install cleanly?

Yes. In a fresh container with an empty cache, pip install colorlog finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.

What does colorlog need to run?

Python >=3.6, and nothing compiled: it is pure Python. In our run import colorlog succeeded in 0.14s, and the package ships py.typed for type checkers.

colorlog or rich: which should you use?

rich: Choose it when logs share a terminal with styled tracebacks, tables, or progress displays. colorlog 6.12.0 installed in 0.2 seconds, left 1 package and 1 MB in our sandbox, imported in 0.14 seconds, and produced 0 audit findings.

When should you not use colorlog?

Logs go straight to JSON ingestion. colorlog emits decorated strings; structlog or python-json-logger preserves fields for machines.

API stability5/5colorlog extends `logging.Formatter` and keeps configuration in familiar format strings, handlers, `dictConfig`, and `fileConfig`. The README says breaking proposals are declined to protect existing users. Version 6.12.0 changed only the failure path for an unmapped `LevelFormatter` level, preserving constructors and documented placeholders while making custom levels safer.
Docs4/5The repository README names every formatter argument, available color token, secondary mapping rule, environment override, configuration mechanism, and custom-level step. Its examples are short enough to transplant into a real logging setup. The stream argument carries an important TTY rule that is easy to overlook, and there is no separate versioned documentation site or migration guide.
Maintenance4/5GitHub shows an unarchived repository, 964 stars, 0 combined open issues and pull requests, and a last push on 23 July 2026. Release 6.12.0 shipped that day after a focused fix for missing `LevelFormatter` mappings. The maintainer promises bug-fix publication but calls the project maintenance mode, so stability is the goal and feature expansion is deliberately limited.
Ecosystem4/5The stored registry count is 14,747,731 weekly downloads, and the package plugs directly into Python's built-in logging configuration instead of introducing a parallel event model. The README lists packages for Debian, Ubuntu, Fedora, Arch, Gentoo, openSUSE, BSD ports, and conda-forge. Its reach is broad, though integrations are mostly inherited from `logging` rather than supplied by colorlog.

Use it if

  • Your code already uses Python logging and only the human-facing terminal handler needs colored levels.
  • Logging is configured with `dictConfig` or `fileConfig`, and changing the formatter class is preferable to replacing the logging API.
  • Different record fields need separate level-aware colors through `secondary_log_colors`.
  • A library or CLI still supports Python 3.6 and needs one formatter that spans that runtime range.
Skip it if

Setup reality

We installed colorlog 6.12.0 in a fresh Python 3.12 Bookworm sandbox in 0.2 seconds. The result was 1 package occupying 1 MB, and import colorlog completed in 0.14 seconds. pip-audit reported 0 known vulnerabilities. The distribution is pure Python, carries py.typed, declares 6 direct dependencies in the measured metadata, and accepts Python 3.6 or newer.

No service account, token, or project file is involved. Put %(log_color)s where coloring begins and %(reset)s where it ends. A dictConfig formatter needs the () factory entry set to colorlog.ColoredFormatter. Supplying log_colors replaces the built-in level map, so a custom mapping should name every standard level that the handler can receive.

TTY behavior depends on the stream passed to ColoredFormatter. Give it the same sys.stderr or sys.stdout used by the handler so a redirect can turn ANSI output off. NO_COLOR disables colors by presence, while FORCE_COLOR overrides it. Files and collectors should get a plain logging.Formatter; a second handler is clearer than trying to strip escape bytes later.

Windows installs use colorama for ANSI support. Custom logging levels work once registered with logging.addLevelName, but their names also need entries in the color map. LevelFormatter can select a different format per level; version 6.12.0 changed an absent mapping from a KeyError into fallback behavior. That is the only current-version change documented by the release commit.

Patterns

Color one stderr handler color-console-handler

import logging
import sys
from colorlog import ColoredFormatter

console = logging.StreamHandler(sys.stderr)
console.setFormatter(ColoredFormatter(
    '%(log_color)s%(levelname)-8s%(reset)s %(message)s',
    stream=sys.stderr,
))
log = logging.getLogger('jobs')
log.setLevel(logging.INFO)
log.addHandler(console)
log.warning('retrying upload')

`stream=sys.stderr` lets colorlog disable ANSI output when the 1 console stream is redirected.

Set up a small command configure-basic-logging

import colorlog

colorlog.basicConfig(
    level='INFO',
    format='%(log_color)s%(levelname)s%(reset)s %(message)s',
)
colorlog.getLogger('sync').info('scan complete')

`basicConfig` follows the standard logging rule: existing root handlers make this call a no-op.

Choose a color for every level map-level-colors

from colorlog import ColoredFormatter

formatter = ColoredFormatter(
    '%(log_color)s%(levelname)s%(reset)s %(message)s',
    log_colors={
        'DEBUG': 'cyan', 'INFO': 'green', 'WARNING': 'yellow',
        'ERROR': 'red', 'CRITICAL': 'bold_red',
    },
)

A custom `log_colors` dictionary replaces the default map instead of merging with its 5 standard levels.

Build the formatter through dictConfig use-dict-config

import logging.config

logging.config.dictConfig({
    'version': 1,
    'formatters': {
        'color': {
            '()': 'colorlog.ColoredFormatter',
            'format': '%(log_color)s%(levelname)s%(reset)s %(message)s',
        },
    },
    'handlers': {'console': {'class': 'logging.StreamHandler', 'formatter': 'color'}},
    'root': {'level': 'INFO', 'handlers': ['console']},
})

The `()` key is required because `dictConfig` must construct `colorlog.ColoredFormatter`, not the standard formatter.

Color the message independently separate-message-color

from colorlog import ColoredFormatter

formatter = ColoredFormatter(
    '%(log_color)s%(levelname)s%(reset)s %(message_log_color)s%(message)s%(reset)s',
    secondary_log_colors={
        'message': {'ERROR': 'red', 'CRITICAL': 'bold_red'},
    },
)

The secondary name `message` creates the record field `message_log_color`; the 2 names must match.

Honor redirected output respect-no-color

import logging
import sys
from colorlog import ColoredFormatter

handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(ColoredFormatter(
    '%(log_color)s%(message)s%(reset)s',
    stream=sys.stdout,
))

With the real stream supplied, a non-TTY destination receives text without ANSI color unless `FORCE_COLOR` is present.

Force color for a captured terminal force-terminal-color

from colorlog import ColoredFormatter

formatter = ColoredFormatter(
    '%(log_color)s%(message)s%(reset)s',
    force_color=True,
)

`force_color=True` wins over `no_color`; use it only when the 1 downstream consumer interprets ANSI escapes.

Register and color TRACE format-custom-level

import logging
from colorlog import ColoredFormatter

TRACE = 5
logging.addLevelName(TRACE, 'TRACE')
formatter = ColoredFormatter(
    '%(log_color)s%(levelname)s%(reset)s %(message)s',
    log_colors={'TRACE': 'light_black'},
)

Register the numeric level first, then use its exact uppercase name in the formatter's map.

Use a detailed format for DEBUG select-level-format

from colorlog import LevelFormatter

formatter = LevelFormatter(fmt={
    'DEBUG': '%(log_color)s%(message)s [%(module)s:%(lineno)d]',
    'INFO': '%(log_color)s%(message)s',
    'DEFAULT': '%(log_color)s%(levelname)s %(message)s',
})

colorlog 6.12.0 uses `DEFAULT` when a level name has no entry instead of raising `KeyError`.

Format with brace syntax use-brace-placeholders

from colorlog import ColoredFormatter

formatter = ColoredFormatter(
    '{log_color}{levelname:<8}{reset} {message}',
    style='{',
)

The `style='{'` argument must agree with every placeholder or Python logging rejects the format string.

Pick a 256-color terminal code use-256-colors

from colorlog import ColoredFormatter

formatter = ColoredFormatter(
    '%(fg_244)s%(asctime)s%(reset)s %(log_color)s%(message)s%(reset)s',
    datefmt='%H:%M:%S',
    log_colors={'WARNING': 'fg_214', 'ERROR': 'white,bg_red'},
)

`fg_N` and `bg_N` accept values from 0 through 255, but the visible result depends on terminal support.

Keep saved logs plain split-file-output

import logging
import sys
from colorlog import ColoredFormatter

console = logging.StreamHandler(sys.stderr)
console.setFormatter(ColoredFormatter(
    '%(log_color)s%(levelname)s%(reset)s %(message)s', stream=sys.stderr))
plain_file = logging.FileHandler('service.log')
plain_file.setFormatter(logging.Formatter(
    '%(asctime)s %(levelname)s %(name)s %(message)s'))
logging.basicConfig(level=logging.INFO, handlers=[console, plain_file])

Two handlers prevent ANSI bytes from entering the 1 file while preserving color on stderr.

Alternatives

PackageRegistryPick it when
richPyPIChoose it when logs share a terminal with styled tracebacks, tables, or progress displays.
structlogPyPIChoose it when events must stay structured through processors and gain color only at the console renderer.
coloredlogsPyPIChoose it for a quick logger installation API and configurable field styles.
loguruPyPIChoose it when replacing standard logging with managed sinks, rotation, and bound context is acceptable.

More cli & tooling guides

commander · chalk · typescript · esbuild · yargs · click · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.