Skip to main content

logurich

Python 3.9+ License: MIT PyPI version

A Python library combining standard logging and Rich for beautiful logging.

Installation

pip install logurich
pip install logurich[click]

Usage

from rich.panel import Panel

from logurich import get_logger, init_logger

init_logger("INFO", enqueue=False)

logger = get_logger(__name__)

logger.info("This is a log message")
logger.info("Hello %s", "world")

logger.info(
    "Rich renderables",
    extra={
        "renderables": (
            Panel("Rich panel output", border_style="green"),
        )
    },
)

with logger.contextualize(app=logger.ctx("demo", style="yellow")):
    logger.info("This log has scoped context")

logger.info(
    "Per-call context",
    extra={
        "context": {
            "session": logger.ctx("sess-42", style="cyan", show_key=True),
        }
    },
)

For full IDE autocompletion of ctx(...), rich(...), bind(...), and contextualize(...), use get_logger(...) from logurich instead of logging.getLogger(...). It returns the same logger instance but typed as LogurichLogger. logger.ctx(...) is shorthand for the existing module-level ctx(...) helper, and logger.contextualize(...) is a convenience alias for global_context_configure(...). The module-level helpers remain supported if you prefer global_context_configure(...) or extra={"context": {"key": ctx(...)}}.

logging.getLogger(...) still works at runtime — only the typing differs.

For short-lived scripts and CLIs, init_logger() automatically registers an atexit hook, so you do not need to call shutdown_logger() just to flush logs at process exit.

Named Loggers

Use the standard library to create named loggers:

from logurich import get_logger, init_logger

init_logger("INFO", enqueue=False)

logger = get_logger(__name__)
logger.info("Hello from %s", __name__)

Use get_logger(...) from logurich for typed access. logging.getLogger(...) still works at runtime.

Using Logurich in Reusable Libraries

If you are writing a Python library that will be imported by another program, the library should not call init_logger() on its own. Let the main application own logging configuration, handler setup, and shutdown.

Inside the library, use standard named loggers:

# mylib/service.py
from rich.panel import Panel

from logurich import ctx, get_logger

logger = get_logger(__name__)


def run_job(job_id: str) -> None:
    logger.info(
        "Starting job %s",
        job_id,
        extra={"context": {"job": ctx(job_id, style="cyan", show_key=True)}},
    )
    logger.info(
        "Job details",
        extra={
            "renderables": (
                Panel(f"Job {job_id} is running", border_style="green"),
            )
        },
    )

Then configure Logurich once in the main program:

# main.py
from logurich import init_logger
from mylib.service import run_job

init_logger("INFO", enqueue=False)

run_job("job-42")

Guidelines for libraries:

  • Use get_logger(__name__) from logurich inside library modules.
  • Do not call init_logger() or shutdown_logger() from library code.
  • Emit normal stdlib log calls such as logger.info("Value %s", value).
  • Use extra={"context": ...} and extra={"renderables": ...} only as optional metadata; they render nicely when the consuming application uses Logurich, and logger.ctx(...) / logger.rich(...) are also available when Logurich has been imported/configured by the application.
  • If the library starts worker processes and the application uses enqueue=True, accept the queue from the application and call configure_child_logging(queue) inside each worker process.

Multiprocessing

When enqueue=True, Logurich is process-safe only if worker processes send records through the shared logging queue created by the parent process.

import multiprocessing as mp

from logurich import configure_child_logging, get_log_queue, get_logger, init_logger


def worker(log_queue: mp.Queue, worker_id: int) -> None:
    configure_child_logging(log_queue)
    get_logger(f"worker.{worker_id}").info("worker=%s ready", worker_id)


def main() -> None:
    init_logger("INFO", enqueue=True)
    log_queue = get_log_queue()

    processes = [
        mp.Process(target=worker, args=(log_queue, index), name=f"worker-{index}")
        for index in range(3)
    ]

    for process in processes:
        process.start()

    for process in processes:
        process.join()

