OpenTelemetry ingestion¶
This is the universal path: any framework that can emit OpenTelemetry spans
streams into LoopLens with no LoopLens code in your agent. The server exposes
an OTLP/HTTP receiver at POST /v1/traces; point your existing OTel exporter at
it and the spans become LoopLens runs, events, and loop warnings.
Setup¶
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
exporter = OTLPSpanExporter(endpoint="http://127.0.0.1:8765/v1/traces")
# register it on your TracerProvider, then instrument your framework as usual
Or configure it with the standard environment variables — no code at all:
Then start the dashboard (looplens dev) and run your agent.
Install¶
OTLP/JSON works with the base server and no extra dependency. The common
default wire format, OTLP/protobuf, needs the otel extra:
If a protobuf request arrives without the extra installed, the endpoint replies
415 with a hint (or export OTLP/JSON via OTEL_EXPORTER_OTLP_PROTOCOL=http/json).
What gets mapped¶
LoopLens is deliberately lenient and reads whichever semantic convention a span
uses — openinference.*, traceloop.*, gen_ai.*, or llm.*:
| Span | Becomes | Fields captured |
|---|---|---|
| LLM / chat-model span | llm_call_started + llm_call_completed |
model, token counts, latency, input/output |
| Tool span | tool_call_started + tool_call_completed |
tool name, input/output, latency |
| Span with error status | the _failed variant |
error message |
| Root span (no parent) | the run | run name, start/end, completed/failed status |
One trace becomes one run. Because exporters often flush child spans before the root finishes, a late-arriving root span corrects the run's name and status. Span kinds LoopLens doesn't map (retriever, embedding, …) are skipped, not errored.
Example¶
examples/otel_openinference_openai.py captures a real OpenAI call through
OpenInference's auto-instrumentation — three lines of OTel setup, then your code
runs untouched:
pip install 'looplens[otel]' opentelemetry-sdk \
opentelemetry-exporter-otlp-proto-http \
openinference-instrumentation-openai openai
export OPENAI_API_KEY=sk-...
looplens dev
PYTHONPATH=. python examples/otel_openinference_openai.py
The same three-line setup works for the OpenInference / OpenLLMetry instrumentations of LangChain, LlamaIndex, CrewAI, AutoGen, and others — LoopLens just ingests the spans.
Handoffs
Agent handoffs expressed as transfer_to_<agent> / handoff_to_<agent> tool
spans (the LangGraph supervisor/swarm and CrewAI convention) are mapped to
handoff_started events, so the handoff_bounce detector
fires through this path. Arbitrary node-to-node transitions are not yet
treated as handoffs.