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.2.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.2-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: without_logging-0.0.2.tar.gz
  • Upload date:
  • Size: 14.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","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.2.tar.gz
Algorithm Hash digest
SHA256 790418976d7c5fc6a9365834dbd673d467e141a28c61d4d3ba561272c38a92f2
MD5 172de253c8991b317cfce70059f3f19e
BLAKE2b-256 2b585046cee76edf05a9b16abf16bdbd0ea7335ffaa5bd7543cfbd4202de28fb

See more details on using hashes here.

File details

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

File metadata

  • Download URL: without_logging-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1d2888054f5b3bfa4289ff0ffa441f027de4968067a1bb3191e9b2e5377847b4
MD5 77408c59c15e1228d670522f0a7eddc5
BLAKE2b-256 5d03d62140a6c8d4aa8ebefb4905a654282f21cdc7554f7bea5d37d6b46db840

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