Skip to content

Commit 0010d59

Browse files
chore(anthropic): Remove transaction-based tracing (#7372)
Remove branches for the static trace lifecycle. Remove manual tracing API calls in tests, as the outer transaction is no longer needed for GenAI spans in the streaming trace lifecycle. Closes #7073
1 parent 267ee6c commit 0010d59

2 files changed

Lines changed: 1529 additions & 4110 deletions

File tree

sentry_sdk/integrations/anthropic.py

Lines changed: 62 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,15 @@
88
from sentry_sdk.ai.monitoring import record_token_usage
99
from sentry_sdk.ai.utils import (
1010
GEN_AI_ALLOWED_MESSAGE_ROLES,
11-
get_start_span_function,
1211
normalize_message_roles,
1312
set_data_normalized,
1413
transform_anthropic_content_part,
15-
truncate_and_annotate_messages,
1614
)
1715
from sentry_sdk.consts import OP, SPANDATA
1816
from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version
1917
from sentry_sdk.scope import should_send_default_pii
2018
from sentry_sdk.traces import StreamedSpan
2119
from sentry_sdk.tracing import Span
22-
from sentry_sdk.tracing_utils import (
23-
has_span_streaming_enabled,
24-
)
2520
from sentry_sdk.utils import (
2621
capture_internal_exceptions,
2722
event_from_exception,
@@ -89,7 +84,7 @@
8984
from sentry_sdk._types import TextPart
9085

9186
class _PatchedRawMessageStream(Stream[RawMessageStreamEvent]):
92-
_span: Span
87+
_span: StreamedSpan
9388
_integration: "AnthropicIntegration"
9489

9590
_model: Optional[ModelParam]
@@ -99,7 +94,7 @@ class _PatchedRawMessageStream(Stream[RawMessageStreamEvent]):
9994
_finish_reason: Optional[str]
10095

10196
class _PatchedMessageStream(MessageStream):
102-
_span: Span
97+
_span: StreamedSpan
10398
_integration: "AnthropicIntegration"
10499

105100
_model: Optional[ModelParam]
@@ -109,7 +104,7 @@ class _PatchedMessageStream(MessageStream):
109104
_finish_reason: Optional[str]
110105

111106
class _PatchedRawAsyncMessageStream(AsyncStream[RawMessageStreamEvent]):
112-
_span: Span
107+
_span: StreamedSpan
113108
_integration: "AnthropicIntegration"
114109

115110
_model: Optional[ModelParam]
@@ -119,7 +114,7 @@ class _PatchedRawAsyncMessageStream(AsyncStream[RawMessageStreamEvent]):
119114
_finish_reason: Optional[str]
120115

121116
class _PatchedAsyncMessageStream(AsyncMessageStream):
122-
_span: Span
117+
_span: StreamedSpan
123118
_integration: "AnthropicIntegration"
124119

125120
_model: Optional[ModelParam]
@@ -129,7 +124,7 @@ class _PatchedAsyncMessageStream(AsyncMessageStream):
129124
_finish_reason: Optional[str]
130125

131126
class _PatchedMessageStreamManager(MessageStreamManager):
132-
_span: Union[Span, StreamedSpan]
127+
_span: StreamedSpan
133128
_integration: "AnthropicIntegration"
134129

135130
_max_tokens: int
@@ -142,7 +137,7 @@ class _PatchedMessageStreamManager(MessageStreamManager):
142137
_tools: Optional[Iterable[ToolUnionParam]]
143138

144139
class _PatchedAsyncMessageStreamManager(AsyncMessageStreamManager[Any]):
145-
_span: Union[Span, StreamedSpan]
140+
_span: StreamedSpan
146141
_integration: "AnthropicIntegration"
147142

148143
_max_tokens: int
@@ -447,7 +442,7 @@ def _transform_system_instructions(
447442

448443

449444
def _set_common_input_data(
450-
span: "Union[Span, StreamedSpan]",
445+
span: "StreamedSpan",
451446
integration: "AnthropicIntegration",
452447
max_tokens: "int",
453448
messages: "Iterable[MessageParam]",
@@ -461,36 +456,35 @@ def _set_common_input_data(
461456
"""
462457
Set input data for the span based on the provided keyword arguments for the anthropic message creation.
463458
"""
464-
set_on_span = (
465-
span.set_attribute if isinstance(span, StreamedSpan) else span.set_data
466-
)
467-
set_on_span(SPANDATA.GEN_AI_SYSTEM, "anthropic")
468-
set_on_span(SPANDATA.GEN_AI_OPERATION_NAME, "chat")
459+
span.set_attribute(SPANDATA.GEN_AI_SYSTEM, "anthropic")
460+
span.set_attribute(SPANDATA.GEN_AI_OPERATION_NAME, "chat")
469461

470462
if max_tokens is not None and _is_given(max_tokens):
471-
set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens)
463+
span.set_attribute(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens)
472464
if model is not None and _is_given(model):
473-
set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model)
465+
span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model)
474466
if temperature is not None and _is_given(temperature):
475-
set_on_span(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature)
467+
span.set_attribute(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature)
476468
if top_k is not None and _is_given(top_k):
477-
set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_K, top_k)
469+
span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_K, top_k)
478470
if top_p is not None and _is_given(top_p):
479-
set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p)
471+
span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p)
480472

481473
client = sentry_sdk.get_client()
482474

483475
if has_data_collection_enabled(client.options):
484476
if client.options["data_collection"]["gen_ai"]["inputs"]:
485477
if tools is not None and _is_given(tools) and len(tools) > 0: # type: ignore
486-
set_on_span(
478+
span.set_attribute(
487479
SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools)
488480
)
489481
else:
490482
# Tools were unconditionally added pre-data collection configuration.
491483
# This can be removed once data collection is fully rolled out
492484
if tools is not None and _is_given(tools) and len(tools) > 0: # type: ignore
493-
set_on_span(SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools))
485+
span.set_attribute(
486+
SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools)
487+
)
494488

495489
if messages is None or len(messages) == 0: # type: ignore
496490
return
@@ -504,7 +498,7 @@ def _set_common_input_data(
504498

505499
if record_inputs:
506500
if isinstance(system, str) or isinstance(system, Iterable):
507-
set_on_span(
501+
span.set_attribute(
508502
SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS,
509503
json.dumps(_transform_system_instructions(system)),
510504
)
@@ -554,35 +548,24 @@ def _set_common_input_data(
554548

555549
role_normalized_messages = normalize_message_roles(normalized_messages)
556550

557-
scope = sentry_sdk.get_current_scope()
558-
messages_data = (
559-
truncate_and_annotate_messages(role_normalized_messages, span, scope)
560-
if not has_span_streaming_enabled(client.options)
561-
else role_normalized_messages
562-
)
563-
if messages_data is not None:
551+
if role_normalized_messages is not None:
564552
set_data_normalized(
565553
span,
566554
SPANDATA.GEN_AI_REQUEST_MESSAGES,
567-
messages_data,
555+
role_normalized_messages,
568556
unpack=False,
569557
)
570558

571559

572560
def _set_create_input_data(
573-
span: "Union[Span, StreamedSpan]",
561+
span: "StreamedSpan",
574562
kwargs: "dict[str, Any]",
575563
integration: "AnthropicIntegration",
576564
) -> None:
577565
"""
578566
Set input data for the span based on the provided keyword arguments for the anthropic message creation.
579567
"""
580-
if isinstance(span, StreamedSpan):
581-
span.set_attribute(
582-
SPANDATA.GEN_AI_RESPONSE_STREAMING, kwargs.get("stream", False)
583-
)
584-
else:
585-
span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, kwargs.get("stream", False))
568+
span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, kwargs.get("stream", False))
586569

587570
_set_common_input_data(
588571
span=span,
@@ -659,7 +642,7 @@ async def _wrap_asynchronous_message_iterator(
659642

660643

661644
def _set_output_data(
662-
span: "Union[Span, StreamedSpan]",
645+
span: "StreamedSpan",
663646
integration: "AnthropicIntegration",
664647
model: "str | None",
665648
input_tokens: "int | None",
@@ -672,15 +655,12 @@ def _set_output_data(
672655
) -> None:
673656
"""
674657
Set output data for the span based on the AI response."""
675-
set_on_span = (
676-
span.set_attribute if isinstance(span, StreamedSpan) else span.set_data
677-
)
678658
if model is not None:
679-
set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, model)
659+
span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, model)
680660
if response_id is not None:
681-
set_on_span(SPANDATA.GEN_AI_RESPONSE_ID, response_id)
661+
span.set_attribute(SPANDATA.GEN_AI_RESPONSE_ID, response_id)
682662
if finish_reason is not None:
683-
set_on_span(SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS, [finish_reason])
663+
span.set_attribute(SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS, [finish_reason])
684664

685665
client = sentry_sdk.get_client()
686666
record_outputs = False
@@ -741,22 +721,13 @@ def _sentry_patched_create_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any
741721

742722
model = kwargs.get("model", "")
743723

744-
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
745-
if span_streaming:
746-
span = sentry_sdk.traces.start_span(
747-
name=f"chat {model}".strip(),
748-
attributes={
749-
"sentry.op": OP.GEN_AI_CHAT,
750-
"sentry.origin": AnthropicIntegration.origin,
751-
},
752-
)
753-
else:
754-
span = get_start_span_function()(
755-
op=OP.GEN_AI_CHAT,
756-
name=f"chat {model}".strip(),
757-
origin=AnthropicIntegration.origin,
758-
)
759-
span.__enter__()
724+
span = sentry_sdk.traces.start_span(
725+
name=f"chat {model}".strip(),
726+
attributes={
727+
"sentry.op": OP.GEN_AI_CHAT,
728+
"sentry.origin": AnthropicIntegration.origin,
729+
},
730+
)
760731

761732
_set_create_input_data(span, kwargs, integration)
762733

@@ -839,22 +810,13 @@ async def _sentry_patched_create_async(
839810

840811
model = kwargs.get("model", "")
841812

842-
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
843-
if span_streaming:
844-
span = sentry_sdk.traces.start_span(
845-
name=f"chat {model}".strip(),
846-
attributes={
847-
"sentry.op": OP.GEN_AI_CHAT,
848-
"sentry.origin": AnthropicIntegration.origin,
849-
},
850-
)
851-
else:
852-
span = get_start_span_function()(
853-
op=OP.GEN_AI_CHAT,
854-
name=f"chat {model}".strip(),
855-
origin=AnthropicIntegration.origin,
856-
)
857-
span.__enter__()
813+
span = sentry_sdk.traces.start_span(
814+
name=f"chat {model}".strip(),
815+
attributes={
816+
"sentry.op": OP.GEN_AI_CHAT,
817+
"sentry.origin": AnthropicIntegration.origin,
818+
},
819+
)
858820

859821
_set_create_input_data(span, kwargs, integration)
860822

@@ -966,7 +928,7 @@ def _accumulate_event_data(
966928

967929

968930
def _set_streaming_output_data(
969-
span: "Span",
931+
span: "StreamedSpan",
970932
integration: "AnthropicIntegration",
971933
model: "Optional[str]",
972934
usage: "_RecordedUsage",
@@ -1088,28 +1050,16 @@ def _sentry_patched_enter(self: "MessageStreamManager") -> "MessageStream":
10881050
except TypeError:
10891051
return f(self)
10901052

1091-
if has_span_streaming_enabled(client.options):
1092-
span = sentry_sdk.traces.start_span(
1093-
name="chat"
1094-
if patched_self._model is None
1095-
else f"chat {patched_self._model}".strip(),
1096-
attributes={
1097-
"sentry.op": OP.GEN_AI_CHAT,
1098-
"sentry.origin": AnthropicIntegration.origin,
1099-
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
1100-
},
1101-
)
1102-
else:
1103-
span = get_start_span_function()(
1104-
op=OP.GEN_AI_CHAT,
1105-
name="chat"
1106-
if patched_self._model is None
1107-
else f"chat {patched_self._model}".strip(),
1108-
origin=AnthropicIntegration.origin,
1109-
)
1110-
span.__enter__()
1111-
1112-
span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True)
1053+
span = sentry_sdk.traces.start_span(
1054+
name="chat"
1055+
if patched_self._model is None
1056+
else f"chat {patched_self._model}".strip(),
1057+
attributes={
1058+
"sentry.op": OP.GEN_AI_CHAT,
1059+
"sentry.origin": AnthropicIntegration.origin,
1060+
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
1061+
},
1062+
)
11131063

11141064
_set_common_input_data(
11151065
span=span,
@@ -1201,28 +1151,16 @@ async def _sentry_patched_aenter(
12011151
except TypeError:
12021152
return await f(self)
12031153

1204-
if has_span_streaming_enabled(client.options):
1205-
span = sentry_sdk.traces.start_span(
1206-
name="chat"
1207-
if patched_self._model is None
1208-
else f"chat {patched_self._model}".strip(),
1209-
attributes={
1210-
"sentry.op": OP.GEN_AI_CHAT,
1211-
"sentry.origin": AnthropicIntegration.origin,
1212-
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
1213-
},
1214-
)
1215-
else:
1216-
span = get_start_span_function()(
1217-
op=OP.GEN_AI_CHAT,
1218-
name="chat"
1219-
if patched_self._model is None
1220-
else f"chat {patched_self._model}".strip(),
1221-
origin=AnthropicIntegration.origin,
1222-
)
1223-
span.__enter__()
1224-
1225-
span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True)
1154+
span = sentry_sdk.traces.start_span(
1155+
name="chat"
1156+
if patched_self._model is None
1157+
else f"chat {patched_self._model}".strip(),
1158+
attributes={
1159+
"sentry.op": OP.GEN_AI_CHAT,
1160+
"sentry.origin": AnthropicIntegration.origin,
1161+
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
1162+
},
1163+
)
12261164

12271165
_set_common_input_data(
12281166
span=span,

0 commit comments

Comments
 (0)