Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

lognest

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lognest

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

pipPyPI
Version
0.1.4
Maintainers
1

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

FeatureExample
Zero configfrom lognest import log; log.info("hi")
Levelstrace · debug · info · success · warning · error · critical
Structured contextlog.info("done", request_id="abc", ms=42)
Bound contextreq_log = log.bind(request_id="abc")
Scoped contextwith log.contextualize(user="alice"): ...
File outputlog.add("app.log")
Size rotationlog.add("app.log", rotate="10 MB", keep=5)
Time rotationlog.add("app.log", rotate="daily", keep="7 days", compress=True)
JSON outputlog.add("app.jsonl", serialize=True)
Custom formatlog.add(sys.stderr, format="{time} {level} {message}")
Exception catching@log.catch / with log.catch(): ...
Exception with TBtry: ... except: log.exception("oops")
stdlib interoplog.intercept_stdlib()
Custom sinklog.add(my_callable)
Per-sink filterlog.add(..., filter=lambda r: "secret" not in r["message"])
Per-sink levellog.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.

Keywords

logging

FAQs

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts