Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/sentry/seer/explorer/tools.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from typing import Any
from typing import Any, Literal

from sentry.api import client
from sentry.models.apikey import ApiKey
Expand Down Expand Up @@ -75,6 +75,7 @@ def execute_trace_query_table(
group_by: list[str] | None = None,
y_axes: list[str] | None = None,
per_page: int = 50,
mode: Literal["spans", "aggregates"] = "spans",
) -> dict[str, Any] | None:
"""
Execute a trace query to get table data by calling the events endpoint.
Expand All @@ -92,9 +93,11 @@ def execute_trace_query_table(
return None

# Determine fields based on mode
if group_by and len(group_by) > 0:
if mode == "aggregates":
# Aggregates mode: group_by fields + aggregate functions
fields = list(group_by)
fields = []
if group_by:
fields.extend(group_by)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Empty Fields List Causes API Failures

In execute_trace_query_table, when mode="aggregates" and both group_by and y_axes are empty, the fields list becomes empty. This can cause API calls to the events endpoint to fail. The previous logic implicitly ensured fields were present by falling back to default span fields, a safeguard removed by the new explicit mode parameter.

Fix in Cursor Fix in Web

if y_axes:
fields.extend(y_axes)
else:
Expand Down
52 changes: 52 additions & 0 deletions tests/sentry/seer/explorer/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ def test_execute_trace_query_table_with_groupby(self):
group_by=["span.op"],
y_axes=["count()"],
per_page=10,
mode="aggregates",
)

assert result is not None
Expand All @@ -288,6 +289,57 @@ def test_execute_trace_query_table_with_groupby(self):
assert "span.op" in row
assert "count()" in row

def test_execute_trace_query_table_aggregates_mode_basic(self):
"""Test table query in aggregates mode without group_by"""
result = execute_trace_query_table(
org_id=self.organization.id,
query="",
stats_period="1h",
sort="-count()",
y_axes=["count()", "avg(span.duration)"],
per_page=10,
mode="aggregates",
)

assert result is not None
assert "data" in result
assert "meta" in result

rows = result["data"]
# Should have aggregate results
assert len(rows) > 0

# Each row should have the aggregate functions
for row in rows:
assert "count()" in row
assert "avg(span.duration)" in row

def test_execute_trace_query_table_aggregates_mode_multiple_functions(self):
"""Test table query in aggregates mode with multiple aggregate functions"""
result = execute_trace_query_table(
org_id=self.organization.id,
query="span.op:db", # Filter to only database operations
stats_period="1h",
sort="-sum(span.duration)",
y_axes=["count()", "sum(span.duration)", "avg(span.duration)"],
per_page=10,
mode="aggregates",
)

assert result is not None
assert "data" in result
assert "meta" in result

rows = result["data"]
# Should have aggregate results for database spans
assert len(rows) > 0

# Each row should have all the aggregate functions
for row in rows:
assert "count()" in row
assert "sum(span.duration)" in row
assert "avg(span.duration)" in row

def test_get_organization_project_ids(self):
"""Test the get_organization_project_ids RPC method"""
from sentry.seer.endpoints.seer_rpc import get_organization_project_ids
Expand Down
Loading