Skip to main content

loglyte

Fast, structured Python logging with one import, optional function awareness, and TOML configuration.

from loglyte import logger

logger.info("Server started", port=8080)
logger.error("Payment failed", order_id=order_id)

No logger factories, module names, or runtime sink setup are required for ordinary application logging. Loglyte buffers records in memory and renders/writes them in batches, off the producer's hot path.

Python 3.10+. The only conditional dependency is tomli on Python 3.10, where TOML is not yet in the standard library.

The model

Use the global logger for normal events. Add @logger only where function or class awareness adds value:

from loglyte import logger


@logger(bind=("request_id", "user_id"))
def charge(order_id, request_id, user_id, log=None):
    log.info("Charging order", order_id=order_id)
    reserve_inventory(order_id, log=log)


def reserve_inventory(order_id, *, log):
    # This retains the parent operation's identity and bound context.
    log.info("Inventory reserved", order_id=order_id)

The decorator captures the function identity once at import time. It binds selected arguments for the call and injects log only if the function declares log=None. Global logger calls inside the decorated scope inherit the bound fields too.

Decorate a class when that policy belongs on all of its public methods:

@logger(bind=("tenant_id",))
class BillingService:
    def charge(self, tenant_id, order_id, log=None):
        log.info("Charging", order_id=order_id)

Private methods and __init__ are not wrapped. Instance methods, static methods, and class methods are.

Use @logger.critical for an error boundary. It logs the traceback and re-raises the exception—it never changes application control flow by swallowing an error.

@logger.critical(bind=("job_id",))
def run_job(job_id):
    raise RuntimeError("worker unavailable")

For context that is not a function parameter, use a short scope:

with logger.bind(request_id=request_id):
    logger.info("Request accepted")

Context is backed by contextvars, so it isolates concurrent asyncio tasks and does not leak across threads.

Configuration

Put loglyte.toml at the application working directory, or set LOGLYTE_CONFIG to its path. Loglyte discovers it once when imported. Configuration mistakes fail early with a clear error rather than silently changing production logging.

[loglyte]
flush_threshold = 500
flush_interval = 0.25
overflow_policy = "drop_oldest"
failure_policy = "retry"
retry_attempts = 2

[[sinks]]
type = "stderr"
level = "INFO"
format = "text"
color = "auto" # auto, always, or never
sample = 1.0
rate_limit = 500 # records per second for this sink
redact = ["password", "token", "authorization"]

[[sinks]]
type = "file"
path = "logs/app.jsonl"
level = "DEBUG"
format = "json"
max_bytes = 10_000_000
rotation_seconds = 86_400
retention_count = 7
process_safe = true
compression = "gzip"

Supported sink types are stderr, stdout, and file; formats are text, json, and logfmt. Configure all deployment behavior here: levels, redaction, rotation, queue flushes, retry behavior, sampling, and overflow policy. color = "auto" only emits ANSI colour to a TTY; use "always" for a local terminal or "never" for plain text. Sampling and rate limits are enforced while dispatching, never on producer calls.

process_safe = true serializes complete file batches and rotation with a sidecar lock. Enable it only when multiple Python processes write the same file: it has unavoidable synchronization overhead. The default is the lowest-latency, single-process path; threads are already serialized by Loglyte's dispatcher.

Set capture_warnings = true in [loglyte] to route Python warnings through the same configured sinks. Gzip compression runs after a file rotates, on the dispatcher rather than the application thread.

Integrations and escape hatches

get_logger(name), catch(), configure(), and custom sinks remain available for libraries and advanced integrations, but they are not the recommended application workflow. logger.exception("message") records a caught exception at ERROR; logger.shutdown() flushes on controlled worker/service shutdown.

catch() is deliberately retained for the distinct case where a background boundary must selectively report and suppress an expected exception type:

from loglyte import catch


@catch(ValueError, reraise=False, message="optional sync failed")
def sync_optional_resource(): ...

To collect standard-library logs from dependencies, install the bridge once at startup:

from loglyte.stdlib import install

install(level="INFO")

Delivery guarantees

Records are accepted into a bounded in-memory queue, then written when its threshold is reached, its interval elapses, logger.shutdown() runs, or Python exits normally. Overflows are counted and reported as warning records; SINK.health() exposes queue and sink-health counters. A hard kill can lose records still buffered in memory.

Performance

On the included Apple Silicon benchmark, Loglyte was 4–10x faster than standard library logging for emitted structured events and about 2.7x faster for JSON output. It is slower for discarded DEBUG calls, where the standard library has an extremely short level-check path. See benchmark results and rerun the suite on your own workload before treating numbers as representative.

Development

uv sync
uv run pytest
uv run ruff check .

License

GNU General Public License v3.0 only. See LICENSE.

Download files

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

Source Distribution

loglyte-1.0.0.tar.gz (36.6 kB view details)

Uploaded Source

Built Distribution

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

loglyte-1.0.0-py3-none-any.whl (37.8 kB view details)

Uploaded Python 3

File details

Details for the file loglyte-1.0.0.tar.gz.

File metadata

  • Download URL: loglyte-1.0.0.tar.gz
  • Upload date:
  • Size: 36.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for loglyte-1.0.0.tar.gz
Algorithm Hash digest
SHA256 1a6b8889f138d3b1d9138c1d33c811523fb7664ccc5570f1a3d32e4b6e36d946
MD5 22f2cc8389a9baf3d895c28b52bb27ea
BLAKE2b-256 0d9503cb5fd9932e0790d226d0936fb42b6045596cdb0d2738d2348e15b32091

See more details on using hashes here.

Provenance

The following attestation bundles were made for loglyte-1.0.0.tar.gz:

Publisher: workflow.yml on lokryn-llc/loglyte

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

File details

Details for the file loglyte-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: loglyte-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 37.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for loglyte-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8fdc2c2b44f572471f4930eb7b1f7e3c750544b0e3f42d3c2cbc04f1abba46f9
MD5 4da17b7a620d10470e82c842a02ff248
BLAKE2b-256 e9e0ef9ea547d829561d00f4f99d2a70cceff064fc28374c8607d802f3bef182

See more details on using hashes here.

Provenance

The following attestation bundles were made for loglyte-1.0.0-py3-none-any.whl:

Publisher: workflow.yml on lokryn-llc/loglyte

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

Release history Release notifications | RSS feed

This release

1.0.0 This release

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