Browse Source

fix(spansIndexed): Lowercase span op and description filters (#67753)

- Lower cases the filters on op and description since they're lowercased
on ingest that way they can be easily filtered regardless of their case
when sent to us
William Mak 11 months ago
parent
commit
344aa102e7

+ 2 - 0
src/sentry/search/events/constants.py

@@ -49,6 +49,8 @@ SPAN_DOMAIN_ALIAS = "span.domain"
 SPAN_DOMAIN_SEPARATOR = ","
 UNIQUE_SPAN_DOMAIN_ALIAS = "unique.span_domains"
 SPAN_IS_SEGMENT_ALIAS = "span.is_segment"
+SPAN_OP = "span.op"
+SPAN_DESCRIPTION = "span.description"
 
 
 class ThresholdDict(TypedDict):

+ 10 - 0
src/sentry/search/events/datasets/filter_aliases.py

@@ -299,3 +299,13 @@ def device_class_converter(
     if value not in device_class_map:
         raise InvalidSearchQuery(f"{value} is not a supported device.class")
     return Condition(builder.column("device.class"), Op.IN, list(device_class_map[value]))
+
+
+def lowercase_search(
+    builder: builder.QueryBuilder, search_filter: SearchFilter
+) -> WhereType | None:
+    """Convert the search value to lower case"""
+    value = search_filter.value.value
+    return builder.default_filter_converter(
+        SearchFilter(search_filter.key, search_filter.operator, SearchValue(value.lower()))
+    )

+ 6 - 0
src/sentry/search/events/datasets/spans_indexed.py

@@ -39,6 +39,12 @@ class SpansIndexedDatasetConfig(DatasetConfig):
             constants.PROJECT_NAME_ALIAS: self._project_slug_filter_converter,
             constants.DEVICE_CLASS_ALIAS: self._device_class_filter_converter,
             constants.SPAN_IS_SEGMENT_ALIAS: filter_aliases.span_is_segment_converter,
+            constants.SPAN_OP: lambda search_filter: filter_aliases.lowercase_search(
+                self.builder, search_filter
+            ),
+            constants.SPAN_DESCRIPTION: lambda search_filter: filter_aliases.lowercase_search(
+                self.builder, search_filter
+            ),
         }
 
     @property

+ 33 - 0
tests/snuba/api/endpoints/test_organization_events_span_indexed.py

@@ -191,3 +191,36 @@ class OrganizationEventsSpanIndexedEndpointTest(OrganizationEventsEndpointTestBa
         assert data[0]["browser.name"] == "Chrome"
         assert data[0]["origin.transaction"] == "/pageloads/"
         assert meta["dataset"] == "spansIndexed"
+
+    def test_span_op_casing(self):
+        self.store_spans(
+            [
+                self.create_span(
+                    {
+                        "sentry_tags": {
+                            "replay_id": "abc123",
+                            "browser.name": "Chrome",
+                            "transaction": "/pageloads/",
+                            "op": "this is a transaction",
+                        }
+                    },
+                    start_ts=self.ten_mins_ago,
+                ),
+            ]
+        )
+        response = self.do_request(
+            {
+                "field": ["span.op", "count()"],
+                "query": 'span.op:"ThIs Is a TraNSActiON"',
+                "orderby": "count()",
+                "project": self.project.id,
+                "dataset": "spansIndexed",
+            }
+        )
+
+        assert response.status_code == 200, response.content
+        data = response.data["data"]
+        meta = response.data["meta"]
+        assert len(data) == 1
+        assert data[0]["span.op"] == "this is a transaction"
+        assert meta["dataset"] == "spansIndexed"