From 1902e81dbb518eb68f38d2be37c1c2a20266e9e0 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 29 Apr 2024 16:19:22 +0200 Subject: [PATCH 1/3] Make os.distribution searchable --- .../rules/conditions/event_attribute.py | 16 ++++++++ src/sentry/snuba/events.py | 16 ++++++++ .../rules/conditions/test_event_attribute.py | 40 +++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/sentry/rules/conditions/event_attribute.py b/src/sentry/rules/conditions/event_attribute.py index 69e84c6aa5b067..9da3d5e632de57 100644 --- a/src/sentry/rules/conditions/event_attribute.py +++ b/src/sentry/rules/conditions/event_attribute.py @@ -39,6 +39,8 @@ "stacktrace.package": Columns.STACK_PACKAGE, "unreal.crashtype": Columns.UNREAL_CRASH_TYPE, "app.in_foreground": Columns.APP_IN_FOREGROUND, + "os.distribution.name": Columns.OS_DISTRIBUTION_NAME, + "os.distribution.version": Columns.OS_DISTRIBUTION_VERSION, } @@ -209,6 +211,20 @@ def _get_attribute_values(self, event: GroupEvent, attr: str) -> Sequence[object response = {} return [response.get(path[1])] + elif path[0] == "os": + if path[1] in ("distribution"): + if path[2] in ("name", "version"): + contexts = event.data["contexts"] + os_context = contexts.get("os") + if os_context is None: + os_context = {} + + distribution = os_context.get(path[1]) + if distribution is None: + distribution = {} + + return [distribution.get(path[2])] + return [] return [] return [] diff --git a/src/sentry/snuba/events.py b/src/sentry/snuba/events.py index 73480b1eb5fead..47e7aee6650d6e 100644 --- a/src/sentry/snuba/events.py +++ b/src/sentry/snuba/events.py @@ -600,6 +600,22 @@ class Columns(Enum): issue_platform_name="contexts[app.in_foreground]", alias="app.in_foreground", ) + OS_DISTRIBUTION_NAME = Column( + group_name="events.contexts[os.distribution.name]", + event_name="contexts[os.distribution.name]", + transaction_name="contexts[os.distribution.name]", + discover_name="contexts[os.distribution.name]", + issue_platform_name="contexts[os.distribution.name]", + alias="os.distribution.name", + ) + OS_DISTRIBUTION_VERSION = Column( + group_name="events.contexts[os.distribution.version]", + event_name="contexts[os.distribution.version]", + transaction_name="contexts[os.distribution.version]", + discover_name="contexts[os.distribution.version]", + issue_platform_name="contexts[os.distribution.version]", + alias="os.distribution.version", + ) # Transactions specific columns TRANSACTION_OP = Column( group_name=None, diff --git a/tests/sentry/rules/conditions/test_event_attribute.py b/tests/sentry/rules/conditions/test_event_attribute.py index 2f43d1d181d833..0681859784b30a 100644 --- a/tests/sentry/rules/conditions/test_event_attribute.py +++ b/tests/sentry/rules/conditions/test_event_attribute.py @@ -59,6 +59,12 @@ def get_event(self, **kwargs): "unreal": { "crash_type": "crash", }, + "os": { + "distribution": { + "name": "ubuntu", + "version": "22.04", + } + }, }, "threads": { "values": [ @@ -757,6 +763,40 @@ def test_app_in_foreground(self): ) self.assertDoesNotPass(rule, event) + def test_os_distribution(self): + event = self.get_event() + rule = self.get_rule( + data={"match": MatchType.EQUAL, "attribute": "os.distribution.name", "value": "ubuntu"} + ) + self.assertPasses(rule, event) + + rule = self.get_rule( + data={ + "match": MatchType.EQUAL, + "attribute": "os.distribution.version", + "value": "22.04", + } + ) + self.assertPasses(rule, event) + + rule = self.get_rule( + data={ + "match": MatchType.EQUAL, + "attribute": "os.distribution.name", + "value": "slackware", + } + ) + self.assertDoesNotPass(rule, event) + + rule = self.get_rule( + data={ + "match": MatchType.EQUAL, + "attribute": "os.distribution.version", + "value": "20.04", + } + ) + self.assertDoesNotPass(rule, event) + def test_unreal_crash_type(self): event = self.get_event() rule = self.get_rule( From 6a2bad065ce330faf1b440e405ec0e6d81531af6 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 29 Apr 2024 19:20:28 +0200 Subject: [PATCH 2/3] Allow event attributes with 3 path elements --- src/sentry/rules/conditions/event_attribute.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/rules/conditions/event_attribute.py b/src/sentry/rules/conditions/event_attribute.py index 9da3d5e632de57..a14cc9f78a7755 100644 --- a/src/sentry/rules/conditions/event_attribute.py +++ b/src/sentry/rules/conditions/event_attribute.py @@ -114,7 +114,7 @@ def _get_attribute_values(self, event: GroupEvent, attr: str) -> Sequence[object return value return [value] - elif len(path) != 2: + elif len(path) < 2 or len(path) > 3: return [] elif path[0] == "exception": From d70586400d308d0bda9a7c516847a7f79f8bed18 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 6 May 2024 16:37:34 +0200 Subject: [PATCH 3/3] correctly delimit attribute path-length in the event condition parser --- src/sentry/rules/conditions/event_attribute.py | 7 +++++-- tests/sentry/rules/conditions/test_event_attribute.py | 9 ++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sentry/rules/conditions/event_attribute.py b/src/sentry/rules/conditions/event_attribute.py index a14cc9f78a7755..f3cdbd12eccc45 100644 --- a/src/sentry/rules/conditions/event_attribute.py +++ b/src/sentry/rules/conditions/event_attribute.py @@ -114,8 +114,8 @@ def _get_attribute_values(self, event: GroupEvent, attr: str) -> Sequence[object return value return [value] - elif len(path) < 2 or len(path) > 3: - return [] + elif len(path) < 2: + return [] # all attribute paths below have at least 2 elements elif path[0] == "exception": if path[1] not in ("type", "value"): @@ -211,6 +211,9 @@ def _get_attribute_values(self, event: GroupEvent, attr: str) -> Sequence[object response = {} return [response.get(path[1])] + elif len(path) < 3: + return [] # all attribute paths below have at least 3 elements + elif path[0] == "os": if path[1] in ("distribution"): if path[2] in ("name", "version"): diff --git a/tests/sentry/rules/conditions/test_event_attribute.py b/tests/sentry/rules/conditions/test_event_attribute.py index 0681859784b30a..3fb3e190e3643a 100644 --- a/tests/sentry/rules/conditions/test_event_attribute.py +++ b/tests/sentry/rules/conditions/test_event_attribute.py @@ -763,7 +763,14 @@ def test_app_in_foreground(self): ) self.assertDoesNotPass(rule, event) - def test_os_distribution(self): + def test_os_distribution_only(self): + event = self.get_event() + rule = self.get_rule( + data={"match": MatchType.EQUAL, "attribute": "os.distribution", "value": "irrelevant"} + ) + self.assertDoesNotPass(rule, event) + + def test_os_distribution_name_and_version(self): event = self.get_event() rule = self.get_rule( data={"match": MatchType.EQUAL, "attribute": "os.distribution.name", "value": "ubuntu"}