Skip to content
Open
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
10 changes: 6 additions & 4 deletions sentry_sdk/integrations/boto3/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
_set_span_attributes,
_start_client_span,
)
from sentry_sdk.integrations.boto3._services.registry import (
_resolve_service,
)
from sentry_sdk.integrations.boto3._services.bedrock import _BedrockExtension
from sentry_sdk.integrations.boto3.consts import IDENTIFIER
from sentry_sdk.traces import NoOpStreamedSpan, StreamedSpan
from sentry_sdk.utils import capture_internal_exceptions

Check failure on line 20 in sentry_sdk/integrations/boto3/_client.py

View check run for this annotation

@sentry/warden / warden: code-review

[UZ9-QK4] get_span_op AND condition never matches, labels all Bedrock ops as gen_ai.chat (additional location)

`_BedrockExtension.get_span_op` in `bedrock.py` uses `operation_name == "Converse" and == "ConverseStream"`, which is never true, so every bedrock-runtime operation gets `OP.GEN_AI_CHAT`. Mirror the `!=` guards already used in `get_span_origin`/`get_request_attributes`.

Check warning on line 20 in sentry_sdk/integrations/boto3/_client.py

View check run for this annotation

@sentry/warden / warden: find-bugs

Bedrock assigns chat operation to every runtime call

In `_BedrockExtension.get_span_op()`, the condition requiring one operation name to equal both `Converse` and `ConverseStream` can never be true. As a result, every `bedrock-runtime` operation—including non-Converse operations—gets `gen_ai.chat`; change the guard to exclude both Converse operations when they do not match.

if TYPE_CHECKING:
from typing import Any, Dict, Iterator, Optional, Union
Expand Down Expand Up @@ -104,7 +102,11 @@
with capture_internal_exceptions():
# add optional metadata to the context, e.g. service-name, region-name, etc.
ctx.add_metadata(self)
service_ext = _resolve_service(ctx.service_name)

service_ext = None
if ctx.service_name == "bedrock-runtime":
service_ext = _BedrockExtension()

Check failure on line 109 in sentry_sdk/integrations/boto3/_client.py

View check run for this annotation

@sentry/warden / warden: code-review

[UZ9-QK4] get_span_op AND condition never matches, labels all Bedrock ops as gen_ai.chat (additional location)

`_BedrockExtension.get_span_op` in `bedrock.py` uses `operation_name == "Converse" and == "ConverseStream"`, which is never true, so every bedrock-runtime operation gets `OP.GEN_AI_CHAT`. Mirror the `!=` guards already used in `get_span_origin`/`get_request_attributes`.
Comment thread
alexander-alderman-webb marked this conversation as resolved.
Resolved
span = _start_client_span(ctx, service_ext)

if span is None:
Expand Down
24 changes: 11 additions & 13 deletions sentry_sdk/integrations/boto3/_instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,30 +173,28 @@
# https://opentelemetry.io/docs/specs/semconv/cloud-providers/aws-sdk/#aws-sdk-spans
SPANDATA.SENTRY_KIND: "client",
}
with capture_internal_exceptions():
attributes.update(_get_client_attributes(ctx))
attributes.update(_get_client_attributes(ctx))

# `sentry.span_op` and `sentry.span_origin` are set to generic defaults;
# a service extension can override them with `get_span_op()` and `get_span_origin()`.
span_op = OP.HTTP_CLIENT
span_origin = ORIGIN

if service_ext is not None:
with capture_internal_exceptions():
service_op = service_ext.get_span_op(ctx)
if service_op is not None:
span_op = service_op
service_op = service_ext.get_span_op(ctx)
if service_op is not None:
span_op = service_op

Check failure on line 186 in sentry_sdk/integrations/boto3/_instrumentation.py

View check run for this annotation

@sentry/warden / warden: code-review

[UZ9-QK4] get_span_op AND condition never matches, labels all Bedrock ops as gen_ai.chat (additional location)

`_BedrockExtension.get_span_op` in `bedrock.py` uses `operation_name == "Converse" and == "ConverseStream"`, which is never true, so every bedrock-runtime operation gets `OP.GEN_AI_CHAT`. Mirror the `!=` guards already used in `get_span_origin`/`get_request_attributes`.

