Skip to main content

A friendly, zero-config Python logger with pretty output, structured context, file rotation, and clean stdlib interop.

This project has been quarantined.

PyPI Admins need to review this project before it can be restored. While in quarantine, the project is not installable by clients, and cannot be being modified by its maintainers.

Read more in the project in quarantine help article.

Project description

lognest

A friendly, zero-configuration Python logger.

One import. Beautiful colored output. Structured context. File rotation. Pretty tracebacks. Thread-safe. Plays nicely with the standard logging module. Pure Python, no dependencies.

from lognest import log

log.info("hello world")
log.warning("careful now", user_id=42)
log.success("all done!")
2026-05-21 12:34:56.789 | INFO     | __main__:<module>:3 | hello world
2026-05-21 12:34:56.790 | WARNING  | __main__:<module>:4 | careful now user_id=42
2026-05-21 12:34:56.790 | SUCCESS  | __main__:<module>:5 | all done!

Install

pip install lognest

Features at a glance

Feature Example
Zero config from lognest import log; log.info("hi")
Levels trace · debug · info · success · warning · error · critical
Structured context log.info("done", request_id="abc", ms=42)
Bound context req_log = log.bind(request_id="abc")
Scoped context with log.contextualize(user="alice"): ...
File output log.add("app.log")
Size rotation log.add("app.log", rotate="10 MB", keep=5)
Time rotation log.add("app.log", rotate="daily", keep="7 days", compress=True)
JSON output log.add("app.jsonl", serialize=True)
Custom format log.add(sys.stderr, format="{time} {level} {message}")
Exception catching @log.catch / with log.catch(): ...
Exception with TB try: ... except: log.exception("oops")
stdlib interop log.intercept_stdlib()
Custom sink log.add(my_callable)
Per-sink filter log.add(..., filter=lambda r: "secret" not in r["message"])
Per-sink level log.add(..., level="WARNING")

Logging

from lognest import log

log.trace("very fine detail")
log.debug("debug detail")
log.info("informational")
log.success("operation succeeded")
log.warning("watch out")
log.error("something failed")
log.critical("crashing now")

Pass keyword arguments to attach structured context to a record:

log.info("payment processed", order_id=1234, amount=29.99, currency="USD")
# ... payment processed order_id=1234 amount=29.99 currency=USD

The message itself can also reference kwargs by name:

log.info("user {name} logged in from {ip}", name="alice", ip="10.0.0.1")

Bound and scoped context

req_log = log.bind(request_id="abc-123", user="alice")
req_log.info("started")
req_log.info("finished", ms=42)
with log.contextualize(job="cleanup"):
    log.info("removed temp files")     # job=cleanup appears in the record

Files and rotation

log.add(...) registers a new sink. The default stderr sink stays in place; you do not need to remove it.

# Plain file
log.add("app.log")

# Rotate every 10 megabytes, keep the 5 most recent
log.add("app.log", rotate="10 MB", keep=5)

# Rotate every day, keep a week, gzip the rotated files
log.add("app.log", rotate="daily", keep="7 days", compress=True)

# Errors only
log.add("errors.log", level="ERROR")

# JSON lines (great for log shippers and analytics)
log.add("events.jsonl", serialize=True)

# Custom format string
log.add("simple.log", format="{time} [{level}] {message}")

# Custom callable sink — receives the fully-rendered line
log.add(lambda line: my_queue.put(line))

log.add(...) returns an integer id. Use it to remove a single sink, or call log.remove() to remove all sinks.

sid = log.add("app.log")
log.remove(sid)
log.remove()           # remove everything (incl. the default stderr sink)

Rotation accepts:

  • A size: "10 MB", "500 KB", "1 GB", or a raw byte count 10_000_000
  • A schedule: "hourly", "daily", "weekly", "monthly"

Retention accepts:

  • A count: keep=5 keeps the five most recent rotated files
  • An age: keep="7 days" removes anything older

Catching exceptions

As a context manager:

with log.catch():
    risky_call()

As a decorator:

@log.catch
def task():
    1 / 0

@log.catch(reraise=True, message="task crashed")
def task():
    ...

Inside an except block:

try:
    risky_call()
except Exception:
    log.exception("call failed", endpoint="/api/x")

All three produce a clean, color-coded traceback.

Standard library interop

If a third-party library uses logging.getLogger(...), just reroute it:

from lognest import log
log.intercept_stdlib()         # everything now flows through lognest

import some_library
some_library.do_thing()

Custom format strings

The default format may be a str template or a callable.

Available placeholders for string templates:

{time} {level} {name} {function} {line} {file}
{message} {thread} {process}
{extra.key}            # any key attached via bind / contextualize / kwargs

For complete control, pass a callable that receives the record dict and returns a string:

def my_format(record):
    return f"[{record['level']}] {record['message']}"

log.add(sys.stderr, format=my_format)

Why lognest?

There are good loggers in the Python ecosystem already. lognest aims for the shortest path from "I want logs" to "I have nice logs":

  • One import, one object, sensible defaults — no factories, no handlers to wire up.
  • Structured context is just kwargs on every call.
  • Configuration uses plain words: rotate="10 MB", keep="7 days".
  • Catching exceptions and intercepting the stdlib is a one-liner.

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

lognest-0.1.1.tar.gz (17.6 kB view details)

Uploaded Source

Built Distribution

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

lognest-0.1.1-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

Details for the file lognest-0.1.1.tar.gz.

File metadata

  • Download URL: lognest-0.1.1.tar.gz
  • Upload date:
  • Size: 17.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for lognest-0.1.1.tar.gz
Algorithm Hash digest
SHA256 432d1c13ad3b68d942ab0850dec9bfc83b0d2e1cbb43afd5d54b0fca8a660851
MD5 16a4c0a8b3d1c2c8ee44ab20fe2c7294
BLAKE2b-256 cb8e31808d790f6987c5e4a9ff9d91d1519252c82f2b5e03288adec093132913

See more details on using hashes here.

File details

Details for the file lognest-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: lognest-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 15.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for lognest-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 99357532bf6182dbf6cff1c1b7d6e68b88208866e9fc027a63e5c373a84bbb85
MD5 20d55c6feb8564c40ab236f7b1041875
BLAKE2b-256 a3f5391e335ecd9ba8c5edbd7ff7f18c295320abef0e8deeba9368cdc645c769

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