Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(apis): Pass query source to snuba - phase 2 #73497

Merged
merged 3 commits into from
Aug 1, 2024
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
10 changes: 10 additions & 0 deletions src/sentry/api/endpoints/organization_events_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
from sentry.api.serializers import serialize
from sentry.api.serializers.models.group import GroupSerializer
from sentry.api.utils import handle_query_errors
from sentry.middleware import is_frontend_request
from sentry.snuba import spans_indexed, spans_metrics
from sentry.snuba.query_sources import QuerySource
from sentry.snuba.referrer import Referrer


Expand All @@ -39,6 +41,10 @@ def get(self, request: Request, organization) -> Response:
params=params,
query=request.query_params.get("query"),
referrer=Referrer.API_ORGANIZATION_EVENTS_META.value,
# TODO: @athena - add query_source when all datasets support it
# query_source=(
# QuerySource.FRONTEND if is_frontend_request(request) else QuerySource.API
# ),
Comment on lines +44 to +47
Copy link
Member

Choose a reason for hiding this comment

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

Did you mean to leave this commented out?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, not all datasets currently expect query_source as a param and they're not typed to safely take care of that. So I'll uncomment it after my last PR.

)

return Response({"count": result["data"][0]["count"]})
Expand Down Expand Up @@ -118,6 +124,7 @@ class OrganizationSpansSamplesEndpoint(OrganizationEventsEndpointBase):
snuba_methods = ["GET"]

def get(self, request: Request, organization) -> Response:
is_frontend = is_frontend_request(request)
try:
params = self.get_snuba_params(request, organization)
except NoProjects:
Expand Down Expand Up @@ -148,6 +155,7 @@ def get(self, request: Request, organization) -> Response:
params=params,
query=request.query_params.get("query"),
referrer=Referrer.API_SPAN_SAMPLE_GET_BOUNDS.value,
query_source=(QuerySource.FRONTEND if is_frontend else QuerySource.API),
)
if len(bound_results["data"]) != 1:
raise ParseError("Could not find bounds")
Expand All @@ -169,6 +177,7 @@ def get(self, request: Request, organization) -> Response:
params=params,
query=request.query_params.get("query"),
referrer=Referrer.API_SPAN_SAMPLE_GET_SPAN_IDS.value,
query_source=(QuerySource.FRONTEND if is_frontend else QuerySource.API),
)
span_ids = []
for row in result["data"]:
Expand All @@ -192,5 +201,6 @@ def get(self, request: Request, organization) -> Response:
query=query,
limit=9,
referrer=Referrer.API_SPAN_SAMPLE_GET_SPAN_DATA.value,
query_source=(QuerySource.FRONTEND if is_frontend else QuerySource.API),
)
return Response({"data": result["data"]})
18 changes: 18 additions & 0 deletions src/sentry/api/endpoints/organization_events_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from sentry.api.base import region_silo_endpoint
from sentry.api.bases import OrganizationEventsV2EndpointBase
from sentry.constants import MAX_TOP_EVENTS
from sentry.middleware import is_frontend_request
from sentry.models.dashboard_widget import DashboardWidget, DashboardWidgetTypes
from sentry.models.organization import Organization
from sentry.snuba import (
Expand All @@ -25,6 +26,7 @@
transactions,
)
from sentry.snuba.metrics.extraction import MetricSpecType
from sentry.snuba.query_sources import QuerySource
from sentry.snuba.referrer import Referrer
from sentry.utils.snuba import SnubaError, SnubaTSResult

Expand Down Expand Up @@ -75,6 +77,9 @@
ALLOWED_EVENTS_STATS_REFERRERS: set[str] = {
Referrer.API_ALERTS_ALERT_RULE_CHART.value,
Referrer.API_ALERTS_CHARTCUTERIE.value,
Referrer.API_ENDPOINT_REGRESSION_ALERT_CHARTCUTERIE.value,
Referrer.API_FUNCTION_REGRESSION_ALERT_CHARTCUTERIE.value,
Referrer.DISCOVER_SLACK_UNFURL.value,
Referrer.API_DASHBOARDS_WIDGET_AREA_CHART.value,
Referrer.API_DASHBOARDS_WIDGET_BAR_CHART.value,
Referrer.API_DASHBOARDS_WIDGET_LINE_CHART.value,
Expand Down Expand Up @@ -108,6 +113,14 @@
}