with capture_internal_exceptions():
service_origin = service_ext.get_span_origin(ctx)
if service_origin is not None:
span_origin = service_origin
service_origin = service_ext.get_span_origin(ctx)
if service_origin is not None:
span_origin = service_origin

with capture_internal_exceptions():
attributes.update(service_ext.get_request_attributes(ctx))
attributes.update(service_ext.get_request_attributes(ctx))

if has_span_streaming_enabled(client.options):
if sentry_sdk.traces.get_current_span() is None:
if (
service_ext is None or service_ext.skip_if_no_active_span
) and sentry_sdk.traces.get_current_span() is None:
return None

# `start_span()` evaluates `ignore_spans` against the initial attributes.
Expand Down
1 change: 1 addition & 0 deletions sentry_sdk/integrations/boto3/_services/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
to use the generic instrumentation.
"""

__slots__ = ()
skip_if_no_active_span = True

Check warning on line 20 in sentry_sdk/integrations/boto3/_services/base.py

View check run for this annotation

@sentry/warden / warden: find-bugs

[ZTQ-9CX] Bedrock assigns chat operation to every runtime call (additional location)

In `_BedrockExtension.get_span_op()`, the condition requiring one operation name to equal both `Converse` and `ConverseStream` can never be true. As a result, every `bedrock-runtime` operation—including non-Converse operations—gets `gen_ai.chat`; change the guard to exclude both Converse operations when they do not match.
def get_span_op(self, ctx: "AwsCallContext") -> "Optional[str]":
"""Return an optional `sentry.op` override, or `None` to keep the default."""
return None
Expand Down
42 changes: 42 additions & 0 deletions sentry_sdk/integrations/boto3/_services/bedrock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from typing import TYPE_CHECKING

from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.integrations.boto3._services.base import _ServiceExtension

if TYPE_CHECKING:
from typing import Any, Optional

from sentry_sdk._types import Attributes
from sentry_sdk.integrations.boto3._context import AwsCallContext


class _BedrockExtension(_ServiceExtension):
__slots__ = ()
skip_if_no_active_span = False

def get_span_op(self, ctx: "AwsCallContext") -> "Optional[str]":
if ctx.operation_name == "Converse" and ctx.operation_name == "ConverseStream":
return None
return OP.GEN_AI_CHAT

Check failure on line 20 in sentry_sdk/integrations/boto3/_services/bedrock.py

View check run for this annotation

@sentry/warden / warden: code-review

[UZ9-QK4] get_span_op AND condition never matches, labels all Bedrock ops as gen_ai.chat (additional location)

`_BedrockExtension.get_span_op` in `bedrock.py` uses `operation_name == "Converse" and == "ConverseStream"`, which is never true, so every bedrock-runtime operation gets `OP.GEN_AI_CHAT`. Mirror the `!=` guards already used in `get_span_origin`/`get_request_attributes`.

Check warning on line 20 in sentry_sdk/integrations/boto3/_services/bedrock.py

View check run for this annotation

@sentry/warden / warden: find-bugs

[ZTQ-9CX] Bedrock assigns chat operation to every runtime call (additional location)

In `_BedrockExtension.get_span_op()`, the condition requiring one operation name to equal both `Converse` and `ConverseStream` can never be true. As a result, every `bedrock-runtime` operation—including non-Converse operations—gets `gen_ai.chat`; change the guard to exclude both Converse operations when they do not match.
Comment thread
alexander-alderman-webb marked this conversation as resolved.
Resolved

def get_span_origin(self, ctx: "AwsCallContext") -> "Optional[str]":
if ctx.operation_name != "Converse" and ctx.operation_name != "ConverseStream":
return None
return "auto.ai.boto3"

def get_request_attributes(self, ctx: "AwsCallContext") -> "Attributes":
if ctx.operation_name != "Converse" and ctx.operation_name != "ConverseStream":
return {}

return {
SPANDATA.GEN_AI_PROVIDER_NAME: "aws.bedrock",
SPANDATA.GEN_AI_OPERATION_NAME: "chat",
SPANDATA.GEN_AI_RESPONSE_STREAMING: ctx.operation_name == "ConverseStream",
}

def get_response_attributes(
self,
ctx: "AwsCallContext",
response: "Any",
) -> "Attributes":
return {}
22 changes: 0 additions & 22 deletions sentry_sdk/integrations/boto3/_services/registry.py

This file was deleted.

Loading
Loading