A without pipeline for logs: stdlib log records parsed into immutable values, filtered and enriched as processors, drained to a sink.
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file without_logging-0.0.1.tar.gz.
File metadata
- Download URL: without_logging-0.0.1.tar.gz
- Upload date:
- Size: 13.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51038c3028c723b9f20f69e4a34add88d2c63614b0195c7cff040f5b2a9de74b
|
|
| MD5 |
94a43070e90197829567c00c7d0dbf6a
|
|
| BLAKE2b-256 |
81ac07c89ae04ae2e1286293177ac4afff5ac7d309f1d81d59b8dd7ca476451f
|
File details
Details for the file without_logging-0.0.1-py3-none-any.whl.
File metadata
- Download URL: without_logging-0.0.1-py3-none-any.whl
- Upload date:
- Size: 17.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f682a6171b4a1184c9d887d8dc97edff1c29e7d3d61c79d649ad8482c8c151a
|
|
| MD5 |
7d1598df02c282c884c6991ea7820e79
|
|
| BLAKE2b-256 |
9fd84c532e2390bc0b8a8911fe2bdb7e0b7bafe9438567e001b20f8ebe09698f
|