Skip to content

Instantly share code, notes, and snippets.

@wmak
Created January 9, 2023 15:54
Show Gist options
  • Save wmak/18bea8802be2a4e3258bdd5b2941381d to your computer and use it in GitHub Desktop.
Save wmak/18bea8802be2a4e3258bdd5b2941381d to your computer and use it in GitHub Desktop.
diff --git a/src/sentry/search/events/builder/metrics.py b/src/sentry/search/events/builder/metrics.py
index 019653f227..4e1afa4e53 100644
--- a/src/sentry/search/events/builder/metrics.py
+++ b/src/sentry/search/events/builder/metrics.py
@@ -43,6 +43,7 @@ from sentry.utils.snuba import DATASETS, Dataset, bulk_snql_query, raw_snql_quer
class MetricsQueryBuilder(QueryBuilder):
requires_organization_condition = True
+ is_alerts_query = False
organization_column: str = "organization_id"
def __init__(
@@ -597,42 +598,40 @@ class MetricsQueryBuilder(QueryBuilder):
) or (isinstance(orderby.exp, Function) and orderby.exp.alias == "title"):
raise IncompatibleMetricsQuery("Can't orderby tags")
- def _run_query_with_metrics_layer(self, query: Query, is_alerts_query: bool = False) -> Any:
- from sentry.snuba.metrics.datasource import get_series
- from sentry.snuba.metrics.mqb_query_transformer import transform_mqb_query_to_metrics_query
-
- try:
- with sentry_sdk.start_span(op="metric_layer", description="transform_query"):
- metric_query = transform_mqb_query_to_metrics_query(query, is_alerts_query)
- with sentry_sdk.start_span(op="metric_layer", description="run_query"):
- metrics_data = get_series(
- projects=self.params.projects,
- metrics_query=metric_query,
- use_case_id=UseCaseKey.PERFORMANCE
- if self.is_performance
- else UseCaseKey.RELEASE_HEALTH,
- include_meta=True,
- )
- except Exception as err:
- raise IncompatibleMetricsQuery(err)
- with sentry_sdk.start_span(op="metric_layer", description="transform_results"):
- # series does some strange stuff to the clickhouse response, turn it back so we can handle it
- metric_layer_result: Any = {
- "data": [],
- "meta": metrics_data["meta"],
- }
- for group in metrics_data["groups"]:
- data = group["by"]
- data.update(group["totals"])
- metric_layer_result["data"].append(data)
- for meta in metric_layer_result["meta"]:
- if data[meta["name"]] is None:
- data[meta["name"]] = self.get_default_value(meta["type"])
- return metric_layer_result
-
def run_query(self, referrer: str, use_cache: bool = False) -> Any:
if self.use_metrics_layer:
- return self._run_query_with_metrics_layer(query=self.get_snql_query().query)
+ from sentry.snuba.metrics.datasource import get_series
+ from sentry.snuba.metrics.mqb_query_transformer import transform_mqb_query_to_metrics_query
+
+ snuba_query = self.get_snql_query().query
+ try:
+ with sentry_sdk.start_span(op="metric_layer", description="transform_query"):
+ metric_query = transform_mqb_query_to_metrics_query(snuba_query, self.is_alerts_query)
+ with sentry_sdk.start_span(op="metric_layer", description="run_query"):
+ metrics_data = get_series(
+ projects=self.params.projects,
+ metrics_query=metric_query,
+ use_case_id=UseCaseKey.PERFORMANCE
+ if self.is_performance
+ else UseCaseKey.RELEASE_HEALTH,
+ include_meta=True,
+ )
+ except Exception as err:
+ raise IncompatibleMetricsQuery(err)
+ with sentry_sdk.start_span(op="metric_layer", description="transform_results"):
+ # series does some strange stuff to the clickhouse response, turn it back so we can handle it
+ metric_layer_result: Any = {
+ "data": [],
+ "meta": metrics_data["meta"],
+ }
+ for group in metrics_data["groups"]:
+ data = group["by"]
+ data.update(group["totals"])
+ metric_layer_result["data"].append(data)
+ for meta in metric_layer_result["meta"]:
+ if data[meta["name"]] is None:
+ data[meta["name"]] = self.get_default_value(meta["type"])
+ return metric_layer_result
self.validate_having_clause()
self.validate_orderby_clause()
@@ -759,6 +758,8 @@ class MetricsQueryBuilder(QueryBuilder):
class AlertMetricsQueryBuilder(MetricsQueryBuilder):
+ is_alerts_query = True
+
def __init__(
self,
*args: Any,
@@ -774,50 +775,33 @@ class AlertMetricsQueryBuilder(MetricsQueryBuilder):
def resolve_granularity(self) -> Granularity:
return Granularity(self._granularity)
- def _get_snql_using_metrics_layer(self, snuba_request: Request) -> Request:
- # We use directly the query builder which is not a good practice, considering that the metrics layer
- # should hide snql generation.
- from sentry.snuba.metrics import SnubaQueryBuilder
- from sentry.snuba.metrics.mqb_query_transformer import transform_mqb_query_to_metrics_query
-
- snuba_queries, _ = SnubaQueryBuilder(
- projects=self.params.projects,
- metrics_query=transform_mqb_query_to_metrics_query(
- snuba_request.query, is_alerts_query=True
- ),
- use_case_id=UseCaseKey.PERFORMANCE
- if self.is_performance
- else UseCaseKey.RELEASE_HEALTH,
- ).get_snuba_queries()
-
- if len(snuba_queries) == 0 or len(snuba_queries) > 1:
- raise NotImplementedError(
- "get_snql_query cannot be implemented for MetricsQueryBuilder"
- )
-
- # We take only the first query, supposing a single query is generated.
- entity = list(snuba_queries.keys())[0]
- snuba_request.query = snuba_queries[entity]["totals"]
-
- return snuba_request
-
- def run_query(self, referrer: str, use_cache: bool = False) -> Any:
- if self.use_metrics_layer:
- # We have to copy the entire code of the run query here, because of how the get_snql_query() method
- # behaves. The get_snql_query() of MetricsQueryBuilder returns a snql query that is understood by the mqb
- # transformer. If we were to call get_snql_query() of this class, we would already get snql generated
- # by the metrics layer, which is not understood by the transformer.
- snuba_query = super().get_snql_query().query
- return self._run_query_with_metrics_layer(query=snuba_query, is_alerts_query=True)
-
- return super().run_query(referrer, use_cache)
-
def get_snql_query(self) -> Request:
request = super().get_snql_query()
if self.use_metrics_layer:
- # Generate through metrics layer
- request = self._get_snql_using_metrics_layer(request)
+ # We use directly the query builder which is not a good practice, considering that the metrics layer
+ # should hide snql generation.
+ from sentry.snuba.metrics import SnubaQueryBuilder
+ from sentry.snuba.metrics.mqb_query_transformer import transform_mqb_query_to_metrics_query
+
+ snuba_queries, _ = SnubaQueryBuilder(
+ projects=self.params.projects,
+ metrics_query=transform_mqb_query_to_metrics_query(
+ request.query, is_alerts_query=True
+ ),
+ use_case_id=UseCaseKey.PERFORMANCE
+ if self.is_performance
+ else UseCaseKey.RELEASE_HEALTH,
+ ).get_snuba_queries()
+
+ if len(snuba_queries) == 0 or len(snuba_queries) > 1:
+ raise NotImplementedError(
+ "get_snql_query cannot be implemented for MetricsQueryBuilder"
+ )
+
+ # We take only the first query, supposing a single query is generated.
+ entity = list(snuba_queries.keys())[0]
+ request.query = snuba_queries[entity]["totals"]
return request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment