Skip to main content

YAPL Kit

Yet Another Python Logger

A modern, minimal, and extensible logging toolkit built on top of Python's standard logging module.

YAPL keeps the stdlib logging ecosystem intact while adding structured logging, queue-backed delivery, formatting, coloring, buffering, stack helpers, and optional webhook support.

The core stays dependency-free. Optional integrations are installed only when you need them.

Installation

YAPL Kit requires Python 3.13 or newer.

With uv:

uv add yapl-kit

With pip:

pip install yapl-kit

Install all optional features:

uv add "yapl-kit[formatting,coloring,buffering,queueing,webhook]"

or:

pip install "yapl-kit[formatting,coloring,buffering,queueing,webhook]"

The canonical import namespace is yapl:

import yapl

The package also exposes a root-level compatibility namespace:

import yapl_kit

Documentation examples use yapl.

Quick Start

import yapl

yapl.setup_logging(
    level="INFO",
    outputs=("stdout",),
    format="text",
)

log = yapl.get_logger(__name__)

log.info("Hello world")
log.warning("Something happened")

Structured fields can be attached directly to log calls:

log.info("user_login", user_id=123, ip="1.2.3.4")
log.error("payment_failed", order_id="A-17", exc_info=True)

Shared request or job fields can be scoped to a block:

with yapl.context(request_id="req-42", user_id=123):
    log.info("request_started")
    log.info("request_finished")

For orderly application shutdown, call:

yapl.shutdown_logging()

This gives queued work its configured bounded drain window. Records still pending when the shutdown deadline expires may be discarded.

Use yapl.flush_logging() to drain queued work while keeping logging active, or use yapl.logging_session(...) for scripts that should configure and shut down YAPL around one block. yapl.logging_status() exposes queue and webhook delivery counters for operational checks.

logging_session() owns the process-wide YAPL configuration for its block and does not restore an earlier YAPL setup; use it at an application or script boundary rather than nesting it inside another logging session.

Design

YAPL does not replace Python logging. It builds on stdlib handlers, formatters, filters, LogRecord objects, and propagation.

The main design goals are:

  • keep the core small and dependency-free
  • preserve compatibility with Python's logging ecosystem
  • keep expensive formatting and I/O off the application hot path
  • make queueing, retries, and shutdown behavior bounded
  • keep optional features isolated and explicit
  • remain easy to understand and maintain

Configuration

YAPL supports direct setup arguments as well as typed configuration.

from yapl import WebhookConfig, YaplConfig, get_logger, setup_logging

config = YaplConfig(
    queue_max_size=2_000,
    webhook=WebhookConfig(
        "https://example.com/webhook",
        min_level="ERROR",
    ),
)

setup_logging(
    config,
    outputs=("stdout", "webhook"),
)

log = get_logger(__name__)
log.info("Application started")

Setup arguments override the supplied YaplConfig for that call without mutating the configuration object.

Output Profiles

A single process can use different output profiles for different sinks.

import yapl
from yapl import OutputConfig, YaplConfig

config = YaplConfig(
    sinks=(
        OutputConfig(
            "stdout",
            format="text",
            color="auto",
            theme_name="dark",
        ),
        OutputConfig(
            "file",
            format="jsonl",
            file_path="service.jsonl",
        ),
    ),
    resource={
        "service.name": "billing",
        "deployment.environment": "production",
    },
)

log = yapl.setup_logging(config)
log.info("payment_processed", request_id="req-42")

Use resource for stable source metadata such as service, environment, region, or cluster. Keep request IDs, user IDs, trace IDs, and other high-cardinality values as normal structured fields. File output profiles also support bounded rotation with file_max_bytes and file_backup_count; those options are valid only for file sinks.

Formatting

Structured, text, JSON Lines, and logfmt output are available through the formatting extension.

from yapl.extensions.formatting import (
    JSONFormatter,
    LogfmtFormatter,
    TextFormatter,
)

formatter = JSONFormatter()

Color output is restricted to human-facing text/plain terminal sinks. JSON, JSONL, logfmt, files, and webhooks remain machine-readable.

color="auto" emits ANSI only for a compatible terminal and respects NO_COLOR.

Queueing

Queue-backed handlers keep sink work away from application threads.

from yapl.extensions.queueing import QueueingConfig, QueueingHandler

In the default queued configuration:

  • queue insertion is bounded and non-blocking
  • formatting runs on workers
  • file and console sink work runs on workers
  • webhook payload construction and network I/O run on workers
  • retries and retry delays are bounded
  • shutdown waiting is bounded

Queue capacity limits the number of retained records, not their total byte size. Queued records may retain message arguments, extra values, exceptions, tracebacks, and object graphs until processed or discarded.

Webhooks

Webhook delivery is optional and uses httpx.

Install it with:

uv add "yapl-kit[webhook]"

Configure a webhook:

