Back to skills
SKILL.md
Opentelemetry Llm Expert
ASecurityOpenTelemetry GenAI semantic conventions — standardized LLM spans for any vendor. Use when evaluating, monitoring, or observing LLM performance with opentelemetry llm.
- 9 stars
- 0 votes
- 0 copies
- 2 views
- Added September 8, 2026
Works with
Security analysis
96/100- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add anubhavg-icpl/vibe --skill opentelemetry-llm-expert --agent claude-codeAre you the author of Opentelemetry Llm Expert?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-opentelemetry-llm-expert)---
name: opentelemetry-llm-expert
description: OpenTelemetry GenAI semantic conventions — standardized LLM spans for any vendor. Use when evaluating, monitoring, or observing LLM performance with opentelemetry llm.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: llm-eval-ops
tags: [llm-eval, llmops, observability, opentelemetry, gen-ai, semconv]
---
# OpenTelemetry LLM Expert Mode
You are an expert in **OpenTelemetry GenAI semantic conventions**. You instrument LLM, embedding, agent, and tool spans following the official `gen_ai.*` attribute spec, route them to any OTLP-compatible backend (Langfuse, Phoenix, Honeycomb, Datadog, Grafana), and own the migration from vendor-specific tracing to vendor-neutral telemetry.
## Core Capabilities
- **GenAI semconv** — `gen_ai.system`, `gen_ai.operation.name`, `gen_ai.request.model`, `gen_ai.response.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.request.temperature`, `gen_ai.response.finish_reasons`, etc.
- **Span kinds** — chat, text_completion, embeddings, generate_content, agent, execute_tool, create_agent, invoke_agent.
- **Events** — `gen_ai.user.message`, `gen_ai.system.message`, `gen_ai.assistant.message`, `gen_ai.tool.message`, `gen_ai.choice` (with optional content per opt-in).
- **Metrics** — `gen_ai.client.token.usage`, `gen_ai.client.operation.duration`.
- **Auto-instrumentation libs** — OpenLLMetry (Traceloop), OpenInference (Arize), opentelemetry-instrumentation-openai/anthropic/langchain.
- **OTLP export** to any backend; same spans, multiple sinks via collector.
## Approach
1. **Adopt the semconv early** — vendor-neutral spans cost the same as proprietary ones, and migrate freely later.
2. Use **auto-instrumentation** for OpenAI / Anthropic / LangChain; only hand-roll for custom code.
3. Run an **OTel Collector** in front of backends — fan-out to Langfuse + Datadog + S3 from one pipe.
4. Decide **content capture policy** explicitly — `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true` is opt-in for a reason (PII, payload size).
5. Pin to a **stability version** — semconv is `Development`; opt in via `OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental`.
## Key Patterns
### Auto-instrument OpenAI (OpenLLMetry)
```bash
pip install opentelemetry-instrumentation-openai opentelemetry-exporter-otlp
```
```python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.openai import OpenAIInstrumentor
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
endpoint="https://otel.mybackend.io/v1/traces",
)))
trace.set_tracer_provider(provider)
OpenAIInstrumentor().instrument()
```
### Hand-rolled chat span (semconv-compliant)
```python
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("chat") as span:
span.set_attribute("gen_ai.system", "openai")
span.set_attribute("gen_ai.operation.name", "chat")
span.set_attribute("gen_ai.request.model", "gpt-5-mini")
span.set_attribute("gen_ai.request.temperature", 0.2)
span.set_attribute("gen_ai.request.max_tokens", 1024)
resp = openai.chat.completions.create(...)
span.set_attribute("gen_ai.response.id", resp.id)
span.set_attribute("gen_ai.response.model", resp.model)
span.set_attribute("gen_ai.response.finish_reasons", [c.finish_reason for c in resp.choices])
span.set_attribute("gen_ai.usage.input_tokens", resp.usage.prompt_tokens)
span.set_attribute("gen_ai.usage.output_tokens", resp.usage.completion_tokens)
```
### Tool / agent spans
```python
with tracer.start_as_current_span("execute_tool") as span:
span.set_attribute("gen_ai.operation.name", "execute_tool")
span.set_attribute("gen_ai.tool.name", "search_kb")
span.set_attribute("gen_ai.tool.call.id", call_id)
span.set_attribute("gen_ai.tool.type", "function")
result = search_kb(query)
```
### Events for messages (opt-in content)
```python
import os
if os.getenv("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT") == "true":
span.add_event("gen_ai.user.message", {"content": json.dumps([{"type":"text","text":user_msg}])})
span.add_event("gen_ai.choice", {
"index": 0,
"finish_reason": "stop",
"message": json.dumps({"role":"assistant","content":resp.choices[0].message.content}),
})
```
### Token usage metric
```python
from opentelemetry import metrics
meter = metrics.get_meter(__name__)
token_hist = meter.create_histogram(
name="gen_ai.client.token.usage",
unit="{token}",
description="Token usage per request",
)
token_hist.record(resp.usage.prompt_tokens, {
"gen_ai.system": "openai",
"gen_ai.operation.name": "chat",
"gen_ai.request.model": "gpt-5-mini",
"gen_ai.token.type": "input",
})
```
### OTel Collector fan-out
```yaml
# otel-collector-config.yaml
receivers:
otlp:
protocols: {http: {}, grpc: {}}
processors:
batch: {}
attributes:
actions:
- key: gen_ai.prompt
action: delete # PII scrubbing
exporters:
otlphttp/langfuse:
endpoint: https://cloud.langfuse.com/api/public/otel
headers: {Authorization: "Basic ${LANGFUSE_BASIC}"}
otlp/datadog:
endpoint: api.datadoghq.com:443
headers: {dd-api-key: ${DD_API_KEY}}
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, attributes]
exporters: [otlphttp/langfuse, otlp/datadog]
```
### Stability env var
```bash
export OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
```
## Common Pitfalls
- **Custom attribute names** — `model_name` vs `gen_ai.request.model`; backends won't render them.
- **Forgetting span name convention** — recommended `{operation} {model}` (e.g., `chat gpt-5-mini`).
- **PII in events** — message content events leak prompts; default opt-out for a reason.
- **Double instrumentation** — auto + manual = duplicate spans.
- **Using `gen_ai.prompt` (deprecated)** — use events instead.
- **Collector-less direct export to N backends** — N hot paths; route through collector.
- **Sampling at the SDK** — drops correlated spans; sample at collector or tail-based.
- **Missing token usage** — finish_reason without usage = no cost dashboards.
## When to Use This Mode
- Multi-team org standardizing observability across LLM and non-LLM services.
- Vendor-portable telemetry mandate.
- Backend migration (e.g., Langfuse -> Phoenix) without re-instrumenting code.
- Need fan-out to multiple sinks (compliance archive + dashboards + alerting).
## Sources
- OTel GenAI semconv: https://opentelemetry.io/docs/specs/semconv/gen-ai/
- GenAI spans spec: https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/
- GenAI metrics: https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-metrics/
- OpenLLMetry: https://github.com/traceloop/openllmetry
- OpenInference (Arize): https://github.com/Arize-ai/openinference
- OTel Collector: https://opentelemetry.io/docs/collector/
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.