Skip to content

Commit edf174b

Browse files
committed
POC OtlpIntegration
1 parent 3e86962 commit edf174b

File tree

4 files changed

+99
-1
lines changed

4 files changed

+99
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pip-wheel-metadata
2929
.mypy_cache
3030
.vscode/
3131
.claude/
32+
.tool-versions
3233

3334
# for running AWS Lambda tests using AWS SAM
3435
sam.template.yaml

sentry_sdk/integrations/otlp.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
from sentry_sdk.integrations import Integration, DidNotEnable
2+
from sentry_sdk.scope import add_global_event_processor
3+
from sentry_sdk.utils import logger
4+
5+
try:
6+
from opentelemetry import trace
7+
from opentelemetry.propagate import set_global_textmap
8+
from opentelemetry.sdk.trace import TracerProvider
9+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
10+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
11+
12+
from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator
13+
except ImportError:
14+
raise DidNotEnable("opentelemetry-distro[otlp] is not installed")
15+
16+
from typing import TYPE_CHECKING
17+
18+
if TYPE_CHECKING:
19+
from typing import Optional
20+
from sentry_sdk._types import Event, Hint
21+
22+
23+
def link_event_to_trace(event, _hint):
24+
# type: (Event, Optional[Hint]) -> Optional[Event]
25+
"""
26+
Get the trace info from the running otel span and
27+
update the trace context on sentry events of other types
28+
(errors, logs, checkins, etc).
29+
"""
30+
if hasattr(event, "type") and event["type"] == "transaction":
31+
return event
32+
33+
otel_span = trace.get_current_span()
34+
if not otel_span:
35+
return event
36+
37+
ctx = otel_span.get_span_context()
38+
39+
if ctx.trace_id == trace.INVALID_TRACE_ID or ctx.span_id == trace.INVALID_SPAN_ID:
40+
return event
41+
42+
contexts = event.setdefault("contexts", {})
43+
contexts.setdefault("trace", {}).update(
44+
{
45+
"trace_id": trace.format_trace_id(ctx.trace_id),
46+
"span_id": trace.format_span_id(ctx.span_id),
47+
"status": "ok", # TODO
48+
}
49+
)
50+
51+
return event
52+
53+
54+
def setup_otlp_exporter():
55+
# type: () -> None
56+
tracer_provider = trace.get_tracer_provider()
57+
58+
if not isinstance(tracer_provider, TracerProvider):
59+
logger.debug("[OTLP] No TracerProvider configured by user, creating a new one")
60+
tracer_provider = TracerProvider()
61+
trace.set_tracer_provider(tracer_provider)
62+
63+
otlp_exporter = OTLPSpanExporter()
64+
span_processor = BatchSpanProcessor(otlp_exporter)
65+
tracer_provider.add_span_processor(span_processor)
66+
67+
68+
class OtlpIntegration(Integration):
69+
identifier = "otlp"
70+
setup_otlp_exporter = True
71+
setup_propagator = True
72+
73+
def __init__(self, setup_otlp_exporter=True, setup_propagator=True):
74+
# type: (bool, bool) -> None
75+
OtlpIntegration.setup_otlp_exporter = setup_otlp_exporter
76+
OtlpIntegration.setup_propagator = setup_propagator
77+
78+
@staticmethod
79+
def setup_once():
80+
# type: () -> None
81+
logger.debug("[OTLP] Setting up trace linking for all events")
82+
add_global_event_processor(link_event_to_trace)
83+
84+
if OtlpIntegration.setup_otlp_exporter:
85+
logger.debug("[OTLP] Setting up OTLP exporter")
86+
setup_otlp_exporter()
87+
88+
if OtlpIntegration.setup_propagator:
89+
logger.debug("[OTLP] Setting up propagator for distributed tracing")
90+
set_global_textmap(SentryPropagator())

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def get_file_text(file_name):
7272
"openai": ["openai>=1.0.0", "tiktoken>=0.3.0"],
7373
"openfeature": ["openfeature-sdk>=0.7.1"],
7474
"opentelemetry": ["opentelemetry-distro>=0.35b0"],
75-
"opentelemetry-experimental": ["opentelemetry-distro"],
75+
"opentelemetry-otlp": ["opentelemetry-distro[otlp]>=0.35b0"],
7676
"pure-eval": ["pure_eval", "executing", "asttokens"],
7777
"pydantic_ai": ["pydantic-ai>=1.0.0"],
7878
"pymongo": ["pymongo>=3.1"],

tox.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ envlist =
4040
# OpenTelemetry (OTel)
4141
{py3.7,py3.9,py3.12,py3.13,py3.14,py3.14t}-opentelemetry
4242

43+
# OpenTelemetry with OTLP
44+
{py3.7,py3.9,py3.12,py3.13,py3.14,py3.14t}-otlp
45+
4346
# OpenTelemetry Experimental (POTel)
4447
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel
4548

@@ -342,6 +345,9 @@ deps =
342345
# OpenTelemetry (OTel)
343346
opentelemetry: opentelemetry-distro
344347

348+
# OpenTelemetry with OTLP
349+
otlp: opentelemetry-distro[otlp]
350+
345351
# OpenTelemetry Experimental (POTel)
346352
potel: -e .[opentelemetry-experimental]
347353

@@ -765,6 +771,7 @@ setenv =
765771
cloud_resource_context: TESTPATH=tests/integrations/cloud_resource_context
766772
gcp: TESTPATH=tests/integrations/gcp
767773
opentelemetry: TESTPATH=tests/integrations/opentelemetry
774+
otlp: TESTPATH=tests/integrations/otlp
768775
potel: TESTPATH=tests/integrations/opentelemetry
769776
socket: TESTPATH=tests/integrations/socket
770777

0 commit comments

Comments
 (0)