Skip to content

Commit c5e7a8d

Browse files
ZStriker19cswatt
andauthored
llmobs: add custom instrumentation otel example (#32781)
* add custom section, not that we do not support openllmetry or openinference currently * Yun comments * edits --------- Co-authored-by: cecilia saixue watt <[email protected]>
1 parent 81b49cd commit c5e7a8d

File tree

1 file changed

+103
-3
lines changed

1 file changed

+103
-3
lines changed

content/en/llm_observability/instrumentation/otel_instrumentation.md

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,15 @@ To generate traces compatible with LLM Observability, do one of the following:
6464

6565
After your application starts sending data, the traces automatically appear in the [**LLM Observability Traces** page][3]. To search for your traces in the UI, use the `ml_app` attribute, which is automatically set to the value of your OpenTelemetry root span's `service` attribute.
6666

67-
**Note**: There may be a 3-5 minute delay between sending traces and seeing them appear on the LLM Observability Traces page.
67+
<div class="alert alert-danger">OpenInference and OpenLLMetry are not supported, as they have not been updated to support OpenTelemetry 1.37 semantic conventions for generative AI.</a></div>
6868

69-
### Example
69+
**Note**: There may be a 3-5 minute delay between sending traces and seeing them appear on the LLM Observability Traces page. If you have APM enabled, traces appear immediately in the APM Traces page.
7070

71-
The following example demonstrates a complete application using strands-agents with the OpenTelemetry integration. This same approach works with any framework that supports OpenTelemetry version 1.37 semantic conventions for generative AI, or with custom instrumentation that emits the required `gen_ai.*` attributes.
71+
### Examples
72+
73+
#### Using strands-agents
74+
75+
The following example demonstrates a complete application using strands-agents with the OpenTelemetry integration. This same approach works with any framework that supports OpenTelemetry version 1.37 semantic conventions for generative AI.
7276

7377
```python
7478
from strands import Agent
@@ -101,6 +105,102 @@ if __name__ == "__main__":
101105
print(f"Agent: {result}")
102106
```
103107

108+
#### Custom OpenTelemetry instrumentation
109+
110+
The following example demonstrates how to instrument your LLM application using custom OpenTelemetry code. This approach gives you full control over the traces and spans emitted by your application.
111+
112+
```python
113+
import os
114+
import json
115+
from opentelemetry import trace
116+
from opentelemetry.sdk.trace import TracerProvider
117+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
118+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
119+
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
120+
from openai import OpenAI
121+
122+
# Configure OpenTelemetry to send traces to Datadog
123+
os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = "{{< region-param key="otlp_trace_endpoint" code="true" >}}"
124+
os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = "dd-api-key=<YOUR_DATADOG_API_KEY>,dd-otlp-source=datadog"
125+
os.environ["OTEL_SEMCONV_STABILITY_OPT_IN"] = "gen_ai_latest_experimental"
126+
127+
# Initialize OpenTelemetry SDK
128+
resource = Resource(attributes={SERVICE_NAME: "simple-llm-example"})
129+
provider = TracerProvider(resource=resource)
130+
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
131+
trace.set_tracer_provider(provider)
132+
133+
tracer = trace.get_tracer(__name__)
134+
135+
# Make LLM call with OpenTelemetry tracing
136+
with tracer.start_as_current_span(
137+
"chat gpt-4o",
138+
kind=trace.SpanKind.CLIENT,
139+
) as span:
140+
model = "gpt-4o"
141+
max_tokens = 1024
142+
temperature = 0.7
143+
messages = [{"role": "user", "content": "Explain OpenTelemetry in one sentence."}]
144+
145+
# Set request attributes
146+
span.set_attribute("gen_ai.provider.name", "openai")
147+
span.set_attribute("gen_ai.request.model", model)
148+
span.set_attribute("gen_ai.operation.name", "chat")
149+
span.set_attribute("gen_ai.request.max_tokens", max_tokens)
150+
span.set_attribute("gen_ai.request.temperature", temperature)
151+
152+
# Add input messages as event
153+
input_messages_parts = []
154+
for msg in messages:
155+
input_messages_parts.append({
156+
"role": msg["role"],
157+
"parts": [{"type": "text", "content": msg["content"]}]
158+
})
159+
160+
span.add_event(
161+
"gen_ai.client.inference.operation.details",
162+
{
163+
"gen_ai.input.messages": json.dumps(input_messages_parts)
164+
}
165+
)
166+
167+
# Make actual LLM call
168+
client = OpenAI(api_key="<YOUR_OPENAI_API_KEY>")
169+
response = client.chat.completions.create(
170+
model=model,
171+
max_tokens=max_tokens,
172+
temperature=temperature,
173+
messages=messages
174+
)
175+
176+
# Set response attributes from actual data
177+
span.set_attribute("gen_ai.response.id", response.id)
178+
span.set_attribute("gen_ai.response.model", response.model)
179+
span.set_attribute("gen_ai.response.finish_reasons", [response.choices[0].finish_reason])
180+
span.set_attribute("gen_ai.usage.input_tokens", response.usage.prompt_tokens)
181+
span.set_attribute("gen_ai.usage.output_tokens", response.usage.completion_tokens)
182+
183+
# Add output messages as event
184+
output_text = response.choices[0].message.content
185+
span.add_event(
186+
"gen_ai.client.inference.operation.details",
187+
{
188+
"gen_ai.output.messages": json.dumps([{
189+
"role": "assistant",
190+
"parts": [{"type": "text", "content": output_text}],
191+
"finish_reason": response.choices[0].finish_reason
192+
}])
193+
}
194+
)
195+
196+
print(f"Response: {output_text}")
197+
198+
# Flush spans before exit
199+
provider.force_flush()
200+
```
201+
202+
After running this example, search for `ml_app:simple-llm-example` in the LLM Observability UI to find the generated trace.
203+
104204
## Supported semantic conventions
105205

106206
LLM Observability supports spans that follow the OpenTelemetry 1.37 semantic conventions for generative AI, including:

0 commit comments

Comments
 (0)