Only the process that calls init_logger(..., enqueue=True) owns the console and file handlers. Child processes must call configure_child_logging(queue) before logging.

Call shutdown_logger() explicitly only when you need deterministic teardown before process exit, such as in tests or when reconfiguring logging multiple times in the same interpreter.

Click CLI helper

Install the optional Click extra to automatically expose logger configuration flags inside your commands:

import click

from logurich import get_logger
from logurich.opt_click import click_logger_params


@click.command()
@click_logger_params
def cli():
    logger = get_logger(__name__)
    logger.info("Click integration ready!")

The click_logger_params decorator injects --logger-level, --logger-verbose, --logger-filename, --logger-level-by-module, and --logger-rich flags and configures Logurich before your command logic runs. The usage example above is also available at examples/click_cli.py.

Idempotent initialisation (force)

By default, calling init_logger() a second time is a no-op — the existing configuration is kept and the call returns None. Pass force=True to tear down the current setup and reconfigure from scratch:

from logurich import init_logger

init_logger("INFO", enqueue=False)          # first call: configures logging
init_logger("DEBUG", enqueue=False)         # no-op, returns None
init_logger("DEBUG", enqueue=False, force=True)  # reconfigures logging

This is useful when tests or interactive sessions need to reset logging between runs.

User input

The user_input module provides Rich-enhanced prompts with type coercion, hidden input, and optional timeouts. It does not depend on Click.

from logurich import get_logger, init_logger, user_input, user_input_with_timeout

init_logger("INFO", enqueue=False)
logger = get_logger(__name__)

# Basic string input
name = user_input("Enter your name", type=str)

# Integer input with a default value
count = user_input("How many items?", type=int, default=5)

# Hidden input (e.g. passwords)
secret = user_input("Enter secret", type=str, hide_input=True)

# Input with a timeout (5 seconds, Unix only — falls back to regular input on Windows)
answer = user_input_with_timeout("Quick! Type something", timeout_duration=5)

A runnable example is available at examples/user_input_example.py.

Download files

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

Source Distribution

logurich-0.9.3.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

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

logurich-0.9.3-py3-none-any.whl (21.6 kB view details)

Uploaded Python 3

File details

Details for the file logurich-0.9.3.tar.gz.

File metadata

  • Download URL: logurich-0.9.3.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for logurich-0.9.3.tar.gz
Algorithm Hash digest
SHA256 7a0875ffda72a7821ffa43c317776d5175541cdca36e14ac1ac94c49440fc580
MD5 5b0991694a331c18c2b878c665c0e06d
BLAKE2b-256 3df76bc7817aa55422890dc173629ff208782ef1a53d1b3a8e4aaf8526f59d4c

See more details on using hashes here.

Provenance

The following attestation bundles were made for logurich-0.9.3.tar.gz:

Publisher: ci.yml on PakitoSec/logurich

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file logurich-0.9.3-py3-none-any.whl.

File metadata

  • Download URL: logurich-0.9.3-py3-none-any.whl
  • Upload date:
  • Size: 21.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for logurich-0.9.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e853926f92bfbe5bfc0879ec001d223b85762fca2008b4f4bbcef6da8d0e118a
MD5 30630d294fc0473e5a4f6de9ce1c9379
BLAKE2b-256 816deaaaa52de6fd8a35eb99812fbd71ca2d97a3ef27a85947aaedbbdcf54628

See more details on using hashes here.

Provenance

The following attestation bundles were made for logurich-0.9.3-py3-none-any.whl:

Publisher: ci.yml on PakitoSec/logurich

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.0.1

2 files

1.0.0

2 files

This release

0.9.3 This release

2 files

0.9.2

2 files

0.9.1

2 files

0.9.0

2 files

0.8.3

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.1

2 files

0.7.0

2 files

0.6.0

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page