SENTRY_BACKEND_REFERRERS = [
Referrer.API_ALERTS_CHARTCUTERIE.value,
Referrer.API_ENDPOINT_REGRESSION_ALERT_CHARTCUTERIE.value,
Referrer.API_FUNCTION_REGRESSION_ALERT_CHARTCUTERIE.value,
Referrer.DISCOVER_SLACK_UNFURL.value,
]


@region_silo_endpoint
class OrganizationEventsStatsEndpoint(OrganizationEventsV2EndpointBase):
publish_status = {
Expand Down Expand Up @@ -167,6 +180,7 @@ def check_if_results_have_data(self, results: SnubaTSResult | dict[str, SnubaTSR
return has_data

def get(self, request: Request, organization: Organization) -> Response:
query_source = QuerySource.FRONTEND if is_frontend_request(request) else QuerySource.API
with sentry_sdk.start_span(op="discover.endpoint", description="filter_params") as span:
span.set_data("organization", organization)

Expand Down Expand Up @@ -205,6 +219,8 @@ def get(self, request: Request, organization: Organization) -> Response:
if referrer in ALLOWED_EVENTS_STATS_REFERRERS.union(METRICS_ENHANCED_REFERRERS)
else Referrer.API_ORGANIZATION_EVENT_STATS.value
)
if referrer in SENTRY_BACKEND_REFERRERS:
query_source = QuerySource.SENTRY_BACKEND
Comment on lines +222 to +223
Copy link
Member

Choose a reason for hiding this comment

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

Can this logic be moved into is_frontend_request? Also, is there no other way to verify that the request came from the backend by inspecting the request like the authentication method?

Copy link
Member Author

Choose a reason for hiding this comment

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

is_frontend_request is using authentication but really no matter how we implement it a customer's direct api call can look like a frontend request so this is just a good estimate.

I don't think it's a good idea to move this to is_frontend_request because that's really independent of Snuba. Let me create a method in Endpoint or a util 🤔

batch_features = self.get_features(organization, request)
has_chart_interpolation = batch_features.get(
"organizations:performance-chart-interpolation", False
Expand Down Expand Up @@ -281,6 +297,7 @@ def _get_event_stats(
on_demand_metrics_enabled=use_on_demand_metrics,
on_demand_metrics_type=on_demand_metrics_type,
include_other=include_other,
query_source=query_source,
)

return scoped_dataset.timeseries_query(
Expand All @@ -306,6 +323,7 @@ def _get_event_stats(
)
),
on_demand_metrics_type=on_demand_metrics_type,
query_source=query_source,
)

def get_event_stats_factory(scoped_dataset):
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/integrations/slack/unfurl/discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from sentry.models.organization import Organization
from sentry.models.user import User
from sentry.search.events.filter import to_list
from sentry.snuba.referrer import Referrer
from sentry.utils.dates import (
get_interval_from_range,
parse_stats_period,
Expand Down Expand Up @@ -235,6 +236,7 @@ def unfurl_discover(
params.setlist("statsPeriod", [stats_period])

endpoint = "events-stats/"
params["referrer"] = Referrer.DISCOVER_SLACK_UNFURL.value

try:
resp = client.get(
Expand Down
7 changes: 5 additions & 2 deletions src/sentry/search/events/builder/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
)
from sentry.snuba.dataset import Dataset
from sentry.snuba.metrics.utils import MetricMeta
from sentry.snuba.query_sources import QuerySource
from sentry.users.services.user.service import user_service
from sentry.utils.dates import outside_retention_with_modified_start
from sentry.utils.env import in_test_environment
Expand Down Expand Up @@ -1509,10 +1510,12 @@ def handle_invalid_float(cls, value: float | None) -> float | None:
return None
return value

def run_query(self, referrer: str | None, use_cache: bool = False) -> Any:
def run_query(
self, referrer: str | None, use_cache: bool = False, query_source: QuerySource | None = None
) -> Any:
if not referrer:
InvalidSearchQuery("Query missing referrer.")
return raw_snql_query(self.get_snql_query(), referrer, use_cache)
return raw_snql_query(self.get_snql_query(), referrer, use_cache, query_source)

def process_results(self, results: Any) -> EventsResponse:
with sentry_sdk.start_span(op="QueryBuilder", description="process_results") as span:
Expand Down
14 changes: 10 additions & 4 deletions src/sentry/search/events/builder/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -1707,7 +1707,9 @@ def get_snql_query(self) -> list[Request]:

return queries

def run_query(self, referrer: str, use_cache: bool = False) -> Any:
def run_query(
self, referrer: str, use_cache: bool = False, query_source: QuerySource | None = None
) -> Any:
if self.use_metrics_layer or self.use_on_demand:
from sentry.snuba.metrics.datasource import get_series
from sentry.snuba.metrics.mqb_query_transformer import (
Expand Down Expand Up @@ -1755,7 +1757,7 @@ def run_query(self, referrer: str, use_cache: bool = False) -> Any:

queries = self.get_snql_query()
if queries:
results = bulk_snuba_queries(queries, referrer, use_cache)
results = bulk_snuba_queries(queries, referrer, use_cache, query_source=query_source)
else:
results = []

Expand Down Expand Up @@ -1965,7 +1967,9 @@ def resolve_top_event_conditions(

return final_condition

def run_query(self, referrer: str, use_cache: bool = False) -> Any:
def run_query(
self, referrer: str, use_cache: bool = False, query_source: QuerySource | None = None
) -> Any:
result = {}
results = []
meta_dict = {}
Expand Down Expand Up @@ -2033,7 +2037,9 @@ def run_query(self, referrer: str, use_cache: bool = False) -> Any:
else:
queries = self.get_snql_query()
if queries:
results = bulk_snuba_queries(queries, referrer, use_cache)
results = bulk_snuba_queries(
queries, referrer, use_cache, query_source=query_source
)

time_map: dict[str, dict[str, Any]] = defaultdict(dict)
for current_result in results:
Expand Down
14 changes: 11 additions & 3 deletions src/sentry/snuba/discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
)
from sentry.snuba.dataset import Dataset
from sentry.snuba.metrics.extraction import MetricSpecType
from sentry.snuba.query_sources import QuerySource
from sentry.tagstore.base import TOP_VALUES_DEFAULT_LIMIT
from sentry.utils.math import nice_int
from sentry.utils.snuba import (
Expand Down Expand Up @@ -205,6 +206,7 @@ def query(
on_demand_metrics_type: MetricSpecType | None = None,
dataset: Dataset = Dataset.Discover,
fallback_to_transactions: bool = False,
query_source: QuerySource | None = None,
) -> EventsResponse:
"""
High-level API for doing arbitrary user queries against events.
Expand Down Expand Up @@ -277,7 +279,9 @@ def query(
if extra_columns is not None:
builder.columns.extend(extra_columns)

result = builder.process_results(builder.run_query(referrer))
result = builder.process_results(
builder.run_query(referrer=referrer, query_source=query_source)
)
result["meta"]["tips"] = transform_tips(builder.tips)
return result

Expand All @@ -298,6 +302,7 @@ def timeseries_query(
on_demand_metrics_enabled: bool = False,
on_demand_metrics_type: MetricSpecType | None = None,
dataset: Dataset = Dataset.Discover,
query_source: QuerySource | None = None,
) -> SnubaTSResult:
"""
High-level API for doing arbitrary user timeseries queries against events.
Expand Down Expand Up @@ -369,7 +374,7 @@ def timeseries_query(
query_list.append(comparison_builder)

query_results = bulk_snuba_queries(
[query.get_snql_query() for query in query_list], referrer
[query.get_snql_query() for query in query_list], referrer, query_source=query_source
)

with sentry_sdk.start_span(op="discover.discover", description="timeseries.transform_results"):
Expand Down Expand Up @@ -470,6 +475,7 @@ def top_events_timeseries(
on_demand_metrics_enabled: bool = False,
on_demand_metrics_type: MetricSpecType | None = None,
dataset: Dataset = Dataset.Discover,
query_source: QuerySource | None = None,
) -> dict[str, SnubaTSResult] | SnubaTSResult:
"""
High-level API for doing arbitrary user timeseries queries for a limited number of top events
Expand Down Expand Up @@ -516,6 +522,7 @@ def top_events_timeseries(
include_equation_fields=True,
skip_tag_resolution=True,
dataset=dataset,
query_source=query_source,
)

top_events_builder = TopEventsQueryBuilder(
Expand Down Expand Up @@ -548,9 +555,10 @@ def top_events_timeseries(
result, other_result = bulk_snuba_queries(
[top_events_builder.get_snql_query(), other_events_builder.get_snql_query()],
referrer=referrer,
query_source=query_source,
)
else:
result = top_events_builder.run_query(referrer)
result = top_events_builder.run_query(referrer=referrer, query_source=query_source)
other_result = {"data": []}
if (
not allow_empty
Expand Down
10 changes: 8 additions & 2 deletions src/sentry/snuba/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from sentry.snuba.dataset import Dataset
from sentry.snuba.discover import OTHER_KEY, create_result_key, transform_tips, zerofill
from sentry.snuba.metrics.extraction import MetricSpecType
from sentry.snuba.query_sources import QuerySource
from sentry.utils.snuba import SnubaTSResult, bulk_snuba_queries

is_filter_translation = {}
Expand Down Expand Up @@ -55,6 +56,7 @@ def query(
on_demand_metrics_enabled=False,
on_demand_metrics_type: MetricSpecType | None = None,
fallback_to_transactions=False,
query_source: QuerySource | None = None,
) -> EventsResponse:
if not selected_columns:
raise InvalidSearchQuery("No columns selected")
Expand Down Expand Up @@ -84,7 +86,7 @@ def query(
)
if conditions is not None:
builder.add_conditions(conditions)
result = builder.process_results(builder.run_query(referrer))
result = builder.process_results(builder.run_query(referrer, query_source=query_source))
result["meta"]["tips"] = transform_tips(builder.tips)
return result

Expand All @@ -104,6 +106,7 @@ def timeseries_query(
use_metrics_layer=False,
on_demand_metrics_enabled=False,
on_demand_metrics_type: MetricSpecType | None = None,
query_source: QuerySource | None = None,
):

if len(params) == 0 and snuba_params is not None:
Expand Down Expand Up @@ -144,7 +147,7 @@ def timeseries_query(
query_list.append(comparison_builder)

query_results = bulk_snuba_queries(
[query.get_snql_query() for query in query_list], referrer
[query.get_snql_query() for query in query_list], referrer, query_source=query_source
)

with sentry_sdk.start_span(op="errors", description="timeseries.transform_results"):
Expand Down Expand Up @@ -216,6 +219,7 @@ def top_events_timeseries(
on_demand_metrics_enabled: bool = False,
on_demand_metrics_type: MetricSpecType | None = None,
dataset: Dataset = Dataset.Discover,
query_source: QuerySource | None = None,
) -> dict[str, SnubaTSResult] | SnubaTSResult:
"""
High-level API for doing arbitrary user timeseries queries for a limited number of top events
Expand Down Expand Up @@ -257,6 +261,7 @@ def top_events_timeseries(
use_aggregate_conditions=True,
include_equation_fields=True,
skip_tag_resolution=True,
query_source=query_source,
)

top_events_builder = ErrorsTopEventsQueryBuilder(
Expand Down Expand Up @@ -291,6 +296,7 @@ def top_events_timeseries(
result, other_result = bulk_snuba_queries(
[top_events_builder.get_snql_query(), other_events_builder.get_snql_query()],
referrer=referrer,
query_source=query_source,
)
else:
result = top_events_builder.run_query(referrer)
Expand Down
Loading
Loading