Skip to content

Commit a478d9e

Browse files
feat(examples): migrate AI examples to OpenTelemetry instrumentation
Switch from PostHog direct SDK wrappers to OpenTelemetry auto-instrumentation for all AI provider examples where OTel instrumentations are available. Uses opentelemetry-instrumentation-openai-v2 for OpenAI-compatible providers, opentelemetry-instrumentation-anthropic for Anthropic, opentelemetry-instrumentation-google-generativeai for Gemini, opentelemetry-instrumentation-langchain for LangChain/LangGraph, opentelemetry-instrumentation-llamaindex for LlamaIndex, and opentelemetry-instrumentation-crewai for CrewAI.
1 parent 7223c52 commit a478d9e

97 files changed

Lines changed: 9358 additions & 3916 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

examples/example-ai-anthropic/chat.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
1-
"""Anthropic chat with tool calling, tracked by PostHog."""
1+
"""Anthropic chat with tool calling, tracked via OpenTelemetry."""
22

33
import os
44
import json
55
import urllib.request
6-
from posthog import Posthog
7-
from posthog.ai.anthropic import Anthropic
6+
from opentelemetry import trace
7+
from opentelemetry.sdk.trace import TracerProvider
8+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
9+
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
10+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
11+
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
812

9-
posthog = Posthog(
10-
os.environ["POSTHOG_API_KEY"],
11-
host=os.environ.get("POSTHOG_HOST", "https://us.i.posthog.com"),
13+
resource = Resource(attributes={SERVICE_NAME: "example-anthropic-app"})
14+
exporter = OTLPSpanExporter(
15+
endpoint=f"{os.environ.get('POSTHOG_HOST', 'https://us.i.posthog.com')}/i/v0/ai/otel",
16+
headers={"Authorization": f"Bearer {os.environ['POSTHOG_API_KEY']}"},
1217
)
13-
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"], posthog_client=posthog)
18+
provider = TracerProvider(resource=resource)
19+
provider.add_span_processor(BatchSpanProcessor(exporter))
20+
trace.set_tracer_provider(provider)
21+
22+
AnthropicInstrumentor().instrument()
23+
24+
import anthropic
25+
26+
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
1427

1528
tools = [
1629
{
@@ -40,7 +53,6 @@ def get_weather(latitude: float, longitude: float, location_name: str) -> str:
4053
message = client.messages.create(
4154
model="claude-sonnet-4-5-20250929",
4255
max_tokens=1024,
43-
posthog_distinct_id="example-user",
4456
tools=tools,
4557
messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
4658
)
@@ -54,4 +66,4 @@ def get_weather(latitude: float, longitude: float, location_name: str) -> str:
5466
result = get_weather(**block.input)
5567
print(result)
5668

57-
posthog.shutdown()
69+
provider.shutdown()
Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
1-
"""Anthropic extended thinking, tracked by PostHog.
1+
"""Anthropic extended thinking, tracked via OpenTelemetry.
22
33
Extended thinking lets Claude show its reasoning process before responding.
44
"""
55

66
import os
7-
from posthog import Posthog
8-
from posthog.ai.anthropic import Anthropic
7+
from opentelemetry import trace
8+
from opentelemetry.sdk.trace import TracerProvider
9+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
10+
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
11+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
12+
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
913

10-
posthog = Posthog(
11-
os.environ["POSTHOG_API_KEY"],
12-
host=os.environ.get("POSTHOG_HOST", "https://us.i.posthog.com"),
14+
resource = Resource(attributes={SERVICE_NAME: "example-anthropic-app"})
15+
exporter = OTLPSpanExporter(
16+
endpoint=f"{os.environ.get('POSTHOG_HOST', 'https://us.i.posthog.com')}/i/v0/ai/otel",
17+
headers={"Authorization": f"Bearer {os.environ['POSTHOG_API_KEY']}"},
1318
)
14-
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"], posthog_client=posthog)
19+
provider = TracerProvider(resource=resource)
20+
provider.add_span_processor(BatchSpanProcessor(exporter))
21+
trace.set_tracer_provider(provider)
22+
23+
AnthropicInstrumentor().instrument()
24+
25+
import anthropic
26+
27+
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
1528

1629
message = client.messages.create(
1730
model="claude-sonnet-4-5-20250929",
1831
max_tokens=16000,
19-
posthog_distinct_id="example-user",
2032
thinking={"type": "enabled", "budget_tokens": 10000},
2133
messages=[
2234
{
@@ -32,4 +44,4 @@
3244
elif block.type == "text":
3345
print(f"Answer: {block.text}")
3446

35-
posthog.shutdown()
47+
provider.shutdown()

examples/example-ai-anthropic/pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ name = "example-ai-anthropic"
33
version = "0.1.0"
44
requires-python = ">=3.10"
55
dependencies = [
6-
"posthog==7.9.12",
7-
"anthropic==0.86.0",
6+
"anthropic>=0.80.0",
7+
"opentelemetry-instrumentation-anthropic>=0.24.0",
8+
"opentelemetry-sdk>=1.30.0",
9+
"opentelemetry-exporter-otlp-proto-http>=1.30.0",
810
]
Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
1-
"""Anthropic streaming chat, tracked by PostHog."""
1+
"""Anthropic streaming chat, tracked via OpenTelemetry."""
22

33
import os
4-
from posthog import Posthog
5-
from posthog.ai.anthropic import Anthropic
4+
from opentelemetry import trace
5+
from opentelemetry.sdk.trace import TracerProvider
6+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
7+
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
8+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
9+
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
610

7-
posthog = Posthog(
8-
os.environ["POSTHOG_API_KEY"],
9-
host=os.environ.get("POSTHOG_HOST", "https://us.i.posthog.com"),
11+
resource = Resource(attributes={SERVICE_NAME: "example-anthropic-app"})
12+
exporter = OTLPSpanExporter(
13+
endpoint=f"{os.environ.get('POSTHOG_HOST', 'https://us.i.posthog.com')}/i/v0/ai/otel",
14+
headers={"Authorization": f"Bearer {os.environ['POSTHOG_API_KEY']}"},
1015
)
11-
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"], posthog_client=posthog)
16+
provider = TracerProvider(resource=resource)
17+
provider.add_span_processor(BatchSpanProcessor(exporter))
18+
trace.set_tracer_provider(provider)
19+
20+
AnthropicInstrumentor().instrument()
21+
22+
import anthropic
23+
24+
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
1225

1326
stream = client.messages.create(
1427
model="claude-sonnet-4-5-20250929",
1528
max_tokens=1024,
16-
posthog_distinct_id="example-user",
1729
messages=[{"role": "user", "content": "Write a haiku about observability."}],
1830
stream=True,
1931
)
@@ -24,4 +36,4 @@
2436
print(event.delta.text, end="", flush=True)
2537

2638
print()
27-
posthog.shutdown()
39+
provider.shutdown()

0 commit comments

Comments
 (0)