without-logging
A without pipeline for logs. Logger calls (yours and every third-party
library's) ultimately produce a stream of records; this package parses each one
into an immutable Record value, lets you filter and enrich them as ordinary
processors, and drains the result into a sink you own.
The two stdlib logging pain points it targets: the impenetrable, mutable,
noun-heavy configuration, and the monolithic handlers that bundle unrelated
decisions (when to flush, how to rotate, how to format) into one object. Here a
record is a value, each stage is a Processor, and the sink is whatever you
compose.
import logging
from without import compose, from_selector, from_sink
from without_logging import Level, at_least, capture
async def write(record):
print(f"{record.timestamp:%H:%M:%S} {record.level_name} {record.message}")
pipeline = compose(from_selector(at_least(Level.WARNING)), from_sink(write))
async with capture(pipeline): # attaches to the root logger for the block
logging.getLogger("app").warning("disk almost full", extra={"free_pct": 3})
capture is the one impure piece: it activates a handler on the root logger,
turns the pushed records into a Stream, and runs your pipeline against them for
the life of the block. Everything upstream of the sink is pure and testable
without touching the logging machinery.
To write to a file without paying a thread hop per line, offload runs a blocking
writer on a single dedicated thread, fed by a queue that delivers items in bursts
(so the writer flushes when it catches up, no flush-frequency knob). Writers are
named by destination: to_rotating_file writes to a file (owning the byte count and
clock, rotating on any combination of size (max_bytes), a relative interval
(max_age), and absolute wall-clock boundaries (schedule=at_times(...))), and
to_stream writes to a caller-owned text stream (sys.stderr, a socket) without
closing it. Both take strings (render a Record to text with a from_map in front):
from datetime import timedelta
from without import compose, from_map, from_selector
from without_logging import Level, at_least, offload, to_rotating_file
writer = to_rotating_file(lambda i, when: directory / f"app.{i}.log", max_bytes=64 << 20, max_age=timedelta(hours=1))
async with offload(writer) as sink:
lines = compose(from_map(render), sink) # Record -> str -> file
async with capture(compose(from_selector(at_least(Level.WARNING)), lines)):
... # WARNING+ records written off the event loop, rotated by size and time
See the
without-logging guide
(with the API reference)
for the design narrative: why stdlib becomes a one-way source, why filtering is
just the core from_selector builder, and where fan-out to multiple sinks slots
in.
Metadata
Release files for without-logging 0.0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| without_logging-0.0.5.tar.gz | 14.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| without_logging-0.0.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.8 kB
Release files / without_logging-0.0.5.tar.gz
| Download URL | without_logging-0.0.5.tar.gz |
|---|---|
| Size | 14.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bcd0af0947fa4892384c3b458a985790c66ba5f5c2a93891589d237983743ff4
|
|
BLAKE2b-256 checksum How to use checksums |
23d2e67177885ffb44c1c9e59f3ed70671cd88cb3fe149d0df41b58867655d4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / without_logging-0.0.5-py3-none-any.whl
| Download URL | without_logging-0.0.5-py3-none-any.whl |
|---|---|
| Size | 17.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
474d4c565a2d7eb5e877e5fc2b7914c82e6b5eb9ebccaf61e3de0a9763fb9953
|
|
BLAKE2b-256 checksum How to use checksums |
3dc4a69d01dcb4fb66f33750e1e4fee3c24caf3c2462d8ae0bb1e7a03fc486b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|