Skip to main content

Ergonomic Python logging with Rich-first defaults and a path to structured observability.

Project description

ultilog

CI PyPI Python License

Ergonomic Python logging that starts with a tiny API and scales to structured observability.

from ultilog import get_logger

log = get_logger()
log.info("app.started")

No explicit settings required. The package lazily configures logging on first access, installs a Rich console handler, and returns a standard-library logger.

Install

pip install ultilog

With extras:

pip install "ultilog[structlog]"   # structlog processor bridge
pip install "ultilog[otel]"        # OpenTelemetry traces, logs, metrics
pip install "ultilog[web]"         # FastAPI / Starlette middleware
pip install "ultilog[full]"        # everything

Quickstart

Zero config

from ultilog import get_logger

log = get_logger()
log.info("hello")

Explicit naming

log = get_logger(__name__)
log = get_logger("my.service")

Optional setup

from ultilog import setup, get_logger

setup(level="DEBUG", force=True)
log = get_logger()

Presets

Three presets configure sensible defaults:

Preset Mode Level Rich
dev (default) rich INFO Enabled
test plain WARNING Disabled
prod json INFO Disabled
setup(preset="prod", force=True)

Modes

Rich (default)

Pretty console output with colors, tracebacks, and path info.

setup(mode="rich", force=True)
get_logger("demo").info("colored output")

Plain

Simple stream logging for CI, containers, or piped output.

setup(mode="plain", force=True)
get_logger("demo").info("plain output")

JSON

Machine-readable JSON logs for production and log aggregators.

setup(mode="json", force=True)
get_logger("api").info("request.finished")
# {"level": "INFO", "logger": "api", "message": "request.finished", ...}

Context

Context belongs at runtime boundaries, not logger creation time. Use logging_context to bind values that appear in every log record within a scope:

from ultilog import get_logger, logging_context

log = get_logger("worker")

with logging_context(job_id="job_1", queue="emails"):
    log.info("job.started")   # job_id=job_1 queue=emails
    log.info("job.finished")  # job_id=job_1 queue=emails
# context automatically restored

Context is contextvars-based, so it works correctly with asyncio and nested scopes:

with logging_context(outer="1"):
    with logging_context(inner="2"):
        log.info("both")  # outer=1 inner=2
    log.info("outer only")  # outer=1

Lower-level helpers are available for integrations:

from ultilog import bind_context, clear_context, get_context

bind_context(request_id="req_123")
get_context()  # {"request_id": "req_123"}
clear_context()

Framework Integrations

FastAPI / Starlette

from fastapi import FastAPI
from ultilog.integrations import install_fastapi_logging

app = FastAPI()
install_fastapi_logging(app)
# Every request gets logging context with request_id, http.method, http.path

ASGI Middleware

from ultilog.integrations import UltilogASGIMiddleware

app = UltilogASGIMiddleware(app)

Celery

from ultilog.integrations import install_celery_logging

install_celery_logging(app)
# Tasks get context with celery_task_id and celery_task_name

httpx

from ultilog.integrations import install_httpx_logging

client = httpx.Client()
install_httpx_logging(client)
# Logs outgoing HTTP requests at DEBUG level

SQLAlchemy

from ultilog.integrations import install_sqlalchemy_logging

install_sqlalchemy_logging(engine, level=logging.DEBUG)

Structlog

When structlog is installed, ultilog can configure it with pre-built processor chains:

from ultilog.structlog import configure_structlog

configure_structlog()  # console renderer for dev

Choose a renderer that matches your mode:

from ultilog.models.structlog import StructlogSettings

configure_structlog(StructlogSettings(renderer="json"))

OpenTelemetry

With the otel extra installed, configure traces, logs, and metrics:

from ultilog.otel.traces import configure_otel_traces
from ultilog.otel.logs import configure_otel_logs
from ultilog.otel.metrics import configure_otel_metrics

configure_otel_traces(service_name="my-api")
configure_otel_logs(service_name="my-api")
configure_otel_metrics(service_name="my-api")

Or configure all signals at once:

from ultilog.otel.exporters import configure_exporters
from ultilog.models.otel import OTelSettings

configure_exporters(OTelSettings(
    enabled=True,
    service_name="my-api",
    traces_enabled=True,
    logs_enabled=True,
))

Trace/log correlation is automatic when a span is active:

from ultilog.otel.correlation import TraceCorrelationFilter

handler.addFilter(TraceCorrelationFilter())
# Log records get trace_id and span_id attributes

Environment Variables

Settings use the ULTILOG_ prefix with __ for nesting:

export ULTILOG_PRESET=prod
export ULTILOG_LOGGING__LEVEL=DEBUG
export ULTILOG_LOGGING__MODE=json
export ULTILOG_RICH__SHOW_PATH=false

CLI

ultilog doctor --json          # runtime diagnostics
ultilog show-config            # dump effective settings
ultilog validate               # check configuration
ultilog demo --mode plain      # emit a demo log line
ultilog demo --mode json

Or via module:

python -m ultilog doctor --json

Testing

ultilog provides test utilities so downstream projects can isolate logging state:

from ultilog.testing.reset import reset_ultilog
from ultilog.testing.capture import capture_logs

reset_ultilog()  # reset package state

with capture_logs("my.logger") as records:
    get_logger("my.logger").info("captured")
assert records[0].getMessage() == "captured"

Advanced Configuration

For full control, use configure() with an explicit settings object:

from ultilog import configure, UltilogSettings

settings = UltilogSettings(
    preset="prod",
    logging=LoggingSettings(level="DEBUG", mode="json"),
    context=ContextSettings(enabled=True),
)
configure(settings, force=True)

Development

pdm sync -G dev -G docs
pdm run pytest                 # tests
pdm run ruff check .           # lint
pdm run mypy src/ultilog       # type-check
pdm run mkdocs serve           # docs preview

License

MIT

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

ultilog-0.2.0.tar.gz (44.6 kB view details)

Uploaded Source

Built Distribution

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

ultilog-0.2.0-py3-none-any.whl (61.4 kB view details)

Uploaded Python 3

File details

Details for the file ultilog-0.2.0.tar.gz.

File metadata

  • Download URL: ultilog-0.2.0.tar.gz
  • Upload date:
  • Size: 44.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ultilog-0.2.0.tar.gz
Algorithm Hash digest
SHA256 bccb921d6a0f12844c0e4bd84c1a7a7cafd4eee53f73d0e9d248fe15e6c980f2
MD5 c5acafa2ee3f82343c706876bb069f93
BLAKE2b-256 3d430a98931df1887b8143dc16d961fe332748b1abf209679cc1fd051de059f0

See more details on using hashes here.

Provenance

The following attestation bundles were made for ultilog-0.2.0.tar.gz:

Publisher: release.yml on pr1m8/ultilog

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

File details

Details for the file ultilog-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: ultilog-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 61.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ultilog-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 34a6cfec3895fdab3b06b55f4b15b6d34e9e14f30f5e3b9ec70e6512815a071c
MD5 8eb6938d8e2a79709dc0a1776beac9d9
BLAKE2b-256 1c71156792e748f86b774b59e39024d7f54e6081b8b7a2e6a46acbfe19fe3a52

See more details on using hashes here.

Provenance

The following attestation bundles were made for ultilog-0.2.0-py3-none-any.whl:

Publisher: release.yml on pr1m8/ultilog

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

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