🔠Telemetry
General​
- Axiom.co is used as the telemetry platform
Backend telemetry​
- OpenTelemetry is used log instrumentation
- Traces and Logs are currently enabled
- Traces and logs are sent to Axiom only in production and are sent to separate datasets
- Traces - traces
- Logs - logs
- In local development logs are sent to console while traces are disabled
Traces​
- Traces are instrumented using the FastAPI automatic instrumentation
- This means that traces are created automatically for all requests to the API
- Adding additional info to traces:
- Adding a new Span - A span represents a unit of work or operation. Spans are the building blocks of Traces
with tracer.start_as_current_span("span name"):
// Span will include eveyrthing in this context - Attributes - key value pairs added to the Span
current_span = trace.get_current_span()
current_span.set_attribute("custom_attribute", "custom message") - Events - a structured log message on a Span
current_span = trace.get_current_span()
current_span.add_event("Running opertation") - Attributes vs Events: generaly if the timestamp in which something happened is important, attach the data to a span event, otherwise use an attribute.
- Adding a new Span - A span represents a unit of work or operation. Spans are the building blocks of Traces
Logs​
- The OTel support for python logs is still under development
- The logs are instrumented using the standard python logging instrumention
- Verbosity: info and above logs are enabled
- To add a new log:
# Typically the logger is available in the global context and you don't need to retrieve it
logger.info("info log")
Langfuse​
- Langfuse is used for LLM observability (traces for AI/LLM calls, separate from OTEL)
- All LLM calls made via LiteLLM are automatically traced - no manual instrumentation needed
- Traces include token usage, model, input/output, and metadata like
session_id,user_id,investigation_id - To trace a function explicitly, use the
@langfuse.observe()decorator:from server.telemetry.langfuse.langfuse_setup import get_langfuse_client
langfuse = get_langfuse_client()
@langfuse.observe(name="my_operation")
def my_function(input):
... - To attach metadata to the current trace:
from server.telemetry.langfuse.langfuse_utils import update_current_langfuse_trace
update_current_langfuse_trace(session_id="...", user_id="...", investigation_id="...") - Certain OTEL instrumentation scopes (e.g. FastAPI requests, auth, background tasks) are blocked from Langfuse to reduce noise — configure in
server/telemetry/langfuse/langfuse_setup.py