Browse Source

feat(mep): Add some sentry spans around the mep code (#33078)

- This adds some spans around the bits of MEP code so we can see how
  different parts are doing performance wise
- This also adds the use_metrics tag to eventsv2 & sets it to false with
  a tagged reason if we are running a non-mep query
William Mak 2 years ago
parent
commit
088d352ca9

+ 2 - 0
src/sentry/api/endpoints/organization_events.py

@@ -1,5 +1,6 @@
 import logging
 
+import sentry_sdk
 from rest_framework.exceptions import ParseError
 from rest_framework.request import Request
 from rest_framework.response import Response
@@ -56,6 +57,7 @@ class OrganizationEventsV2Endpoint(OrganizationEventsV2EndpointBase):
             "organizations:performance-use-metrics", organization=organization, actor=request.user
         )
         metrics_enhanced = request.GET.get("metricsEnhanced") == "1" and performance_use_metrics
+        sentry_sdk.set_tag("performance.metrics_enhanced", metrics_enhanced)
         allow_metric_aggregates = request.GET.get("preventMetricAggregates") != "1"
         referrer = (
             referrer if referrer in ALLOWED_EVENTS_V2_REFERRERS else "api.organization-events-v2"

+ 1 - 1
src/sentry/api/endpoints/organization_events_stats.py

@@ -142,7 +142,7 @@ class OrganizationEventsStatsEndpoint(OrganizationEventsV2EndpointBase):  # type
 
             metrics_enhanced = request.GET.get("metricsEnhanced") == "1" and performance_use_metrics
             allow_metric_aggregates = request.GET.get("preventMetricAggregates") != "1"
-            sentry_sdk.set_tag("performance.use_metrics", metrics_enhanced)
+            sentry_sdk.set_tag("performance.metrics_enhanced", metrics_enhanced)
 
         def get_event_stats(
             query_columns: Sequence[str],

+ 22 - 8
src/sentry/search/events/builder.py

@@ -154,14 +154,19 @@ class QueryBuilder:
         equations: Optional[List[str]] = None,
         orderby: Optional[List[str]] = None,
     ) -> None:
-        self.where, self.having = self.resolve_conditions(
-            query, use_aggregate_conditions=use_aggregate_conditions
-        )
-        # params depends on parse_query, and conditions being resolved first since there may be projects in conditions
-        self.where += self.resolve_params()
-        self.columns = self.resolve_select(selected_columns, equations)
-        self.orderby = self.resolve_orderby(orderby)
-        self.groupby = self.resolve_groupby()
+        with sentry_sdk.start_span(op="QueryBuilder", description="resolve_conditions"):
+            self.where, self.having = self.resolve_conditions(
+                query, use_aggregate_conditions=use_aggregate_conditions
+            )
+        with sentry_sdk.start_span(op="QueryBuilder", description="resolve_params"):
+            # params depends on parse_query, and conditions being resolved first since there may be projects in conditions
+            self.where += self.resolve_params()
+        with sentry_sdk.start_span(op="QueryBuilder", description="resolve_columns"):
+            self.columns = self.resolve_select(selected_columns, equations)
+        with sentry_sdk.start_span(op="QueryBuilder", description="resolve_orderby"):
+            self.orderby = self.resolve_orderby(orderby)
+        with sentry_sdk.start_span(op="QueryBuilder", description="resolve_groupby"):
+            self.groupby = self.resolve_groupby()
 
     def load_config(
         self,
@@ -242,9 +247,13 @@ class QueryBuilder:
         query: Optional[str],
         use_aggregate_conditions: bool,
     ) -> Tuple[List[WhereType], List[WhereType]]:
+        sentry_sdk.set_tag("query.query_string", query if query else "<No Query>")
+        sentry_sdk.set_tag("query.use_aggregate_conditions", use_aggregate_conditions)
         parsed_terms = self.parse_query(query)
 
         self.has_or_condition = any(SearchBoolean.is_or_operator(term) for term in parsed_terms)
+        sentry_sdk.set_tag("query.has_or_condition", self.has_or_condition)
+
         if any(
             isinstance(term, ParenExpression) or SearchBoolean.is_operator(term)
             for term in parsed_terms
@@ -253,6 +262,10 @@ class QueryBuilder:
         else:
             where = self.resolve_where(parsed_terms)
             having = self.resolve_having(parsed_terms, use_aggregate_conditions)
+
+        sentry_sdk.set_tag("query.has_having_conditions", len(having) > 0)
+        sentry_sdk.set_tag("query.has_where_conditions", len(where) > 0)
+
         return where, having
 
     def resolve_boolean_conditions(
@@ -399,6 +412,7 @@ class QueryBuilder:
         resolved_columns = []
         stripped_columns = [column.strip() for column in set(selected_columns)]
 
+        sentry_sdk.set_tag("query.has_equations", equations is not None and len(equations) > 0)
         if equations:
             _, _, parsed_equations = resolve_equation_list(
                 equations, stripped_columns, use_snql=True, **self.equation_config

+ 32 - 23
src/sentry/snuba/metrics_enhanced_performance.py

@@ -1,6 +1,7 @@
 from datetime import timedelta
 from typing import Any, Dict, List, Optional, Sequence
 
+import sentry_sdk
 from snuba_sdk import AliasedExpression
 
 from sentry.discover.arithmetic import categorize_columns
@@ -15,19 +16,20 @@ def resolve_tags(results: Any, metrics_query: MetricsQueryBuilder) -> Any:
     """Go through the results of a metrics query and reverse resolve its tags"""
     tags: List[str] = []
 
-    for column in metrics_query.columns:
-        if (
-            isinstance(column, AliasedExpression)
-            and column.exp.subscriptable == "tags"
-            and column.alias
-        ):
-            tags.append(column.alias)
-
-    for tag in tags:
-        for row in results["data"]:
-            row[tag] = indexer.reverse_resolve(row[tag])
-        if tag in results["meta"]:
-            results["meta"][tag] = "string"
+    with sentry_sdk.start_span(op="mep", description="resolve_tags"):
+        for column in metrics_query.columns:
+            if (
+                isinstance(column, AliasedExpression)
+                and column.exp.subscriptable == "tags"
+                and column.alias
+            ):
+                tags.append(column.alias)
+
+        for tag in tags:
+            for row in results["data"]:
+                row[tag] = indexer.reverse_resolve(row[tag])
+            if tag in results["meta"]:
+                results["meta"][tag] = "string"
 
     return results
 
@@ -70,23 +72,27 @@ def query(
                 limit=limit,
                 offset=offset,
             )
-            # Getting the 0th result for now, will need to consolidate multiple query results later
-            results = metrics_query.run_query(referrer + ".metrics-enhanced")
-            results = discover.transform_results(
-                results, metrics_query.function_alias_map, {}, None
-            )
-            results = resolve_tags(results, metrics_query)
-            results["meta"]["isMetricsData"] = True
-            return results
+            with sentry_sdk.start_span(op="mep", description="query.transform_results"):
+                # Getting the 0th result for now, will need to consolidate multiple query results later
+                results = metrics_query.run_query(referrer + ".metrics-enhanced")
+                results = discover.transform_results(
+                    results, metrics_query.function_alias_map, {}, None
+                )
+                results = resolve_tags(results, metrics_query)
+                results["meta"]["isMetricsData"] = True
+                sentry_sdk.set_tag("performance.dataset", "metrics")
+                return results
         # raise Invalid Queries since the same thing will happen with discover
         except InvalidSearchQuery as error:
             raise error
         # any remaining errors mean we should try again with discover
-        except IncompatibleMetricsQuery:
+        except IncompatibleMetricsQuery as error:
+            sentry_sdk.set_tag("performance.mep_incompatible", str(error))
             metrics_compatible = False
 
     # Either metrics failed, or this isn't a query we can enhance with metrics
     if not metrics_compatible:
+        sentry_sdk.set_tag("performance.dataset", "discover")
         results = discover.query(
             selected_columns,
             query,
@@ -155,6 +161,7 @@ def timeseries_query(
                 if zerofill_results
                 else result["data"]
             )
+            sentry_sdk.set_tag("performance.dataset", "metrics")
             return SnubaTSResult(
                 {"data": result["data"], "isMetricsData": True},
                 params["start"],
@@ -165,11 +172,13 @@ def timeseries_query(
         except InvalidSearchQuery as error:
             raise error
         # any remaining errors mean we should try again with discover
-        except IncompatibleMetricsQuery:
+        except IncompatibleMetricsQuery as error:
+            sentry_sdk.set_tag("performance.mep_incompatible", str(error))
             metrics_compatible = False
 
     # This isn't a query we can enhance with metrics
     if not metrics_compatible:
+        sentry_sdk.set_tag("performance.dataset", "discover")
         return discover.timeseries_query(
             selected_columns,
             query,