Browse Source

feat(metrics_extraction): Return isMetricsExtractedData in event-stats API (#60183)

When using on-demand metrics, we should return `isMetricsExtractedData:
true` in the `events-stat` API.

This is a follow-up to #60047 since we wanted to at least merge the
events API portion of it on that PR.
Armen Zambrano G 1 year ago
parent
commit
2f193c5efb

+ 19 - 0
src/sentry/api/bases/organization_events.py

@@ -525,6 +525,10 @@ class OrganizationEventsV2EndpointBase(OrganizationEventsEndpointBase):
                             zerofill_results=zerofill_results,
                             dataset=dataset,
                         )
+                        if request.query_params.get("useOnDemandMetrics") == "true":
+                            results[key]["isMetricsExtractedData"] = self._query_if_extracted_data(
+                                results, key, query_columns
+                            )
                     else:
                         results[key] = serializer.serialize(
                             event_result,
@@ -579,6 +583,21 @@ class OrganizationEventsV2EndpointBase(OrganizationEventsEndpointBase):
 
             return serialized_result
 
+    def _query_if_extracted_data(
+        self, results: dict[str, Any], key: str, query_columns: list[str]
+    ) -> bool:
+        ret_value = False
+        try:
+            for c in query_columns:
+                # At least one of the columns has required extracted data
+                if results[key][c].get("meta", {}).get("isMetricsExtractedData"):
+                    ret_value = True
+                    break
+        except Exception as error:
+            sentry_sdk.capture_exception(error)
+
+        return ret_value
+
     def serialize_multiple_axis(
         self,
         request: Request,

+ 6 - 0
src/sentry/snuba/metrics_performance.py

@@ -243,10 +243,13 @@ def timeseries_query(
             )
             sentry_sdk.set_tag("performance.dataset", "metrics")
             result["meta"]["isMetricsData"] = True
+            sentry_sdk.set_tag("on_demand.is_extracted", metrics_query.use_on_demand)
+            result["meta"]["isMetricsExtractedData"] = metrics_query.use_on_demand
 
             return {
                 "data": result["data"],
                 "isMetricsData": True,
+                "isMetricsExtractedData": metrics_query.use_on_demand,
                 "meta": result["meta"],
             }
 
@@ -440,6 +443,9 @@ def top_events_timeseries(
                 if zerofill_results
                 else item["data"],
                 "order": item["order"],
+                # One of the queries in the builder has required, thus, we mark all of them
+                # This could mislead downstream consumers of the meta data
+                "meta": {"isMetricsExtractedData": top_events_builder.use_on_demand},
             },
             params["start"],
             params["end"],

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

@@ -2637,19 +2637,6 @@ class OrganizationEventsMetricsEnhancedPerformanceEndpointTestWithOnDemandMetric
             dataset="metricsEnhanced",
         )
 
-    def test_is_metrics_extracted_data_is_excluded(self):
-        self._test_is_metrics_extracted_data(
-            {
-                "field": ["count()"],
-                "query": "transaction.duration:>=91",
-                "useOnDemandMetrics": "true",
-                "yAxis": "count()",
-            },
-            # Since we do not include metricsEnhanced dataset it will fail
-            expected_on_demand_query=False,
-            dataset="discover",
-        )
-
 
 class OrganizationEventsMetricsEnhancedPerformanceEndpointTestWithMetricLayer(
     OrganizationEventsMetricsEnhancedPerformanceEndpointTest

+ 44 - 2
tests/snuba/api/endpoints/test_organization_events_stats_mep.py

@@ -1,4 +1,7 @@
+from __future__ import annotations
+
 from datetime import timedelta
+from typing import Any
 from unittest import mock
 
 import pytest
@@ -1077,7 +1080,10 @@ class OrganizationEventsStatsMetricsEnhancedPerformanceEndpointTestWithOnDemand(
         for group_count in groups:
             group, agg, row1, row2 = group_count
             row_data = response.data[group][agg]["data"][:2]
-            assert [attrs for time, attrs in row_data] == [[{"count": row1}], [{"count": row2}]]
+            assert [attrs for _, attrs in row_data] == [[{"count": row1}], [{"count": row2}]]
+
+            assert response.data[group][agg]["meta"]["isMetricsExtractedData"]
+            assert response.data[group]["isMetricsExtractedData"]
 
     def test_top_events_with_transaction_on_demand_and_no_environment(self):
         field = "count()"
@@ -1149,4 +1155,40 @@ class OrganizationEventsStatsMetricsEnhancedPerformanceEndpointTestWithOnDemand(
         for group_count in groups:
             group, agg, row1, row2 = group_count
             row_data = response.data[group][agg]["data"][:2]
-            assert [attrs for time, attrs in row_data] == [[{"count": row1}], [{"count": row2}]]
+            assert [attrs for _, attrs in row_data] == [[{"count": row1}], [{"count": row2}]]
+
+            assert response.data[group][agg]["meta"]["isMetricsExtractedData"]
+            assert response.data[group]["isMetricsExtractedData"]
+
+    def _test_is_metrics_extracted_data(
+        self, params: dict[str, Any], expected_on_demand_query: bool, dataset: str
+    ) -> None:
+        features = {"organizations:on-demand-metrics-extraction": True}
+        spec = OnDemandMetricSpec(
+            field="count()",
+            query="transaction.duration:>1s",
+            spec_type=MetricSpecType.DYNAMIC_QUERY,
+        )
+
+        self.store_on_demand_metric(1, spec=spec)
+        response = self.do_request(params, features=features)
+
+        assert response.status_code == 200, response.content
+        meta = response.data["meta"]
+        # This is the main thing we want to test for
+        assert meta.get("isMetricsExtractedData", False) is expected_on_demand_query
+        assert meta["dataset"] == dataset
+
+        return meta
+
+    def test_is_metrics_extracted_data_is_included(self):
+        self._test_is_metrics_extracted_data(
+            {
+                "dataset": "metricsEnhanced",
+                "query": "transaction.duration:>=91",
+                "useOnDemandMetrics": "true",
+                "yAxis": "count()",
+            },
+            expected_on_demand_query=True,
+            dataset="metricsEnhanced",
+        )