Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions sentry_sdk/integrations/anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,8 @@ def _sentry_patched_create_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any

span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
if span_streaming:
if sentry_sdk.traces.get_current_span() is None:
return f(*args, **kwargs)
span = sentry_sdk.traces.start_span(
name=f"chat {model}".strip(),
attributes={
Expand Down Expand Up @@ -738,6 +740,8 @@ async def _sentry_patched_create_async(

span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
if span_streaming:
if sentry_sdk.traces.get_current_span() is None:
return await f(*args, **kwargs)
span = sentry_sdk.traces.start_span(
name=f"chat {model}".strip(),
attributes={
Expand Down Expand Up @@ -982,6 +986,8 @@ def _sentry_patched_enter(self: "MessageStreamManager") -> "MessageStream":
return f(self)

if has_span_streaming_enabled(client.options):
if sentry_sdk.traces.get_current_span() is None:
return f(self)
span = sentry_sdk.traces.start_span(
name="chat" if self._model is None else f"chat {self._model}".strip(),
attributes={
Expand Down Expand Up @@ -1089,6 +1095,8 @@ async def _sentry_patched_aenter(
return await f(self)

if has_span_streaming_enabled(client.options):
if sentry_sdk.traces.get_current_span() is None:
return await f(self)
span = sentry_sdk.traces.start_span(
name="chat" if self._model is None else f"chat {self._model}".strip(),
attributes={
Expand Down
10 changes: 9 additions & 1 deletion sentry_sdk/integrations/cohere.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
import sentry_sdk
from sentry_sdk.integrations import DidNotEnable, Integration
from sentry_sdk.scope import should_send_default_pii
from sentry_sdk.utils import capture_internal_exceptions, event_from_exception, reraise
from sentry_sdk.utils import (
capture_internal_exceptions,
event_from_exception,
reraise,
)

try:
from cohere import (
Expand Down Expand Up @@ -154,6 +158,8 @@ def new_chat(*args: "Any", **kwargs: "Any") -> "Any":
message = kwargs.get("message")

if is_span_streaming_enabled:
if sentry_sdk.traces.get_current_span() is None:
return f(*args, **kwargs)
span = sentry_sdk.traces.start_span(
name="cohere.client.Chat",
attributes={
Expand Down Expand Up @@ -250,6 +256,8 @@ def new_embed(*args: "Any", **kwargs: "Any") -> "Any":
)

if is_span_streaming_enabled:
if sentry_sdk.traces.get_current_span() is None:
return f(*args, **kwargs)
span_ctx = sentry_sdk.traces.start_span(
name="Cohere Embedding Creation",
attributes={
Expand Down
124 changes: 76 additions & 48 deletions sentry_sdk/integrations/google_genai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,19 @@ def new_generate_content_stream(
_model, contents, model_name = prepare_generate_content_args(args, kwargs)

if has_span_streaming_enabled(client.options):
chat_span = sentry_sdk.traces.start_span(
name=f"chat {model_name}",
attributes={
"sentry.op": OP.GEN_AI_CHAT,
"sentry.origin": ORIGIN,
SPANDATA.GEN_AI_OPERATION_NAME: "chat",
SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM,
SPANDATA.GEN_AI_REQUEST_MODEL: model_name,
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
},
)
chat_span = None
if sentry_sdk.traces.get_current_span() is not None:
chat_span = sentry_sdk.traces.start_span(
name=f"chat {model_name}",
attributes={
"sentry.op": OP.GEN_AI_CHAT,
"sentry.origin": ORIGIN,
SPANDATA.GEN_AI_OPERATION_NAME: "chat",
SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM,
SPANDATA.GEN_AI_REQUEST_MODEL: model_name,
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
},
)
else:
chat_span = get_start_span_function()(
op=OP.GEN_AI_CHAT,
Expand All @@ -100,7 +102,10 @@ def new_generate_content_stream(
chat_span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name)
chat_span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True)

set_span_data_for_request(chat_span, integration, model_name, contents, kwargs)
if chat_span is not None:
set_span_data_for_request(
chat_span, integration, model_name, contents, kwargs
)

try:
stream = f(self, *args, **kwargs)
Expand All @@ -114,25 +119,28 @@ def new_iterator() -> "Iterator[Any]":
yield chunk
except Exception as exc:
_capture_exception(exc)
if isinstance(chat_span, StreamedSpan):
chat_span.status = SpanStatus.ERROR
else:
chat_span.set_status(SPANSTATUS.INTERNAL_ERROR)
if chat_span is not None:
if isinstance(chat_span, StreamedSpan):
chat_span.status = SpanStatus.ERROR
else:
chat_span.set_status(SPANSTATUS.INTERNAL_ERROR)
raise
finally:
# Accumulate all chunks and set final response data on spans
if chunks:
accumulated_response = accumulate_streaming_response(chunks)
set_span_data_for_streaming_response(
chat_span, integration, accumulated_response
)
chat_span.__exit__(None, None, None)
if chat_span is not None:
# Accumulate all chunks and set final response data on spans
if chunks:
accumulated_response = accumulate_streaming_response(chunks)
set_span_data_for_streaming_response(
chat_span, integration, accumulated_response
)
chat_span.__exit__(None, None, None)

return new_iterator()

except Exception as exc:
_capture_exception(exc)
chat_span.__exit__(None, None, None)
if chat_span is not None:
chat_span.__exit__(None, None, None)
raise

return new_generate_content_stream
Expand All @@ -153,17 +161,19 @@ async def new_async_generate_content_stream(
_model, contents, model_name = prepare_generate_content_args(args, kwargs)

if has_span_streaming_enabled(client.options):
chat_span = sentry_sdk.traces.start_span(
name=f"chat {model_name}",
attributes={
"sentry.op": OP.GEN_AI_CHAT,
"sentry.origin": ORIGIN,
SPANDATA.GEN_AI_OPERATION_NAME: "chat",
SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM,
SPANDATA.GEN_AI_REQUEST_MODEL: model_name,
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
},
)
chat_span = None
if sentry_sdk.traces.get_current_span() is not None:
chat_span = sentry_sdk.traces.start_span(
name=f"chat {model_name}",
attributes={
"sentry.op": OP.GEN_AI_CHAT,
"sentry.origin": ORIGIN,
SPANDATA.GEN_AI_OPERATION_NAME: "chat",
SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM,
SPANDATA.GEN_AI_REQUEST_MODEL: model_name,
SPANDATA.GEN_AI_RESPONSE_STREAMING: True,
},
)
else:
chat_span = get_start_span_function()(
op=OP.GEN_AI_CHAT,
Expand All @@ -177,7 +187,10 @@ async def new_async_generate_content_stream(
chat_span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name)
chat_span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True)

set_span_data_for_request(chat_span, integration, model_name, contents, kwargs)
if chat_span is not None:
set_span_data_for_request(
chat_span, integration, model_name, contents, kwargs
)

try:
stream = await f(self, *args, **kwargs)
Expand All @@ -191,25 +204,28 @@ async def new_async_iterator() -> "AsyncIterator[Any]":
yield chunk
except Exception as exc:
_capture_exception(exc)
if isinstance(chat_span, StreamedSpan):
chat_span.status = SpanStatus.ERROR
else:
chat_span.set_status(SPANSTATUS.INTERNAL_ERROR)
if chat_span is not None:
if isinstance(chat_span, StreamedSpan):
chat_span.status = SpanStatus.ERROR
else:
chat_span.set_status(SPANSTATUS.INTERNAL_ERROR)
raise
finally:
# Accumulate all chunks and set final response data on spans
if chunks:
accumulated_response = accumulate_streaming_response(chunks)
set_span_data_for_streaming_response(
chat_span, integration, accumulated_response
)
chat_span.__exit__(None, None, None)
if chat_span is not None:
# Accumulate all chunks and set final response data on spans
if chunks:
accumulated_response = accumulate_streaming_response(chunks)
set_span_data_for_streaming_response(
chat_span, integration, accumulated_response
)
chat_span.__exit__(None, None, None)

return new_async_iterator()

except Exception as exc:
_capture_exception(exc)
chat_span.__exit__(None, None, None)
if chat_span is not None:
chat_span.__exit__(None, None, None)
raise

return new_async_generate_content_stream
Expand All @@ -226,6 +242,9 @@ def new_generate_content(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
model, contents, model_name = prepare_generate_content_args(args, kwargs)

if has_span_streaming_enabled(client.options):
if sentry_sdk.traces.get_current_span() is None:
return f(self, *args, **kwargs)

with sentry_sdk.traces.start_span(
name=f"chat {model_name}",
attributes={
Expand Down Expand Up @@ -290,6 +309,9 @@ async def new_async_generate_content(
model, contents, model_name = prepare_generate_content_args(args, kwargs)

if has_span_streaming_enabled(client.options):
if sentry_sdk.traces.get_current_span() is None:
return await f(self, *args, **kwargs)

with sentry_sdk.traces.start_span(
name=f"chat {model_name}",
attributes={
Expand Down Expand Up @@ -350,6 +372,9 @@ def new_embed_content(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
model_name, contents = prepare_embed_content_args(args, kwargs)

if has_span_streaming_enabled(client.options):
if sentry_sdk.traces.get_current_span() is None:
return f(self, *args, **kwargs)

with sentry_sdk.traces.start_span(
name=f"embeddings {model_name}",
attributes={
Expand Down Expand Up @@ -410,6 +435,9 @@ async def new_async_embed_content(
model_name, contents = prepare_embed_content_args(args, kwargs)

if has_span_streaming_enabled(client.options):
if sentry_sdk.traces.get_current_span() is None:
return await f(self, *args, **kwargs)

with sentry_sdk.traces.start_span(
name=f"embeddings {model_name}",
attributes={
Expand Down
65 changes: 42 additions & 23 deletions sentry_sdk/integrations/google_genai/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from sentry_sdk.utils import (
capture_internal_exceptions,
event_from_exception,
nullcontext,
safe_serialize,
)

Expand Down Expand Up @@ -671,10 +672,12 @@ def _capture_tool_input(

def _create_tool_span(
tool_name: str, tool_doc: "Optional[str]"
) -> "Union[Span, StreamedSpan]":
) -> "Union[Span, StreamedSpan, nullcontext[None]]":
"""Create a span for tool execution."""
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
if span_streaming:
if sentry_sdk.traces.get_current_span() is None:
return nullcontext()
span = sentry_sdk.traces.start_span(
name=f"execute_tool {tool_name}",
attributes={
Expand Down Expand Up @@ -712,22 +715,30 @@ def wrapped_tool(tool: "Tool | Callable[..., Any]") -> "Tool | Callable[..., Any
@wraps(tool)
async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
with _create_tool_span(tool_name, tool_doc) as span:
set_on_span = (
span.set_attribute
if isinstance(span, StreamedSpan)
else span.set_data
)
# Capture tool input
tool_input = _capture_tool_input(args, kwargs, tool)
with capture_internal_exceptions():
set_on_span(SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input))
if span is not None:
set_on_span = (
span.set_attribute
if isinstance(span, StreamedSpan)
else span.set_data
)
# Capture tool input
tool_input = _capture_tool_input(args, kwargs, tool)
with capture_internal_exceptions():
set_on_span(
SPANDATA.GEN_AI_TOOL_INPUT,
safe_serialize(tool_input),
)

try:
result = await tool(*args, **kwargs)

# Capture tool output
with capture_internal_exceptions():
set_on_span(SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result))
if span is not None:
with capture_internal_exceptions():
set_on_span(
SPANDATA.GEN_AI_TOOL_OUTPUT,
safe_serialize(result),
)

return result
except Exception as exc:
Expand All @@ -740,22 +751,30 @@ async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
@wraps(tool)
def sync_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
with _create_tool_span(tool_name, tool_doc) as span:
set_on_span = (
span.set_attribute
if isinstance(span, StreamedSpan)
else span.set_data
)
# Capture tool input
tool_input = _capture_tool_input(args, kwargs, tool)
with capture_internal_exceptions():
set_on_span(SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input))
if span is not None:
set_on_span = (
span.set_attribute
if isinstance(span, StreamedSpan)
else span.set_data
)
# Capture tool input
tool_input = _capture_tool_input(args, kwargs, tool)
with capture_internal_exceptions():
set_on_span(
SPANDATA.GEN_AI_TOOL_INPUT,
safe_serialize(tool_input),
)

try:
result = tool(*args, **kwargs)

# Capture tool output
with capture_internal_exceptions():
set_on_span(SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result))
if span is not None:
with capture_internal_exceptions():
set_on_span(
SPANDATA.GEN_AI_TOOL_OUTPUT,
safe_serialize(result),
)

return result
except Exception as exc:
Expand Down
2 changes: 2 additions & 0 deletions sentry_sdk/integrations/huggingface_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any":

span: "Union[Span, StreamedSpan]"
if has_span_streaming_enabled(sentry_sdk.get_client().options):
if sentry_sdk.traces.get_current_span() is None:
return f(*args, **kwargs)
span = sentry_sdk.traces.start_span(
name=f"{operation_name} {model}",
attributes={
Expand Down
Loading
Loading