From 4b6b0df246c419809dd39cac4a42d0317ee79633 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Fri, 16 May 2025 14:02:51 -0700 Subject: [PATCH 1/3] add helper to combine hints --- src/sentry/grouping/enhancer/__init__.py | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sentry/grouping/enhancer/__init__.py b/src/sentry/grouping/enhancer/__init__.py index 01636bd5c595c7..2466de484c7775 100644 --- a/src/sentry/grouping/enhancer/__init__.py +++ b/src/sentry/grouping/enhancer/__init__.py @@ -257,6 +257,46 @@ def _split_rules( ) +def _combine_hints( + variant_name: str, + frame_component: FrameGroupingComponent, + in_app_hint: str | None, + contributes_hint: str | None, +) -> str | None: + """ + Given possible in-app and contributes hints, determine the frame's final hint. + """ + frame_type = "in-app" if frame_component.in_app else "system" + + # In-app hints never apply to the system stacktrace, so even if the contributes hint is `None`, + # it's the one we want + if variant_name == "system": + return contributes_hint + + # From here on out everything we're doing is for the app variant + + # System frames never contribute to the app stacktrace, so if they've already been marked out of + # app, we don't care whether or not they're ignored (or un-ignored), because they weren't going + # to count anyway. + if frame_type == "system": + return in_app_hint + + # If only one hint exists, return that one + if in_app_hint and not contributes_hint: + return in_app_hint + if contributes_hint and not in_app_hint: + return contributes_hint + + # If neither hint exists, return None + if not in_app_hint and not contributes_hint: + return None + + # Combine the hints in such as way that we get "marked in-app by xxx AND un-ignored by yyy" and + # "marked in-app by xxx BUT ignored by yyy" + conjunction = "and" if frame_component.contributes else "but" + return f"{in_app_hint} {conjunction} {contributes_hint}" + + def is_valid_profiling_matcher(matchers: list[str]) -> bool: for matcher in matchers: if not matcher.startswith(VALID_PROFILING_MATCHER_PREFIXES): From 474788de1383a11978fe3d2e67039d01b8b895f4 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Fri, 16 May 2025 14:02:53 -0700 Subject: [PATCH 2/3] update `contributes` before getting hint --- src/sentry/grouping/enhancer/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sentry/grouping/enhancer/__init__.py b/src/sentry/grouping/enhancer/__init__.py index 2466de484c7775..3f802a0ad7944a 100644 --- a/src/sentry/grouping/enhancer/__init__.py +++ b/src/sentry/grouping/enhancer/__init__.py @@ -723,6 +723,8 @@ def assemble_stacktrace_component( else: contributes = rust_frame.contributes + frame_component.update(contributes=contributes) + hint = get_hint_for_frame(variant_name, frame, frame_component, rust_frame) if self.run_split_enhancements: split_in_app_hint = ( @@ -736,7 +738,7 @@ def assemble_stacktrace_component( variant_name, frame, frame_component, contributes_rust_frame, "contributes" ) - frame_component.update(contributes=contributes, hint=hint) + frame_component.update(hint=hint) # Add this frame to our tally key = f"{"in_app" if frame_component.in_app else "system"}_{"contributing" if frame_component.contributes else "non_contributing"}_frames" From 84f1d026a8be2aef258f63027ae44013d00a0960 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Fri, 16 May 2025 14:02:55 -0700 Subject: [PATCH 3/3] add test for combining hints --- .../grouping/enhancements/test_hints.py | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/sentry/grouping/enhancements/test_hints.py b/tests/sentry/grouping/enhancements/test_hints.py index 2962ef8547444d..c0e0d7e0c0417e 100644 --- a/tests/sentry/grouping/enhancements/test_hints.py +++ b/tests/sentry/grouping/enhancements/test_hints.py @@ -6,7 +6,7 @@ import pytest from sentry.grouping.component import FrameGroupingComponent -from sentry.grouping.enhancer import get_hint_for_frame +from sentry.grouping.enhancer import _combine_hints, get_hint_for_frame @dataclass @@ -431,3 +431,35 @@ def test_get_hint_for_frame( get_hint_for_frame(variant_name, frame, frame_component, rust_frame, desired_hint_type) # type: ignore[arg-type] == expected_result ) + + +@pytest.mark.parametrize( + ["variant_name", "in_app", "contributes", "in_app_hint", "contributes_hint", "expected_result"], + [ + ("app", True, True, in_app_hint, None, in_app_hint), + ("app", True, True, in_app_hint, unignored_hint, f"{in_app_hint} and {unignored_hint}"), + ("app", True, False, in_app_hint, ignored_hint, f"{in_app_hint} but {ignored_hint}"), + ("app", False, True, out_of_app_hint, None, out_of_app_hint), + ("app", False, True, out_of_app_hint, unignored_hint, out_of_app_hint), + ("app", False, False, out_of_app_hint, ignored_hint, out_of_app_hint), + ("system", True, True, None, None, None), + ("system", True, True, None, unignored_hint, unignored_hint), + ("system", True, False, None, ignored_hint, ignored_hint), + ("system", False, True, None, None, None), + ("system", False, True, None, unignored_hint, unignored_hint), + ("system", False, False, None, ignored_hint, ignored_hint), + ], +) +def test_combining_hints( + variant_name, + in_app, + contributes, + in_app_hint, + contributes_hint, + expected_result, +): + frame_component = FrameGroupingComponent(in_app=in_app, contributes=contributes, values=[]) + assert ( + _combine_hints(variant_name, frame_component, in_app_hint, contributes_hint) + == expected_result + )