Skip to content

Commit 1f6816e

Browse files
Handle None span context in the span processor and pin tokenizers version for anthropic tests on Python 3.8 (#5967)
Exit early if there is no span context to create a Sentry span from.
1 parent eaacc97 commit 1f6816e

4 files changed

Lines changed: 40 additions & 20 deletions

File tree

scripts/populate_tox/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"deps": {
1919
"*": ["pytest-asyncio"],
2020
"<0.50": ["httpx<0.28.0"],
21+
# tokenizers dropped Python 3.8 support, but didn't update package metadata.
22+
# https://github.com/huggingface/tokenizers/commit/f4c9fd7f402fc794df8f1b547a95ee5305f9fe62
23+
"py3.8": ["tokenizers<0.20.4"],
2124
},
2225
"python": ">=3.8",
2326
},

sentry_sdk/integrations/opentelemetry/span_processor.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
if TYPE_CHECKING:
3535
from typing import Any, Optional, Union
3636
from opentelemetry import context as context_api
37+
from opentelemetry.trace import SpanContext
3738
from sentry_sdk._types import Event, Hint
3839

3940
OPEN_TELEMETRY_CONTEXT = "otel"
@@ -124,13 +125,16 @@ def on_start(
124125
if client.options["instrumenter"] != INSTRUMENTER.OTEL:
125126
return
126127

127-
if not otel_span.get_span_context().is_valid:
128+
span_context = otel_span.get_span_context()
129+
if span_context is None or not span_context.is_valid:
128130
return
129131

130132
if self._is_sentry_span(otel_span):
131133
return
132134

133-
trace_data = self._get_trace_data(otel_span, parent_context)
135+
trace_data = self._get_trace_data(
136+
span_context, otel_span.parent, parent_context
137+
)
134138

135139
parent_span_id = trace_data["parent_span_id"]
136140
sentry_parent_span = (
@@ -183,7 +187,7 @@ def on_end(self, otel_span: "OTelSpan") -> None:
183187
return
184188

185189
span_context = otel_span.get_span_context()
186-
if not span_context.is_valid:
190+
if span_context is None or not span_context.is_valid:
187191
return
188192

189193
span_id = format_span_id(span_context.span_id)
@@ -255,13 +259,15 @@ def _get_otel_context(self, otel_span: "OTelSpan") -> "dict[str, Any]":
255259
return ctx
256260

257261
def _get_trace_data(
258-
self, otel_span: "OTelSpan", parent_context: "Optional[context_api.Context]"
262+
self,
263+
span_context: "SpanContext",
264+
parent_span_context: "Optional[SpanContext]",
265+
parent_context: "Optional[context_api.Context]",
259266
) -> "dict[str, Any]":
260267
"""
261-
Extracts tracing information from one OTel span and its parent OTel context.
268+
Extracts tracing information from one OTel span's context and its parent OTel context.
262269
"""
263270
trace_data: "dict[str, Any]" = {}
264-
span_context = otel_span.get_span_context()
265271

266272
span_id = format_span_id(span_context.span_id)
267273
trace_data["span_id"] = span_id
@@ -270,7 +276,7 @@ def _get_trace_data(
270276
trace_data["trace_id"] = trace_id
271277

272278
parent_span_id = (
273-
format_span_id(otel_span.parent.span_id) if otel_span.parent else None
279+
format_span_id(parent_span_context.span_id) if parent_span_context else None
274280
)
275281
trace_data["parent_span_id"] = parent_span_id
276282

tests/integrations/opentelemetry/test_span_processor.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ def test_get_trace_data_with_span_and_trace():
6868
parent_context = {}
6969

7070
span_processor = SentrySpanProcessor()
71-
sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context)
71+
sentry_trace_data = span_processor._get_trace_data(
72+
otel_span.get_span_context(), otel_span.parent, parent_context
73+
)
7274
assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef"
7375
assert sentry_trace_data["span_id"] == "1234567890abcdef"
7476
assert sentry_trace_data["parent_span_id"] is None
@@ -90,7 +92,9 @@ def test_get_trace_data_with_span_and_trace_and_parent():
9092
parent_context = {}
9193

9294
span_processor = SentrySpanProcessor()
93-
sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context)
95+
sentry_trace_data = span_processor._get_trace_data(
96+
otel_span.get_span_context(), otel_span.parent, parent_context
97+
)
9498
assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef"
9599
assert sentry_trace_data["span_id"] == "1234567890abcdef"
96100
assert sentry_trace_data["parent_span_id"] == "abcdef1234567890"
@@ -121,7 +125,9 @@ def test_get_trace_data_with_sentry_trace():
121125
],
122126
):
123127
span_processor = SentrySpanProcessor()
124-
sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context)
128+
sentry_trace_data = span_processor._get_trace_data(
129+
otel_span.get_span_context(), otel_span.parent, parent_context
130+
)
125131
assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef"
126132
assert sentry_trace_data["span_id"] == "1234567890abcdef"
127133
assert sentry_trace_data["parent_span_id"] == "abcdef1234567890"
@@ -138,7 +144,9 @@ def test_get_trace_data_with_sentry_trace():
138144
],
139145
):
140146
span_processor = SentrySpanProcessor()
141-
sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context)
147+
sentry_trace_data = span_processor._get_trace_data(
148+
otel_span.get_span_context(), otel_span.parent, parent_context
149+
)
142150
assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef"
143151
assert sentry_trace_data["span_id"] == "1234567890abcdef"
144152
assert sentry_trace_data["parent_span_id"] == "abcdef1234567890"
@@ -175,7 +183,9 @@ def test_get_trace_data_with_sentry_trace_and_baggage():
175183
],
176184
):
177185
span_processor = SentrySpanProcessor()
178-
sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context)
186+
sentry_trace_data = span_processor._get_trace_data(
187+
otel_span.get_span_context(), otel_span.parent, parent_context
188+
)
179189
assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef"
180190
assert sentry_trace_data["span_id"] == "1234567890abcdef"
181191
assert sentry_trace_data["parent_span_id"] == "abcdef1234567890"

tox.ini

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ envlist =
102102

103103
# ~~~ AI ~~~
104104
{py3.8,py3.11,py3.12}-anthropic-v0.16.0
105-
{py3.8,py3.11,py3.12}-anthropic-v0.39.0
106-
{py3.8,py3.12,py3.13}-anthropic-v0.62.0
107-
{py3.9,py3.13,py3.14,py3.14t}-anthropic-v0.86.0
105+
{py3.8,py3.11,py3.12}-anthropic-v0.42.0
106+
{py3.8,py3.12,py3.13}-anthropic-v0.68.2
107+
{py3.9,py3.13,py3.14,py3.14t}-anthropic-v0.93.0
108108
{py3.9,py3.13,py3.14,py3.14t}-anthropic-latest
109109

110110
{py3.9,py3.10,py3.11}-cohere-v5.4.0
@@ -515,13 +515,14 @@ deps =
515515

516516
# ~~~ AI ~~~
517517
anthropic-v0.16.0: anthropic==0.16.0
518-
anthropic-v0.39.0: anthropic==0.39.0
519-
anthropic-v0.62.0: anthropic==0.62.0
520-
anthropic-v0.86.0: anthropic==0.86.0
521-
anthropic-latest: anthropic==0.86.0
518+
anthropic-v0.42.0: anthropic==0.42.0
519+
anthropic-v0.68.2: anthropic==0.68.2
520+
anthropic-v0.93.0: anthropic==0.93.0
521+
anthropic-latest: anthropic==0.93.0
522522
anthropic: pytest-asyncio
523523
anthropic-v0.16.0: httpx<0.28.0
524-
anthropic-v0.39.0: httpx<0.28.0
524+
anthropic-v0.42.0: httpx<0.28.0
525+
{py3.8}-anthropic: tokenizers<0.20.4
525526

526527
cohere-v5.4.0: cohere==5.4.0
527528
cohere-v5.10.0: cohere==5.10.0

0 commit comments

Comments
 (0)