Skip to main content

Batteries-included structured logger for Python data/ML projects, built on Rich.

Project description

klogr

Batteries-included structured logger for Python data/ML projects — built on Rich.

PyPI Downloads Python Publish License: MIT uv Ruff mypy jaxtyping PRs Welcome

  get_logger()
       |
       v
  +---------------------------+
  |        LoggingRich        |
  +---------------------------+
  | .info  .success  .warning |  -->  Rich-formatted console
  | .error .debug    .rule    |       with auto file:line prefix
  | .track .print    .info_json|
  +---------------------------+

  plus, from the same package:

    @lru_cache  +  DisableableLRUCache  -->  cached calls,
                                             with a disable hook for tests
    path_join / path_exists / path_open      -->  local + s3:// transparent
    get_elapsed_time(seconds)                -->  "01d : 01h : 12m : 03s"
    sha256sum(path) / get_cache_dir()        -->  stable on-disk caching

klogr is what you reach for when stdlib logging.basicConfig doesn't cut it and print() feels gross. It wraps Python's logging module with rich.logging.RichHandler pre-configured, adds stacklevel awareness so every line shows where it came from, and ships a handful of helpers (caching, paths, timing) that show up in every ML/data project.

Why use it

  • Drop-in get_logger() — module-scoped, cached, zero setup. No logging.basicConfig, no handler wiring.
  • Stacklevel-aware — every log line auto-prefixes with the caller's file:line. Stop hunting for which module shouted what.
  • logger.track() — wraps rich.progress.track() and works inside ThreadPoolExecutor / ProcessPoolExecutor without going silent.
  • logger.print() / logger.info_json() — pretty-print Pydantic models, dicts, JSON without piping through print(json.dumps(..., indent=2)).
  • @lru_cache with a disable hook — flip an env var to bypass caching globally (handy for tests).
  • Path helpers that handle S3path_join, path_exists, path_mkdir, etc. work whether you pass /tmp/foo or s3://bucket/foo.
  • get_elapsed_time(seconds) — formats float seconds as 00d : 01h : 12m : 03s.
  • One-liner dual outputlogger.enable_dual_output("run.log") and every log line goes to BOTH the Rich-formatted console AND the log file. Perfect for batch jobs you also want to scroll back through.

Install

uv add klogr
# or
pip install klogr

Requires Python ≥ 3.10. Runtime deps: rich, pydantic, python-dotenv, beartype, jaxtyping, natsort, sha256sum.

Quickstart

from klogr import get_logger

logger = get_logger()

logger.info("loaded %d samples", 1024)         # auto file:line prefix
logger.success("training converged")            # green check
logger.warning("validation loss plateaued")
logger.error("OOM on batch 42")

# Pretty-print structured data
logger.print({"epoch": 12, "lr": 3e-4, "loss": 0.21})

# Progress bar that works in parallel
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=8) as pool:
    for result in logger.track(pool.map(process, items), total=len(items), description="batch"):
        ...

What's in the box

Logger

from klogr import get_logger, LoggingRich, DEFAULT_VERBOSITY

logger = get_logger()                            # default verbosity
quiet  = get_logger({"info": False, "debug": False})  # custom

logger.info(msg)            # cyan
logger.success(msg)         # green check
logger.warning(msg)         # yellow
logger.error(msg)           # red
logger.rule(title)          # horizontal divider
logger.print(any_object)    # rich.print, soft-wrap aware
logger.info_json(json_str)  # syntax-colored JSON
logger.track(iter, total, description)  # progress bar

Log to console AND a file at the same time

One line to mirror everything you log into a file — handy for CI logs, batch jobs, or anything you want to scroll back through later.

from klogr import get_logger

logger = get_logger()

logger.enable_dual_output("training.log")   # everything below goes to BOTH
logger.info("epoch=12 lr=3e-4 loss=0.214")  # ...console (Rich colors)
logger.success("training converged")         # ...AND training.log

logger.disable_dual_output()                # back to console-only

Want it scoped to a block? LoggingRich doesn't expose a context manager directly, but the pattern is one line:

logger.enable_dual_output("step.log")
try:
    run_step()
finally:
    logger.disable_dual_output()

The file gets the Rich-rendered output verbatim (colors stripped on the file side, preserved in the terminal). Check logger.is_file_enabled() to confirm dual output is on.

Caching

from klogr import lru_cache, DisableableLRUCache, get_cache_dir, sha256sum

@lru_cache(maxsize=128)
def expensive(key: str) -> bytes:
    ...

# Stable on-disk paths
cache_root = get_cache_dir()                          # XDG cache root
digest     = sha256sum("/path/to/file.bin")           # hex string

Path helpers (local + S3 transparent)

from klogr.path import (
    path_join, path_exists, path_mkdir, path_dirname,
    path_basename, path_glob, path_is_s3, path_open,
)

path_exists("/tmp/local.bin")       # True/False
path_exists("s3://bucket/key.bin")  # True/False (same call)
path_mkdir("/tmp/nested/dir", parents=True, exist_ok=True)
for p in path_glob("/data/*.jpg"):
    with path_open(p, "rb") as f:
        ...

Timing

from klogr import get_elapsed_time

print(get_elapsed_time(86400 + 3661))   # '01d : 01h : 01m : 01s'

Examples

Runnable scripts live in examples/:

uv run examples/01_basic_logger.py

Layout

klogr/
├── __init__.py     # public re-exports
├── logger.py       # LoggingRich, LoggingTable, get_logger
├── cache.py        # lru_cache, DisableableLRUCache, sha256sum, get_cache_dir
├── path/           # local + S3 path helpers
│   ├── __init__.py
│   ├── ops.py      # pure ops (join, dirname, basename, suffix, …)
│   ├── env.py      # path_dotenv, path_home, path_expanduser
│   ├── io.py       # mkdir, remove, copy, move, read/write
│   └── query.py    # exists, is_dir, glob, listdir, stat
└── time.py         # get_elapsed_time

Build & test

uv sync
.venv/bin/pre-commit run --all-files
.venv/bin/pytest
.venv/bin/mypy klogr/

License

MIT — see LICENSE.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

klogr-0.1.6.tar.gz (31.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

klogr-0.1.6-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

Details for the file klogr-0.1.6.tar.gz.

File metadata

  • Download URL: klogr-0.1.6.tar.gz
  • Upload date:
  • Size: 31.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for klogr-0.1.6.tar.gz
Algorithm Hash digest
SHA256 d226c4e2856327a53f9bd42afe8ec7e2488a670d50e87f75b36945c7d45a304e
MD5 dcc84a2abcdbda1d23e2304f387ce2df
BLAKE2b-256 40f8ede5b34c14e5a61ed2fe3f2cb3794393aaf34fd2228a1d36492de84f720c

See more details on using hashes here.

File details

Details for the file klogr-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: klogr-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 26.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for klogr-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 eb322454144c6a5b348192ea3fb01e909c4f79287115de9958157252523a9212
MD5 9f4a5cacd23a927a322ed99b473484d3
BLAKE2b-256 c320655ad06bfd079696916e0723dd3d0411b964a4a1a130144cc21e5f0cdf1f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page