Browse Source

chore(metrics): Allow wildcards in performance (#41103)

- This removes the tag value option since we're now fully on using tag
values as strings instead of indexed integers
- This is needed so we can start on wildcard searching
William Mak 2 years ago
parent
commit
7c64fd2469

+ 7 - 3
src/sentry/search/events/builder/metrics.py

@@ -332,9 +332,6 @@ class MetricsQueryBuilder(QueryBuilder):
         return self.resolve_metric_index(value)
 
     def _default_filter_converter(self, search_filter: SearchFilter) -> Optional[WhereType]:
-        if search_filter.value.is_wildcard():
-            raise IncompatibleMetricsQuery("wildcards not supported")
-
         name = search_filter.key.name
         operator = search_filter.operator
         value = search_filter.value.value
@@ -386,6 +383,13 @@ class MetricsQueryBuilder(QueryBuilder):
                     1,
                 )
 
+        if search_filter.value.is_wildcard():
+            return Condition(
+                Function("match", [lhs, f"(?i){value}"]),
+                Op(search_filter.operator),
+                1,
+            )
+
         return Condition(lhs, Op(search_filter.operator), value)
 
     def _resolve_environment_filter_value(self, value: str) -> Union[int, str]:

+ 7 - 0
src/sentry/search/events/datasets/metrics.py

@@ -743,6 +743,13 @@ class MetricsDatasetConfig(DatasetConfig):
                 raise IncompatibleMetricsQuery(f"Transaction value {value} in filter not found")
         value = resolved_value
 
+        if search_filter.value.is_wildcard():
+            return Condition(
+                Function("match", [self.builder.resolve_column("transaction"), f"(?i){value}"]),
+                Op(search_filter.operator),
+                1,
+            )
+
         return Condition(self.builder.resolve_column("transaction"), Op(operator), value)
 
     # Query Functions

+ 7 - 0
src/sentry/search/events/datasets/metrics_layer.py

@@ -472,6 +472,13 @@ class MetricsLayerDatasetConfig(MetricsDatasetConfig):
                 raise IncompatibleMetricsQuery(f"Transaction value {value} in filter not found")
         value = resolved_value
 
+        if search_filter.value.is_wildcard():
+            return Condition(
+                Function("match", [self.builder.resolve_column("transaction"), f"(?i){value}"]),
+                Op(search_filter.operator),
+                1,
+            )
+
         return Condition(self.builder.resolve_column("transaction"), Op(operator), value)
 
     # Query Functions

+ 54 - 0
tests/snuba/api/endpoints/test_organization_events_mep.py

@@ -1929,6 +1929,60 @@ class OrganizationEventsMetricsEnhancedPerformanceEndpointTest(MetricsEnhancedPe
         meta = response.data["meta"]
         assert not meta["isMetricsData"]
 
+    def test_transaction_wildcard(self):
+        self.store_transaction_metric(
+            1,
+            tags={"transaction": "foo_transaction"},
+            timestamp=self.min_ago,
+        )
+        self.store_transaction_metric(
+            1,
+            tags={"transaction": "bar_transaction"},
+            timestamp=self.min_ago,
+        )
+        response = self.do_request(
+            {
+                "field": [
+                    "transaction",
+                    "p90()",
+                ],
+                "query": "transaction:foo*",
+                "dataset": "metrics",
+            }
+        )
+        assert response.status_code == 200, response.content
+        data = response.data["data"]
+        assert len(data) == 1
+        assert data[0]["p90()"] == 1
+
+        meta = response.data["meta"]
+        assert meta["isMetricsData"]
+        assert data[0]["transaction"] == "foo_transaction"
+
+    def test_transaction_status_wildcard(self):
+        self.store_transaction_metric(
+            1,
+            tags={"transaction": "foo_transaction", "transaction.status": "foobar"},
+            timestamp=self.min_ago,
+        )
+        response = self.do_request(
+            {
+                "field": [
+                    "transaction",
+                    "p90()",
+                ],
+                "query": "transaction.status:f*bar",
+                "dataset": "metrics",
+            }
+        )
+        assert response.status_code == 200, response.content
+        data = response.data["data"]
+        assert len(data) == 1
+        assert data[0]["p90()"] == 1
+
+        meta = response.data["meta"]
+        assert meta["isMetricsData"]
+
 
 class OrganizationEventsMetricsEnhancedPerformanceEndpointTestWithMetricLayer(
     OrganizationEventsMetricsEnhancedPerformanceEndpointTest