Skip to main content

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.

Download files

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

Source Distribution

without_logging-0.0.3.tar.gz (14.1 kB view details)

Uploaded Source

Built Distribution

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

without_logging-0.0.3-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file without_logging-0.0.3.tar.gz.

File metadata

  • Download URL: without_logging-0.0.3.tar.gz
  • Upload date:
  • Size: 14.1 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for without_logging-0.0.3.tar.gz
Algorithm Hash digest
SHA256 d27d142a95ec4f04416df86157ad4acea199650ce6eddbb2cea826bf6489461c
MD5 e9665f108336486ca75d944933f23ce4
BLAKE2b-256 b9dc5f05c0625efed0dc5f66375fcc20b2d6aef6d1042186be9a2a7a43a9ae27

See more details on using hashes here.

File details

Details for the file without_logging-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: without_logging-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for without_logging-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3d041a982c89cb61e55f82dec63c7b622b2cb48079ada6cf64ef71e344aedf76
MD5 beb50df59c17f37b836c1b6c112b1a4d
BLAKE2b-256 fdc877e42751e7c80fcf36f9ec5f7f54e1f2b551e9451c31f846ccb862828bae

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 Sentry Error logging StatusPage Status page