Skip to content

Commit 9898dcb

Browse files
authored
feat(tracemetrics): Add metric into aggregate arguments (#102965)
The top level params doesn't play nicely with dashboards so we're putting the metric name into the aggregation function. This just introduces the new signatures so we can update the frontend but still relies on the top level params. Once the frontend is updated to send the metric in the aggregate function, we can update the backend to actually handle them.
1 parent 9a547bd commit 9898dcb

File tree

6 files changed

+444
-69
lines changed

6 files changed

+444
-69
lines changed

src/sentry/search/eap/columns.py

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ class AggregateDefinition(FunctionDefinition):
311311
An optional function that takes in the resolved argument and returns the attribute key to aggregate on.
312312
If not provided, assumes the aggregate is on the first argument.
313313
"""
314-
attribute_resolver: Callable[[ResolvedArguments], AttributeKey] | None = None
314+
attribute_resolver: Callable[[ResolvedArgument], AttributeKey] | None = None
315315

316316
def resolve(
317317
self,
@@ -334,7 +334,72 @@ def resolve(
334334
raise InvalidSearchQuery("Aggregates accept attribute keys only")
335335
resolved_attribute = resolved_arguments[0]
336336
if self.attribute_resolver is not None:
337-
resolved_attribute = self.attribute_resolver(resolved_arguments)
337+
resolved_attribute = self.attribute_resolver(resolved_attribute)
338+
339+
return ResolvedAggregate(
340+
public_alias=alias,
341+
internal_name=self.internal_function,
342+
search_type=search_type,
343+
internal_type=self.internal_type,
344+
processor=self.processor,
345+
extrapolation=(
346+
self.extrapolation if not search_config.disable_aggregate_extrapolation else False
347+
),
348+
argument=resolved_attribute,
349+
)
350+
351+
352+
@dataclass(kw_only=True)
353+
class TraceMetricAggregateDefinition(AggregateDefinition):
354+
internal_function: Function.ValueType
355+
attribute_resolver: Callable[[ResolvedArgument], AttributeKey] | None = None
356+
357+
def __post_init__(self) -> None:
358+
if len(self.arguments) != 4:
359+
raise InvalidSearchQuery(
360+
f"Trace metric aggregates expects exactly 4 arguments to be defined, got {len(self.arguments)}"
361+
)
362+
363+
if not isinstance(self.arguments[0], AttributeArgumentDefinition):
364+
raise InvalidSearchQuery(
365+
"Trace metric aggregates expect argument 0 to be of type AttributeArgumentDefinition"
366+
)
367+
368+
for i in range(1, 4):
369+
if not isinstance(self.arguments[i], ValueArgumentDefinition):
370+
raise InvalidSearchQuery(
371+
f"Trace metric aggregates expects argument {i} to be of type ValueArgumentDefinition"
372+
)
373+
374+
def resolve(
375+
self,
376+
alias: str,
377+
search_type: constants.SearchType,
378+
resolved_arguments: ResolvedArguments,
379+
snuba_params: SnubaParams,
380+
query_result_cache: dict[str, EAPResponse],
381+
search_config: SearchResolverConfig,
382+
) -> ResolvedAggregate:
383+
if not isinstance(resolved_arguments[0], AttributeKey):
384+
raise InvalidSearchQuery(
385+
"Trace metric aggregates expect argument 0 to be of type AttributeArgumentDefinition"
386+
)
387+
388+
resolved_attribute = resolved_arguments[0]
389+
if self.attribute_resolver is not None:
390+
resolved_attribute = self.attribute_resolver(resolved_attribute)
391+
392+
if all(resolved_argument != "" for resolved_argument in resolved_arguments[1:]):
393+
# a metric was passed
394+
# TODO: we need to put it into the top level query conditions
395+
pass
396+
elif all(resolved_argument == "" for resolved_argument in resolved_arguments[1:]):
397+
# no metrics were specified, assume we query all metrics
398+
pass
399+
else:
400+
raise InvalidSearchQuery(
401+
f"Trace metric aggregates expect the full metric to be specified, got name:{resolved_arguments[1]} type:{resolved_arguments[2]} unit:{resolved_arguments[3]}"
402+
)
338403

339404
return ResolvedAggregate(
340405
public_alias=alias,
@@ -519,25 +584,18 @@ def attribute_key_to_tuple(attribute_key: AttributeKey) -> tuple[str, AttributeK
519584

520585
def count_argument_resolver_optimized(
521586
always_present_attributes: list[AttributeKey],
522-
) -> Callable[[ResolvedArguments], AttributeKey]:
587+
) -> Callable[[ResolvedArgument], AttributeKey]:
523588
always_present_attributes_set = {
524589
attribute_key_to_tuple(attribute) for attribute in always_present_attributes
525590
}
526591

527-
def count_argument_resolver(resolved_arguments: ResolvedArguments) -> AttributeKey:
528-
if len(resolved_arguments) != 1:
529-
raise InvalidSearchQuery(
530-
f"Aggregates expects exactly 1 argument, got {len(resolved_arguments)}"
531-
)
532-
533-
if not isinstance(resolved_arguments[0], AttributeKey):
592+
def count_argument_resolver(resolved_argument: ResolvedArgument) -> AttributeKey:
593+
if not isinstance(resolved_argument, AttributeKey):
534594
raise InvalidSearchQuery("Aggregates accept attribute keys only")
535595

536-
resolved_attribute: AttributeKey = resolved_arguments[0]
537-
538-
if attribute_key_to_tuple(resolved_attribute) in always_present_attributes_set:
596+
if attribute_key_to_tuple(resolved_argument) in always_present_attributes_set:
539597
return AttributeKey(name="sentry.project_id", type=AttributeKey.Type.TYPE_INT)
540598

541-
return resolved_attribute
599+
return resolved_argument
542600

543601
return count_argument_resolver

src/sentry/search/eap/resolver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ def resolve_function(
987987

988988
# If there are missing arguments, and the argument definition has a default arg, use the default arg
989989
# this assumes the missing args are at the beginning or end of the arguments list
990-
if missing_args > 0 and argument_definition.default_arg:
990+
if missing_args > 0 and argument_definition.default_arg is not None:
991991
if isinstance(argument_definition, ValueArgumentDefinition):
992992
parsed_args.append(argument_definition.default_arg)
993993
else:

0 commit comments

Comments
 (0)