Metadata-Version: 2.3
Name: yapl-kit
Version: 0.2.0
Summary: YetAnotherPythonLogger - a minimal, extensible logging toolkit built on top of Python's standard logging module.
Author: SirKaiMartin
Requires-Dist: httpx>=0.28.1 ; extra == 'webhook'
Requires-Python: >=3.13
Provides-Extra: buffering
Provides-Extra: coloring
Provides-Extra: formatting
Provides-Extra: queueing
Provides-Extra: webhook
Description-Content-Type: text/markdown

# 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`:

```bash
uv add yapl-kit
```

With `pip`:

```bash
pip install yapl-kit
```

Install all optional features:

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

or:

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

The canonical import namespace is `yapl`:

```python
import yapl
```

The package also exposes a root-level compatibility namespace:

```python
import yapl_kit
```

Documentation examples use `yapl`.

## Quick Start

```python
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:

```python
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:

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

For orderly application shutdown, call:

```python
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.

```python
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.

```python
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.

```python
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.

```python
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:

```bash
uv add "yapl-kit[webhook]"
```

Configure a webhook:

```python
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.

```python
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:

```python
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`.

```python
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:

```python
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