import yapl
from yapl.extensions.webhook import WebhookConfig

webhook = WebhookConfig(
    url="https://example.com/webhook",
    min_level="ERROR",
)

log = yapl.setup_logging(webhook=webhook)

Webhook work runs in the background so application threads do not intentionally wait for network I/O. Active webhook handlers reuse their HTTP client, and timeout/retry behavior is bounded.

Buffering

Buffering captures records during a block and then replays or discards them when the block exits.

from yapl.extensions.buffering import (
    BufferedLogs,
    BufferingConfig,
    install_buffering,
)

install_buffering()

with BufferedLogs(BufferingConfig(flush_mode="ordered")):
    log.info("preflight", phase="warmup")
    log.warning("preflight_warning", stage=1)

The default behavior flushes buffered records on success and on error. Configuration can be used to discard them instead when a block should remain silent.

Extended Levels

YAPL can register extra development levels:

import yapl

yapl.setup_logging(level_mode="extended")

log = yapl.get_logger(__name__)
log.trace("trace message")
log.dev("dev message")

Built-in extended levels:

Level Value
TRACE 5
DEV 15

Stack Helpers

Callsite and tracing helpers live under yapl.stack.

from yapl import get_logger, setup_logging
from yapl.stack import FunctionCallTracer, get_callsite

setup_logging(level_mode="extended")
callsite = get_callsite()

tracer = FunctionCallTracer(get_logger(__name__))
tracer.enable_current_thread()
try:
    run_complex_operation()
finally:
    tracer.disable_current_thread()

Guarantees and Non-Guarantees

In the default queued configuration, remote and sink I/O never runs on the caller thread, and queue insertion does not intentionally wait.

This is an operational guarantee for YAPL's queue and built-in webhook path, not an absolute claim that logging can never block under every possible configuration.

Guaranteed by default

  • Queue-backed delivery has a bounded record count.
  • Queue insertion uses non-blocking insertion under the default overflow policy.
  • Formatting, file/console delivery, webhook payload work, HTTP, DNS, and retry waits happen on background workers.
  • Webhook retry attempts and retry delays are bounded.
  • Active webhook handlers reuse a lazily created HTTP client.
  • Shutdown waiting is bounded by shutdown_timeout_seconds.
  • Records may be discarded when the shutdown deadline expires so the caller can continue.

Not guaranteed

  • Delivery of every record during overload, remote failure, or shutdown.
  • A fixed byte-level memory limit.
  • Termination of arbitrary custom handlers already blocked forever.

Python cannot safely terminate arbitrary user handler code. Keep custom handlers non-blocking or give them their own timeouts.

Explicit opt-outs

overflow_policy="block" deliberately enables application-level backpressure and may block the caller. With enqueue_timeout_seconds=None, that wait may be indefinite.

queue_enabled=False runs normal stdlib handlers directly, so file, console, or custom sink work may occur on the caller thread.

Optional Modules

YAPL keeps concrete optional features under explicit modules:

from yapl.stack import FunctionCallTracer, get_callsite
from yapl.extensions.buffering import BufferedLogs, BufferingConfig
from yapl.extensions.coloring import install_color_structured_console
from yapl.extensions.formatting import JSONFormatter, StructuredFormatterConfig
from yapl.extensions.queueing import QueueingConfig
from yapl.extensions.webhook import WebhookConfig

The yapl.extensions package is a namespace; concrete features live in its submodules.

Package Philosophy

YAPL is intended to be a small quality-of-life logging toolkit rather than a replacement observability framework.

The focus is on:

  • predictable behavior
  • low caller-side overhead
  • bounded background work
  • readable configuration
  • stdlib compatibility
  • optional features without unnecessary runtime weight

Metadata

Release files for yapl-kit 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yapl-kit 0.2.0
File Size Uploaded
yapl_kit-0.2.0.tar.gz 52.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yapl-kit 0.2.0
File Interpreter ABI Platform
yapl_kit-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 126.7 kB

Release files / yapl_kit-0.2.0.tar.gz

Download URL yapl_kit-0.2.0.tar.gz
Size 52.4 kB
Tags Source
SHA-256 checksum
How to use checksums
773b618570c305b9a52d242e85c19834a4546906c73f9abafa8cca829c28c966
BLAKE2b-256 checksum
How to use checksums
4619bc36e3ae5a1803536aa00f80d558a1c6a768915d9f5bcaf24d23ef298fed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log

Release files / yapl_kit-0.2.0-py3-none-any.whl

Download URL yapl_kit-0.2.0-py3-none-any.whl
Size 74.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bfa94675933e1af4f46b0640c5cb644b615947ade0e043003cd86d47df173b39
BLAKE2b-256 checksum
How to use checksums
6c9b8ef0e3f3801d42aa1d9c34bbda4ab68679644d7b6f3996cf4a4c83058bdd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page