haiku.rag/haiku_rag_slim/haiku/rag/telemetry.py
2026-05-26 11:44:47 +03:00

47 lines
1.7 KiB
Python

from typing import Literal
from logfire import Logfire, attach_context, get_context
# Scoped Logfire instance — every span emitted through `logfire.span(...)`
# on this object carries `instrumentation_scope.name = "haiku.rag"` instead
# of the default "logfire". The scope is OTel's identifier for *which
# library* produced the span, separate from `service.name` which is the
# running process. Downstream consumers (Logfire UI saved views, OTel
# collectors, alert rules) can then filter on `scope.name = haiku.rag`
# rather than catching every span the SDK ever exports.
#
# Cross-library instrumentations (pydantic-ai, FastAPI, OpenAI) keep their
# own scopes — this only retags the spans WE write.
logfire = Logfire(otel_scope="haiku.rag")
def configure(
*,
service_name: str | None = None,
console: Literal[False] | None = False,
) -> None:
"""Configure Logfire and enable pydantic-ai instrumentation for the
running process. Each CLI entry point calls this once at startup.
Silently no-ops on failure so a missing/misconfigured LOGFIRE_TOKEN
never crashes the app.
- service_name: identifies the process in the Logfire UI (e.g.
"haiku-ingester"). Falls back to logfire's default when None.
- console: False (default) suppresses span lines on stderr so they
don't interleave with RichHandler logs. Pass None to let logfire
decide (its own default applies).
"""
try:
import logfire as _lf
_lf.configure(
service_name=service_name,
send_to_logfire="if-token-present",
console=console,
)
_lf.instrument_pydantic_ai()
except Exception: # pragma: no cover
pass
__all__ = ["attach_context", "configure", "get_context", "logfire"]