From 68cfd23f95dc844d074b828c747123e79a93211f Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 21 Sep 2026 10:59:04 +0200 Subject: [PATCH 1/3] fix(bottle): Set transaction name in event processor --- sentry_sdk/integrations/bottle.py | 27 +++++++++++++++++++++++ tests/integrations/bottle/test_bottle.py | 28 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/sentry_sdk/integrations/bottle.py b/sentry_sdk/integrations/bottle.py index a973e6fbe3..3782f4337a 100644 --- a/sentry_sdk/integrations/bottle.py +++ b/sentry_sdk/integrations/bottle.py @@ -211,10 +211,37 @@ def _set_segment_name_and_source(transaction_style: str) -> None: pass +def _set_transaction_name_and_source( + event: "Event", transaction_style: str, request: "Any" +) -> None: + name = "" + + if transaction_style == "url": + try: + name = request.route.rule or "" + except RuntimeError: + pass + + elif transaction_style == "endpoint": + try: + name = ( + request.route.name + or transaction_from_function(request.route.callback) + or "" + ) + except RuntimeError: + pass + + event["transaction"] = name + event["transaction_info"] = {"source": SEGMENT_SOURCE_FOR_STYLE[transaction_style]} + + def _make_request_event_processor( app: "Bottle", request: "LocalRequest", integration: "BottleIntegration" ) -> "EventProcessor": def event_processor(event: "Event", hint: "dict[str, Any]") -> "Event": + _set_transaction_name_and_source(event, integration.transaction_style, request) + with capture_internal_exceptions(): BottleRequestExtractor(request).extract_into_event(event) diff --git a/tests/integrations/bottle/test_bottle.py b/tests/integrations/bottle/test_bottle.py index 0c4648bf2e..9798e8ded0 100644 --- a/tests/integrations/bottle/test_bottle.py +++ b/tests/integrations/bottle/test_bottle.py @@ -824,6 +824,34 @@ def index(): assert "data" not in event.get("_meta", {}).get("request", {}) +def test_error_event_has_transaction_name(sentry_init, capture_events): + """ + Error events captured during request handling should have the correct + transaction name set by the event processor, even though the inline + set_transaction_name call happens after the handler returns. + """ + sentry_init(integrations=[BottleIntegration(transaction_style="url")]) + events = capture_events() + + app = Bottle() + + @app.route("/error/") + def error_handler(error_id): + 1 / 0 + + client = Client(app) + + try: + client.get("/error/123") + except ZeroDivisionError: + pass + + (event,) = events + assert event["exception"]["values"][0]["type"] == "ZeroDivisionError" + assert event["transaction"] == "/error/" + assert event["transaction_info"] == {"source": "route"} + + def test_oversized_request_body_not_annotated_data_collection( sentry_init, capture_events, app, get_client ): From 06b25cebf1445277a915e0ec67493887e45023ba Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 21 Sep 2026 11:17:47 +0200 Subject: [PATCH 2/3] . --- sentry_sdk/integrations/bottle.py | 51 +++++++++++-------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/sentry_sdk/integrations/bottle.py b/sentry_sdk/integrations/bottle.py index 3782f4337a..90561956e1 100644 --- a/sentry_sdk/integrations/bottle.py +++ b/sentry_sdk/integrations/bottle.py @@ -192,55 +192,38 @@ def size_of_file(self, file: "FileUpload") -> int: return file.content_length -def _set_segment_name_and_source(transaction_style: str) -> None: +def _get_transaction_name(transaction_style: str, request: "Any") -> str: try: if transaction_style == "url": - name = bottle_request.route.rule or "bottle request" + return request.route.rule or "" else: - name = ( - bottle_request.route.name - or transaction_from_function(bottle_request.route.callback) - or "bottle request" + return ( + request.route.name + or transaction_from_function(request.route.callback) + or "" ) + except RuntimeError: + return "" + +def _set_segment_name_and_source(transaction_style: str) -> None: + name = _get_transaction_name(transaction_style, bottle_request) + if name: sentry_sdk.get_current_scope().set_transaction_name( name, source=SEGMENT_SOURCE_FOR_STYLE[transaction_style], ) - except RuntimeError: - pass - - -def _set_transaction_name_and_source( - event: "Event", transaction_style: str, request: "Any" -) -> None: - name = "" - - if transaction_style == "url": - try: - name = request.route.rule or "" - except RuntimeError: - pass - - elif transaction_style == "endpoint": - try: - name = ( - request.route.name - or transaction_from_function(request.route.callback) - or "" - ) - except RuntimeError: - pass - - event["transaction"] = name - event["transaction_info"] = {"source": SEGMENT_SOURCE_FOR_STYLE[transaction_style]} def _make_request_event_processor( app: "Bottle", request: "LocalRequest", integration: "BottleIntegration" ) -> "EventProcessor": def event_processor(event: "Event", hint: "dict[str, Any]") -> "Event": - _set_transaction_name_and_source(event, integration.transaction_style, request) + name = _get_transaction_name(integration.transaction_style, request) + event["transaction"] = name + event["transaction_info"] = { + "source": SEGMENT_SOURCE_FOR_STYLE[integration.transaction_style] + } with capture_internal_exceptions(): BottleRequestExtractor(request).extract_into_event(event) From ebb39c184a28cd520d47e0d99680764796d5a448 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 21 Sep 2026 11:23:15 +0200 Subject: [PATCH 3/3] . --- sentry_sdk/integrations/bottle.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/bottle.py b/sentry_sdk/integrations/bottle.py index 90561956e1..51c9ba6d2e 100644 --- a/sentry_sdk/integrations/bottle.py +++ b/sentry_sdk/integrations/bottle.py @@ -195,15 +195,15 @@ def size_of_file(self, file: "FileUpload") -> int: def _get_transaction_name(transaction_style: str, request: "Any") -> str: try: if transaction_style == "url": - return request.route.rule or "" + return request.route.rule or "bottle request" else: return ( request.route.name or transaction_from_function(request.route.callback) - or "" + or "bottle request" ) except RuntimeError: - return "" + return "bottle request" def _set_segment_name_and_source(transaction_style: str) -> None: