From 97acc21d1302f5a818721f67056760716b5fc6ec Mon Sep 17 00:00:00 2001 From: Pablo Deputter Date: Thu, 15 Oct 2026 14:57:55 +0200 Subject: [PATCH 1/4] . --- sentry_sdk/consts.py | 30 ++++ sentry_sdk/integrations/boto3/_client.py | 7 +- .../boto3/_services/stepfunctions.py | 100 +++++++++-- .../integrations/boto3/test_stepfunctions.py | 161 +++++++++++++++++- 4 files changed, 280 insertions(+), 18 deletions(-) diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 5ff880ab73..48a98505ec 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -423,6 +423,36 @@ class SPANDATA: Example: "dfRtDYWFbkRONycy.Yxwh66Yjlx.cph0gtNBtJ" """ + AWS_STEP_FUNCTIONS_ACTIVITY_ARN = "aws.step_functions.activity.arn" + """ + The ARN of the AWS Step Functions activity the request refers to. + Example: "arn:aws:states:us-east-1:123456789012:activity:approve-order" + """ + + AWS_STEP_FUNCTIONS_ACTIVITY_NAME = "aws.step_functions.activity.name" + """ + The name of the AWS Step Functions activity the request refers to. + Example: "approve-order" + """ + + AWS_STEP_FUNCTIONS_EXECUTION_ARN = "aws.step_functions.execution.arn" + """ + The ARN of the AWS Step Functions execution the request refers to. + Example: "arn:aws:states:us-east-1:123456789012:execution:orders:4f9b1c2e" + """ + + AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN = "aws.step_functions.state_machine.arn" + """ + The ARN of the AWS Step Functions state machine the request refers to. + Example: "arn:aws:states:us-east-1:123456789012:stateMachine:orders" + """ + + AWS_STEP_FUNCTIONS_STATE_MACHINE_NAME = "aws.step_functions.state_machine.name" + """ + The name of the AWS Step Functions state machine the request refers to, without a version or alias qualifier. + Example: "orders" + """ + CACHE_HIT = "cache.hit" """ A boolean indicating whether the requested data was found in the cache. diff --git a/sentry_sdk/integrations/boto3/_client.py b/sentry_sdk/integrations/boto3/_client.py index 10a5bb5c93..35ea846e22 100644 --- a/sentry_sdk/integrations/boto3/_client.py +++ b/sentry_sdk/integrations/boto3/_client.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING import sentry_sdk +from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.boto3._context import AwsCallContext from sentry_sdk.integrations.boto3._instrumentation import ( @@ -17,7 +18,7 @@ _resolve_service, ) from sentry_sdk.integrations.boto3.consts import IDENTIFIER -from sentry_sdk.traces import NoOpSpan, Span +from sentry_sdk.traces import NoOpSpan, Span, SpanStatus from sentry_sdk.utils import capture_internal_exceptions if TYPE_CHECKING: @@ -125,6 +126,10 @@ def sentry_patched_make_api_call( attributes.update(_get_response_attributes(parsed)) with capture_internal_exceptions(): span.set_attributes(attributes) + # a service extension reports a failure that didn't raise, i.e. one + # in a successful response, with `error.type`. + if SPANDATA.ERROR_TYPE in attributes: + span.status = SpanStatus.ERROR except BaseException as error: _finish_span(span, error) raise diff --git a/sentry_sdk/integrations/boto3/_services/stepfunctions.py b/sentry_sdk/integrations/boto3/_services/stepfunctions.py index 2c37397660..bfbafbb34c 100644 --- a/sentry_sdk/integrations/boto3/_services/stepfunctions.py +++ b/sentry_sdk/integrations/boto3/_services/stepfunctions.py @@ -1,30 +1,98 @@ from typing import TYPE_CHECKING +from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.boto3._services.base import _ServiceExtension -from sentry_sdk.integrations.boto3._utils import _get_aws_arn_attributes +from sentry_sdk.integrations.boto3._utils import ( + _extract_attributes, + _get_aws_arn_attributes, +) from sentry_sdk.utils import capture_internal_exceptions if TYPE_CHECKING: + from typing import Any, Sequence, Tuple + from sentry_sdk._types import Attributes from sentry_sdk.integrations.boto3._context import AwsCallContext + from sentry_sdk.integrations.boto3._utils import _AttributeSpec + +# the arns otel records from the request and the response, plus the execution's. +# https://opentelemetry.io/docs/specs/semconv/registry/attributes/aws/#amazon-step-functions-attributes +_ARN_ATTRIBUTES: "Sequence[_AttributeSpec]" = ( + ("activityArn", SPANDATA.AWS_STEP_FUNCTIONS_ACTIVITY_ARN), + ("executionArn", SPANDATA.AWS_STEP_FUNCTIONS_EXECUTION_ARN), + ("stateMachineArn", SPANDATA.AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN), +) + +# request parameters with the arn of the resource a call acts on. a call takes at most +# one, `ListExecutions` either a `mapRunArn` or a `stateMachineArn`. +_TARGET_ARN_PARAMS = ( + "activityArn", + "executionArn", + "mapRunArn", + "resourceArn", + "stateMachineAliasArn", + "stateMachineArn", + "stateMachineVersionArn", +) + +# apis whose `name` is the name of what they create; elsewhere it names an execution +# (often per order or customer) or an alias. +_CREATED_NAME_ATTRIBUTES = { + "CreateActivity": SPANDATA.AWS_STEP_FUNCTIONS_ACTIVITY_NAME, + "CreateStateMachine": SPANDATA.AWS_STEP_FUNCTIONS_STATE_MACHINE_NAME, +} + +# `StartSyncExecution` returns `200 OK` for a failed or timed out execution too. +# https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartSyncExecution.html +_SYNC_EXECUTION_ERROR_TYPES = { + "FAILED": "stepfunctions_execution_failed", + "TIMED_OUT": "stepfunctions_execution_timed_out", +} + + +def _get_name_attribute(arn: str) -> "Tuple[str, str]": + # `arn::states::::…`, where is the + # activity's or the state machine's. versions and aliases append `:`, + # executions `:`; map runs and their child executions put `/