Skip to content

Observability recipes (low-cardinality tags)

See also: HTTP recipes, DB recipes, Worker recipes.

Read this page when you want backend-agnostic observability patterns and operational guidance for tags, stop reasons, and hook usage in real systems.

For the observability contract itself, see Observability. For the canonical core API shape, see Usage.

Redress emits lifecycle events via on_metric and on_log. These hooks are designed for metrics/logging without coupling to a specific backend.

Do (low-cardinality): - class (ErrorClass) - operation (stable operation name) - stop_reason - cause (exception or result) - event (retry, success, deadline_exceeded, etc.)

Don't (high-cardinality): - full URLs or query strings - user IDs, request IDs, trace IDs - raw SQL or exception messages - stack traces

If you need detailed diagnostics, log them separately at debug level, not as tags.

Copy/paste example

from redress import Policy, Retry, default_classifier
from redress.strategies import decorrelated_jitter


def metric_hook(event: str, attempt: int, sleep_s: float, tags: dict[str, object]) -> None:
    # Keep tags low-cardinality.
    print(f"event={event} attempt={attempt} sleep_s={sleep_s:.3f} tags={tags}")

policy = Policy(
    retry=Retry(
        classifier=default_classifier,
        strategy=decorrelated_jitter(max_s=3.0),
    )
)

policy.call(do_work, on_metric=metric_hook, operation="worker_task")

Stop reasons in execute()

If you need a structured stop reason, use execute() and inspect the outcome:

outcome = policy.execute(do_work, operation="worker_task")
print(outcome.stop_reason)

stop_reason is intentionally low-cardinality (ABORTED, DEADLINE_EXCEEDED, SCHEDULED, MAX_ATTEMPTS_EXCEEDED, etc.).