Skip to main content
A translation run touches many moving parts — multiple LLM calls, MCP database tools, and ephemeral compile sandboxes — and can take several minutes. When something is slow or wrong, you need to see where. UOM ships with three complementary, independently-toggleable observability backends, all driven by environment variables. All three can run at once; they are wired so their own export traffic does not pollute the traces (see §4).

1. LangSmith (LangGraph-native tracing)

LangGraph emits traces to LangSmith automatically when tracing is enabled. Set these in services/orchestrator/.env (or .env.dev):
Once set, every run of the universal-object-mapping-translator graph appears in your LangSmith project as a trace tree: extract_input → schema_inspection → generate_translation_node → validate_* → evaluation_node, with each node’s inputs, outputs, token counts, and latency. This is the primary tool for prompt debugging and for spotting which stage dominates a run’s wall-clock time.
During local development, the langgraph dev server opens the LangSmith Agent Studio automatically at startup, letting you inspect and replay traces interactively without leaving your machine.

2. Pydantic Logfire (OpenTelemetry)

Logfire is configured and active by default in react_agent/graph.py. It instruments the HTTP clients and the OpenAI-compatible SDK so every outbound model/MCP/sandbox call becomes an OpenTelemetry span:
Provide a token to ship spans to Logfire’s backend:
Because Logfire speaks OpenTelemetry, you are not locked into Pydantic’s hosted backend. Point the standard OTEL_EXPORTER_OTLP_* environment variables at any OTLP-compatible collector (Grafana Tempo, Honeycomb, Jaeger, your own OpenTelemetry Collector) to keep telemetry in your own infrastructure. The repo also sets OTEL resource attributes so traces are tagged with the source revision:
Daytona sandbox telemetry can be forwarded too, via DAYTONA_OTEL_ENABLED=true / DAYTONA_EXPERIMENTAL_OTEL_ENABLED=true.

3. Langfuse (optional)

Langfuse support is available (the langfuse dependency is installed) but its LangChain CallbackHandler is commented out by default in graph.py. To enable it, supply credentials and uncomment the handler wiring:
Use Langfuse if you want self-hosted LLM analytics, scoring, or prompt management alongside (or instead of) LangSmith.

4. Keeping Telemetry Out of the Traces

A subtle but important detail: the tracing backends themselves make HTTP calls (to upload spans). Without care, Logfire’s httpx instrumentation would trace Langfuse’s and LangSmith’s own uploads, creating noisy, recursive spans. UOM excludes those URLs from instrumentation:
Keep these in sync if you add another exporter whose upload endpoint you do not want traced.

5. Bring Your Own Backend — Checklist

  1. Just want graph/prompt traces? Set the four LANGSMITH_* vars. Nothing else required.
  2. Want OTEL spans in your own collector? Set LOGFIRE_TOKEN (or configure a bare OTLP exporter) and the OTEL_EXPORTER_OTLP_ENDPOINT. Logfire is already instrumenting the code.
  3. Want self-hosted LLM analytics? Add the LANGFUSE_* vars and uncomment the handler in graph.py.
  4. Add a new excluded URL to the OTEL_PYTHON_*_EXCLUDED_URLS regexes whenever you add an exporter, so its upload traffic does not get traced.

DevOps & Deployment

Compose profiles, env configuration, and production operations.

Getting Started

Boot the stack and enable request mocking for local dev.

Architecture

The graph whose spans you are tracing.

Why runs are slow

Use traces to confirm where the ~12 minutes go.