Source code for fluxlit.tracing
"""Optional no-dependency tracing hooks for FluxLit internals.
The core package does not depend on OpenTelemetry. Integrations can register a
small context-manager factory and translate FluxLit spans into any tracing backend.
"""
from __future__ import annotations
from collections.abc import Callable, Mapping
from contextlib import AbstractContextManager, nullcontext
from contextvars import ContextVar, Token
from typing import TypeAlias
TraceValue: TypeAlias = str | int | float | bool | None
TraceAttributes: TypeAlias = Mapping[str, TraceValue]
TraceHook: TypeAlias = Callable[[str, TraceAttributes], AbstractContextManager[None]]
_trace_hook: ContextVar[TraceHook | None] = ContextVar("fluxlit_trace_hook", default=None)
[docs]
def set_trace_hook(hook: TraceHook | None) -> Token[TraceHook | None]:
"""Install a tracing hook for the current context and return a reset token."""
return _trace_hook.set(hook)
[docs]
def reset_trace_hook(token: Token[TraceHook | None]) -> None:
"""Reset the tracing hook installed by :func:`set_trace_hook`."""
_trace_hook.reset(token)
[docs]
def trace_span(name: str, attributes: TraceAttributes) -> AbstractContextManager[None]:
"""Return a context manager for an optional span.
If no hook is installed, this is a no-op. Hook exceptions intentionally bubble
up so integrations fail loudly during development instead of hiding broken
instrumentation.
"""
hook = _trace_hook.get()
if hook is None:
return nullcontext()
return hook(name, attributes)