Send your GenAI traces to Sumo Logic with OpenLLMetry
The Sumo Logic AI Observability app reads OpenLLMetry traces, which follow the OpenTelemetry GenAI semantic conventions (gen_ai.*) and add traceloop.* attributes. Any library that emits gen_ai.* span attributes works, and you don't need a Sumo Logic agent or SDK.
Get started with OpenLLMetry instrumentation
Use either OpenLLMetry or OpenTelemetry instrumentation method per process. Running both can generate duplicate spans.
| Category | OpenLLMetry |
|---|---|
| Overview | Open-source Traceloop SDK built on OpenTelemetry. |
| Setup | Install the SDK and initialize it with Traceloop.init(). |
| Prompt and response capture | Enabled by default. |
| Best suited for | Broad provider and framework coverage with minimal code. |
Tested providers and frameworks
The following providers and frameworks have been tested with OpenLLMetry. Any provider or framework that OpenLLMetry instruments and that emits gen_ai.* span attributes works with the app.
| Vendor | OpenLLMetry |
|---|---|
| Google Gemini | Yes |
| Groq | Yes |
| LangChain and LangGraph | Yes |
| LlamaIndex | Yes |
| Haystack | Yes |
| OpenAI and AI gateways: Helicone, OpenRouter, Braintrust | Yes |
How to instrument your LLM application?
Prerequisites
- Create a Sumo Logic OTLP/HTTP source and copy its source URL. The URL contains the authentication token, so you don't need to set headers or API keys.
- Use Python 3.10 or later.
- Use one virtual environment per method. Don't install OpenTelemetry and OpenLLMetry together.
Step 1. Set up the exporter
Set up the exporter only once in your application, using OpenLLMetry. Every example in Instrument your application assumes it has run first, so none of them repeats it.
-
Set the following environment variables, along with your LLM provider's API key. Use the same source URL value as the OpenTelemetry method:
export TRACELOOP_BASE_URL="<YOUR_SOURCE_URL>"export OTEL_SERVICE_NAME="<YOUR_SERVICE_NAME>"export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=<YOUR_ENVIRONMENT>"export TRACELOOP_METRICS_ENABLED=false # Sumo Logic drops OTLP histogram metrics, so send traces onlyOTEL_SERVICE_NAMEbecomes the service filter in the dashboards, anddeployment.environmentbecomes the environment filter. -
Install the SDK:
pip install "traceloop-sdk>=0.62.0" -
Initialize the SDK by adding the following code at the start of your application, before you import any LLM or framework library:
import osfrom traceloop.sdk import Traceloop# Endpoint comes from TRACELOOP_BASE_URL. Service name and deployment.environment# come from OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES.Traceloop.init(app_name=os.getenv("OTEL_SERVICE_NAME"),api_endpoint=os.getenv("TRACELOOP_BASE_URL"),telemetry_enabled=False, # don't send anonymous SDK usage data to Traceloop) -
Flush spans before the process exits. OpenLLMetry has no public
flush(), but it registers the global provider:from opentelemetry import tracetrace.get_tracer_provider().shutdown()In a long-running service, skip the shutdown call. Spans are sent in batches.
Step 2. Instrument your application
You can use Python to instrument your LLM application directly with OpenLLMetry.
- Python
Google Gemini
Traces content generation, including streamed calls, made with the Google GenAI SDK (google-genai), for both the Gemini Developer API and Vertex AI.
Gemini spans use the operation name generate_content, not chat.
Install:
pip install "traceloop-sdk>=0.62.0" google-genai
Run the following code after the OpenLLMetry setup:
import os
from google import genai
client = genai.Client() # reads GEMINI_API_KEY
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="What is 15 multiplied by 7?",
)
print(response.text)
The provider is reported as gcp.gen_ai.
Additional resources:
Groq
Traces chat completions sent to Groq.
Install:
pip install "traceloop-sdk>=0.62.0" groq
Run the following code after the OpenLLMetry setup:
import os
from groq import Groq
client = Groq() # reads GROQ_API_KEY
response = client.chat.completions.create(
model="openai/gpt-oss-20b",
messages=[{"role": "user", "content": "What is 15 multiplied by 7?"}],
max_tokens=100,
)
print(response.choices[0].message.content)
Uses the native Groq SDK, so the provider is reported correctly as groq.
Additional resources:
LangChain and LangGraph
Traces agents, chains, chat models, and tool calls. One package covers both LangChain and LangGraph. The example is a tool-calling agent: each run appears as a LangGraph.workflow span with invoke_agent, execute_task, ChatOpenAI.chat, and execute_tool child spans.
Install:
pip install "traceloop-sdk>=0.62.0" "langchain<2" langchain-openai
Run the following code after the OpenLLMetry setup:
import os
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two integers."""
return a * b
agent = create_agent(ChatOpenAI(model="gpt-4o-mini"), tools=[multiply]) # reads OPENAI_API_KEY
from traceloop.sdk.tracing import set_conversation_id
set_conversation_id("session-123") # sets gen_ai.conversation.id on the spans that follow
result = agent.invoke({"messages": [("user", "What is 15 multiplied by 7?")]})
print(result["messages"][-1].content)
OpenLLMetry emits an execute_task span for each LangGraph node. A plain LangChain chain appears as a RunnableSequence.workflow span with execute_task and ChatOpenAI.chat child spans.
LangGraph's thread_id doesn't set the conversation ID with OpenLLMetry. Call set_conversation_id() instead. For more information, see Track conversations.
Additional resources:
LlamaIndex
Traces the LLM calls made by LlamaIndex query engines and agents. Each query appears as an openai.chat span. OpenLLMetry doesn't emit separate retrieval spans; to trace retrieval, use the OpenTelemetry method.
Install:
pip install "traceloop-sdk>=0.62.0" llama-index-core llama-index-llms-openai llama-index-embeddings-openai
Run the following code after the OpenLLMetry setup:
import os
from llama_index.core import Document, Settings, VectorStoreIndex
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
Settings.llm = OpenAI(model="gpt-4o-mini") # reads OPENAI_API_KEY
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
index = VectorStoreIndex.from_documents([
Document(text="Sumo Logic accepts OpenTelemetry traces over OTLP/HTTP."),
Document(text="The AI Observability app reads gen_ai.* span attributes."),
])
print(index.as_query_engine().query("How do I send LLM traces to Sumo Logic?"))
Additional resources:
Haystack
Traces Haystack pipelines and the LLM calls their components make.
Install:
pip install "traceloop-sdk>=0.62.0" "haystack-ai>=2.11,<3"
haystack-ai 3.x isn't supported by the OpenLLMetry Haystack instrumentor.
Run the following code after the OpenLLMetry setup:
import os
from haystack import Pipeline
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
pipeline = Pipeline()
pipeline.add_component("prompt_builder", ChatPromptBuilder())
pipeline.add_component("llm", OpenAIChatGenerator(model="gpt-4o-mini")) # reads OPENAI_API_KEY
pipeline.connect("prompt_builder.prompt", "llm.messages")
result = pipeline.run({"prompt_builder": {
"template": [ChatMessage.from_user("What is {{ a }} multiplied by {{ b }}?")],
"template_variables": {"a": 15, "b": 7},
}})
print(result["llm"]["replies"][0].text)
Additional resources:
OpenAI and AI gateways
Traces calls made with the OpenAI Python SDK, directly or through an OpenAI-compatible gateway. To use a gateway, set base_url to it.
The provider is reported as openai. Use the Gateway/API Base Distribution panel, which reads server.address, to split traffic by gateway.
Related sources:
Install:
pip install "traceloop-sdk>=0.62.0" openai
Run the following code after the OpenLLMetry setup:
import os
from openai import OpenAI
# Pick your gateway's base URL and key:
# Helicone https://gateway.helicone.ai/api/v1 (plus a Helicone-Auth header)
# OpenRouter https://openrouter.ai/api/v1
# Braintrust https://api.braintrust.dev/v1/proxy
client = OpenAI(api_key=os.environ["OPENROUTER_API_KEY"], base_url="https://openrouter.ai/api/v1")
response = client.chat.completions.create(
model="openai/gpt-4o-mini",
messages=[{"role": "user", "content": "What is 15 multiplied by 7?"}],
max_tokens=100,
)
print(response.choices[0].message.content)
For Helicone, also pass the Helicone key and the provider to forward to:
client = OpenAI(
api_key=os.environ["OPENROUTER_API_KEY"],
base_url="https://gateway.helicone.ai/api/v1",
default_headers={
"Helicone-Auth": f"Bearer {os.environ['HELICONE_API_KEY']}",
"Helicone-Target-Url": "https://openrouter.ai",
},
)
Additional resources:
Optional settings
Track conversations
The Conversation Analytics dashboard and the conversation_id filter require gen_ai.conversation.id on each LLM span. Use one ID for every call in the same chat or session. Don't include personal data.
Import set_conversation_id from traceloop.sdk.tracing, then call set_conversation_id("<ID>") before your LLM calls.
Name workflows
With OpenLLMetry, decorate a workflow's entry point with @workflow, so it appears by name in the Agent and Workflow Intelligence dashboard:
from traceloop.sdk.decorators import workflow
@workflow(name="answer_question")
def answer_question(question: str): ...
Capture prompts and responses
Prompts and responses can contain personal data, credentials, or regulated data. Review your data-handling policies before you capture them in production.
Content is the text your application exchanges with the model:
- Prompts and system instructions.
- Model responses.
- Tool call arguments and results.
Only the Prompt and Response Analytics dashboard and the tool input and output panels use content. All other panels work without it.
OpenLLMetry captures content by default. To turn it off, set TRACELOOP_TRACE_CONTENT=false. See OpenLLMetry privacy.
Other providers
If OpenLLMetry doesn't cover your provider, call Traceloop.init() as in Step 1, and then set the gen_ai.* attributes on your own span:
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("chat my-model", kind=trace.SpanKind.CLIENT) as span:
span.set_attribute("gen_ai.operation.name", "chat")
span.set_attribute("gen_ai.provider.name", "my-provider")
span.set_attribute("gen_ai.request.model", "my-model")
response = call_my_model(prompt)
span.set_attribute("gen_ai.usage.input_tokens", response.input_tokens)
span.set_attribute("gen_ai.usage.output_tokens", response.output_tokens)
span.set_attribute("gen_ai.response.finish_reasons", [response.finish_reason])
For every attribute, see GenAI client spans and GenAI agent spans.
Verify data collection
Run your application, send a few requests, and then run this log search in Sumo Logic:
_index=_trace_spans service="<YOUR_SERVICE_NAME>"
Within a few minutes, you should see one row per provider, model, and operation. Then open any AI Observability dashboard and select your service in the service filter.