oss-vs-frontier-assistant / src /observability.py
KevinMerchant13's picture
Phase 7: initial deploy (cpu-basic)
35c0d38 verified
"""Observability via Langfuse (v4).
Initializes the Langfuse client from our settings and re-exports the pieces the
rest of the app uses to trace itself:
- ``observe`` : decorator that turns a function into a traced span
(use as_type="generation" for model calls,
as_type="tool" for tool calls).
- ``trace_attributes`` : context manager that stamps trace-level fields
(session_id, tags, metadata) onto every span
created inside it.
- ``annotate_span`` : add metadata to the currently-running span.
- ``flush`` / ``current_trace_url`` : flush buffered events; fetch the URL of
the trace currently in scope.
If Langfuse keys are not configured, every export degrades to a safe no-op so
the app and eval still run untraced.
"""
from __future__ import annotations
from contextlib import contextmanager, nullcontext
from src.config import settings
# Tracing is only active when both Langfuse keys are present.
enabled = bool(settings.langfuse_public_key and settings.langfuse_secret_key)
if enabled:
from langfuse import Langfuse, get_client
from langfuse import observe as observe # re-export
from langfuse import propagate_attributes as _propagate
# Configure the singleton client explicitly. We pass keys from settings
# because they live in .env (read by pydantic) and are NOT exported to
# os.environ, which is the only place the Langfuse SDK would look otherwise.
Langfuse(
public_key=settings.langfuse_public_key,
secret_key=settings.langfuse_secret_key,
host=settings.langfuse_host,
)
_client = get_client()
def trace_attributes(**kwargs):
"""Stamp trace-level attributes (session_id, tags, metadata, ...)."""
return _propagate(**kwargs)
def annotate_span(**kwargs) -> None:
"""Attach metadata/name/level to the current span."""
_client.update_current_span(**kwargs)
def flush() -> None:
_client.flush()
def current_trace_url() -> str | None:
try:
return _client.get_trace_url()
except Exception: # noqa: BLE001
return None
else:
def observe(func=None, **_kwargs): # type: ignore[misc]
"""No-op stand-in for langfuse.observe (supports @observe and @observe(...))."""
if callable(func):
return func
def _decorator(f):
return f
return _decorator
def trace_attributes(**_kwargs):
return nullcontext()
def annotate_span(**_kwargs) -> None:
pass
def flush() -> None:
pass
def current_trace_url() -> str | None:
return None