Skip to content

Commit ee463c6

Browse files
maheshbabugorantlaMahesh Babu Gorantla
andauthored
docs(integration): Add Elasticsearch APM Integration guide (#126)
Co-authored-by: Mahesh Babu Gorantla <mahesh@projexel.vet>
1 parent 0548818 commit ee463c6

File tree

5 files changed

+293
-0
lines changed

5 files changed

+293
-0
lines changed
250 KB
Loading
243 KB
Loading

mint.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
"openllmetry/integrations/dash0",
115115
"openllmetry/integrations/datadog",
116116
"openllmetry/integrations/dynatrace",
117+
"openllmetry/integrations/elasticsearch-apm",
117118
"openllmetry/integrations/gcp",
118119
"openllmetry/integrations/grafana",
119120
"openllmetry/integrations/highlight",
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
---
2+
title: "LLM Observability with Elasticsearch APM Service"
3+
sidebarTitle: "Elasticsearch APM"
4+
---
5+
6+
Connect OpenLLMetry to [Elastic APM](https://www.elastic.co/guide/en/apm/guide/current/index.html) to visualize LLM traces in Kibana's native APM interface. This integration uses OpenTelemetry Protocol (OTLP) to route traces from your application through an OpenTelemetry Collector to Elastic APM Server.
7+
8+
<Note>
9+
This integration requires an OpenTelemetry Collector to route traces between Traceloop OpenLLMetry client and Elastic APM Server.
10+
Elastic APM Server 8.x+ supports OTLP natively.
11+
</Note>
12+
13+
## Quick Start
14+
15+
<Steps>
16+
<Step title="Install OpenLLMetry">
17+
Install the Traceloop SDK alongside your LLM provider client:
18+
19+
```bash
20+
pip install traceloop-sdk openai
21+
```
22+
</Step>
23+
24+
<Step title="Configure OpenTelemetry Collector">
25+
Configure your OpenTelemetry Collector to receive traces from OpenLLMetry and forward them to APM Server.
26+
27+
Create an `otel-collector-config.yaml` file:
28+
29+
```yaml
30+
receivers:
31+
otlp:
32+
protocols:
33+
http:
34+
endpoint: localhost:4318
35+
grpc:
36+
endpoint: localhost:4317
37+
38+
processors:
39+
batch:
40+
timeout: 10s
41+
send_batch_size: 1024
42+
43+
memory_limiter:
44+
check_interval: 1s
45+
limit_mib: 512
46+
47+
resource:
48+
attributes:
49+
- key: service.name
50+
action: upsert
51+
value: your-service-name # Match this to app_name parameter value when calling Traceloop.init()
52+
53+
exporters:
54+
# Export to APM Server via OTLP
55+
otlp/apm:
56+
endpoint: http://localhost:8200 # APM Server Endpoint
57+
tls:
58+
insecure: true # Allow insecure connection from OTEL Collector to APM Server (for demo purposes)
59+
compression: gzip
60+
61+
# Logging exporter for debugging (can ignore if not needed)
62+
logging:
63+
verbosity: normal # This is the verbosity of the logging
64+
sampling_initial: 5
65+
sampling_thereafter: 200
66+
67+
# Debug exporter to verify trace data
68+
debug:
69+
verbosity: detailed
70+
sampling_initial: 10
71+
sampling_thereafter: 10
72+
73+
extensions:
74+
health_check:
75+
endpoint: localhost:13133 # Endpoint of OpenTelemetry Collector's health check extension
76+
77+
service:
78+
extensions: [health_check] # Enable health check extension
79+
80+
pipelines:
81+
traces:
82+
receivers: [otlp]
83+
processors: [memory_limiter, batch, resource]
84+
exporters: [otlp/apm, logging, debug]
85+
86+
metrics:
87+
receivers: [otlp]
88+
processors: [memory_limiter, batch, resource]
89+
exporters: [otlp/apm, logging]
90+
91+
logs:
92+
receivers: [otlp]
93+
processors: [memory_limiter, batch, resource]
94+
exporters: [otlp/apm, logging]
95+
```
96+
97+
<Warning>
98+
In production, enable TLS and use APM Server secret tokens for authentication.
99+
Set `tls.insecure: false` and configure `headers: Authorization: Bearer <token>`.
100+
</Warning>
101+
</Step>
102+
103+
<Step title="Initialize Traceloop">
104+
Import and initialize Traceloop before any LLM imports:
105+
106+
```python
107+
from os import getenv
108+
109+
from traceloop.sdk import Traceloop
110+
from openai import OpenAI
111+
112+
# Initialize Traceloop with OTLP endpoint
113+
Traceloop.init(
114+
app_name="your-service-name",
115+
api_endpoint="http://localhost:4318"
116+
)
117+
118+
# Traceloop must be initialized before importing the LLM client
119+
# Traceloop instruments the OpenAI client automatically
120+
client = OpenAI(api_key=getenv("OPENAI_API_KEY"))
121+
122+
# Make LLM calls - automatically traced
123+
response = client.chat.completions.create(
124+
model="gpt-4o-mini",
125+
messages=[{"role": "user", "content": "Hello!"}]
126+
)
127+
```
128+
129+
<Note>
130+
The `app_name` parameter sets the service name visible in Kibana APM's service list.
131+
</Note>
132+
</Step>
133+
134+
<Step title="View Traces in Kibana">
135+
Navigate to Kibana's APM interface:
136+
137+
1. Open Kibana at `http://localhost:5601`
138+
2. Go to **Observability → APM → Services**
139+
3. Click on your service name (e.g., `your-service-name`)
140+
4. View transactions and trace timelines with full LLM metadata
141+
142+
Each LLM call appears as a span containing:
143+
- Model name (`gen_ai.request.model`)
144+
- Token usage (`gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`)
145+
- Prompts and completions (configurable)
146+
- Request duration and latency
147+
</Step>
148+
</Steps>
149+
150+
## Environment Variables
151+
152+
Configure OpenLLMetry behavior using environment variables:
153+
154+
| Variable | Description | Default |
155+
|----------|-------------|---------|
156+
| `TRACELOOP_BASE_URL` | OpenTelemetry Collector endpoint | `http://localhost:4318` |
157+
| `TRACELOOP_TRACE_CONTENT` | Capture prompts/completions | `true` |
158+
159+
160+
<Warning>
161+
Set `TRACELOOP_TRACE_CONTENT=false` in production to prevent logging sensitive prompt content.
162+
</Warning>
163+
164+
## Using Workflow Decorators
165+
166+
For complex applications with multiple steps, use workflow decorators to create hierarchical traces:
167+
168+
```python
169+
from os import getenv
170+
from traceloop.sdk import Traceloop
171+
from traceloop.sdk.decorators import workflow, task
172+
from openai import OpenAI
173+
174+
Traceloop.init(
175+
app_name="recipe-service",
176+
api_endpoint="http://localhost:4318",
177+
)
178+
179+
# Traceloop must be initialized before importing the LLM client
180+
# Traceloop instruments the OpenAI client automatically
181+
client = OpenAI(api_key=getenv("OPENAI_API_KEY"))
182+
183+
@task(name="generate_recipe")
184+
def generate_recipe(dish: str):
185+
"""LLM call - creates a child span"""
186+
response = client.chat.completions.create(
187+
model="gpt-4o-mini",
188+
messages=[
189+
{"role": "system", "content": "You are a chef."},
190+
{"role": "user", "content": f"Recipe for {dish}"}
191+
]
192+
)
193+
return response.choices[0].message.content
194+
195+
196+
@workflow(name="recipe_workflow")
197+
def create_recipe(dish: str, servings: int):
198+
"""Parent workflow - creates the root transaction"""
199+
recipe = generate_recipe(dish)
200+
return {"recipe": recipe, "servings": servings}
201+
202+
# Call the workflow
203+
result = create_recipe("pasta carbonara", 4)
204+
```
205+
206+
In Kibana APM, you'll see:
207+
- `recipe_workflow.workflow` as the parent transaction
208+
- `generate_recipe.task` as a child span
209+
- `openai.chat.completions` as the LLM API span with full metadata
210+
211+
212+
## Example Trace Visualization
213+
214+
### Trace View
215+
216+
<Frame>
217+
<img src="/img/integrations/elasticsearch-apm.png" />
218+
</Frame>
219+
220+
### Trace Details
221+
222+
<Frame>
223+
<img src="/img/integrations/elasticsearch-apm-trace-details.png" />
224+
</Frame>
225+
226+
## Captured Metadata
227+
228+
OpenLLMetry automatically captures these attributes in each LLM span:
229+
230+
**Request Attributes:**
231+
- `gen_ai.request.model` - Model identifier
232+
- `gen_ai.request.temperature` - Sampling temperature
233+
- `gen_ai.system` - Provider name (OpenAI, Anthropic, etc.)
234+
235+
**Response Attributes:**
236+
- `gen_ai.response.model` - Actual model used
237+
- `gen_ai.response.id` - Unique response identifier
238+
- `gen_ai.response.finish_reason` - Completion reason
239+
240+
**Token Usage:**
241+
- `gen_ai.usage.input_tokens` - Input token count
242+
- `gen_ai.usage.output_tokens` - Output token count
243+
- `llm.usage.total_tokens` - Total tokens
244+
245+
**Content (if enabled):**
246+
- `gen_ai.prompt.{N}.content` - Prompt messages
247+
- `gen_ai.completion.{N}.content` - Generated completions
248+
249+
## Production Considerations
250+
251+
<Tabs>
252+
<Tab title="Content Logging">
253+
Disable prompt/completion logging in production:
254+
255+
```bash
256+
export TRACELOOP_TRACE_CONTENT=false
257+
```
258+
259+
This prevents sensitive data from being stored in Elasticsearch.
260+
</Tab>
261+
262+
<Tab title="Sampling">
263+
Configure sampling in the OpenTelemetry Collector to reduce trace volume:
264+
265+
```yaml
266+
processors:
267+
probabilistic_sampler:
268+
sampling_percentage: 10 # Sample 10% of traces
269+
```
270+
</Tab>
271+
272+
<Tab title="Security">
273+
Enable APM Server authentication:
274+
275+
```yaml
276+
exporters:
277+
otlp/apm:
278+
endpoint: https://localhost:8200
279+
headers:
280+
Authorization: "Bearer <secret-token>"
281+
tls:
282+
insecure: false
283+
```
284+
</Tab>
285+
</Tabs>
286+
287+
## Resources
288+
289+
- [Elastic APM Documentation](https://www.elastic.co/docs/solutions/observability/apm)
290+
- [OpenTelemetry Collector Configuration](https://opentelemetry.io/docs/collector/configuration/)
291+
- [Traceloop SDK Configuration](https://www.traceloop.com/docs/openllmetry/configuration)

openllmetry/integrations/introduction.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ in any observability platform that supports OpenTelemetry.
2020
<Card title="Dash0" href="/openllmetry/integrations/dash0"></Card>
2121
<Card title="Datadog" href="/openllmetry/integrations/datadog"></Card>
2222
<Card title="Dynatrace" href="/openllmetry/integrations/dynatrace"></Card>
23+
<Card title="Elasticsearch APM" href="/openllmetry/integrations/elasticsearch-apm"></Card>
2324
<Card title="Google Cloud" href="/openllmetry/integrations/gcp"></Card>
2425
<Card title="Grafana Tempo" href="/openllmetry/integrations/grafana"></Card>
2526
<Card title="Highlight" href="/openllmetry/integrations/highlight"></Card>

0 commit comments

Comments
 (0)