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
5 changes: 5 additions & 0 deletions src/sentry/search/events/builder/discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
ParamsType,
QueryBuilderConfig,
SelectType,
SnubaParams,
WhereType,
)
from sentry.snuba.dataset import Dataset
Expand Down Expand Up @@ -159,6 +160,7 @@ def __init__(
dataset: Dataset,
params: ParamsType,
interval: int,
snuba_params: SnubaParams | None = None,
query: str | None = None,
selected_columns: list[str] | None = None,
equations: list[str] | None = None,
Expand All @@ -171,6 +173,7 @@ def __init__(
super().__init__(
dataset,
params,
snuba_params=snuba_params,
query=query,
selected_columns=selected_columns,
equations=equations,
Expand Down Expand Up @@ -275,6 +278,7 @@ def __init__(
params: ParamsType,
interval: int,
top_events: list[dict[str, Any]],
snuba_params: SnubaParams | None = None,
other: bool = False,
query: str | None = None,
selected_columns: list[str] | None = None,
Expand All @@ -290,6 +294,7 @@ def __init__(
super().__init__(
dataset,
params,
snuba_params=snuba_params,
interval=interval,
query=query,
selected_columns=list(set(selected_columns + timeseries_functions)),
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/search/events/builder/profile_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def __init__(
params: ParamsType,
interval: int,
top_events: list[dict[str, Any]],
snuba_params: SnubaParams | None = None,
other: bool = False,
query: str | None = None,
selected_columns: list[str] | None = None,
Expand All @@ -100,6 +101,7 @@ def __init__(
super().__init__(
dataset,
params,
snuba_params=snuba_params,
interval=interval,
query=query,
selected_columns=list(set(selected_columns + timeseries_functions)),
Expand Down
56 changes: 48 additions & 8 deletions src/sentry/search/events/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from collections import namedtuple
from collections.abc import Mapping, Sequence
from copy import deepcopy
from dataclasses import dataclass
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any, NotRequired, Optional, TypedDict, Union

from django.utils import timezone as django_timezone
from snuba_sdk.aliased_expression import AliasedExpression
from snuba_sdk.column import Column
from snuba_sdk.conditions import BooleanCondition, Condition
Expand Down Expand Up @@ -74,24 +75,36 @@ class EventsResponse(TypedDict):

@dataclass
class SnubaParams:
start: datetime | None
end: datetime | None
start: datetime | None = None
end: datetime | None = None
stats_period: str | None = None
# The None value in this sequence is because the filter params could include that
environments: Sequence[Environment | None]
projects: Sequence[Project]
user: RpcUser | None
teams: Sequence[Team]
organization: Organization | None
environments: Sequence[Environment | None] = field(default_factory=list)
projects: Sequence[Project] = field(default_factory=list)
user: RpcUser | None = None
teams: Sequence[Team] = field(default_factory=list)
organization: Organization | None = None

def __post_init__(self) -> None:
if self.start:
self.start = self.start.replace(tzinfo=timezone.utc)
if self.end:
self.end = self.end.replace(tzinfo=timezone.utc)
if self.start is None and self.end is None:
self.parse_stats_period()
if self.organization is None and len(self.projects) > 0:
self.organization = self.projects[0].organization

# Only used in the trend query builder
self.aliases: dict[str, Alias] | None = {}

def parse_stats_period(self) -> None:
if self.stats_period is not None:
self.end = django_timezone.now()
from sentry.api.utils import get_datetime_from_stats_period

self.start = get_datetime_from_stats_period(self.stats_period, self.end)

@property
def environment_names(self) -> Sequence[str]:
return (
Expand Down Expand Up @@ -122,6 +135,33 @@ def interval(self) -> float | None:
return (self.end - self.start).total_seconds()
return None

@property
def organization_id(self) -> int | None:
if self.organization is not None:
return self.organization.id
return None

@property
def filter_params(self) -> ParamsType:
# Compatibility function so we can switch over to this dataclass more easily
filter_params: ParamsType = {
"project_id": list(self.project_ids),
"projects": list(self.projects),
"project_objects": list(self.projects),
"environment": list(self.environment_names),
"team_id": list(self.team_ids),
"environment_objects": [env for env in self.environments if env is not None],
}
if self.organization_id:
filter_params["organization_id"] = self.organization_id
if self.start:
filter_params["start"] = self.start
if self.end:
filter_params["end"] = self.end
if self.stats_period:
filter_params["statsPeriod"] = self.stats_period
return filter_params

def copy(self) -> SnubaParams:
return deepcopy(self)

Expand Down
8 changes: 8 additions & 0 deletions src/sentry/snuba/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def top_events_timeseries(
rollup,
limit,
organization,
snuba_params=None,
equations=None,
referrer=None,
top_events=None,
Expand All @@ -152,6 +153,7 @@ def top_events_timeseries(
selected_columns,
query=user_query,
params=params,
snuba_params=snuba_params,
equations=equations,
orderby=orderby,
limit=limit,
Expand All @@ -163,6 +165,7 @@ def top_events_timeseries(
top_functions_builder = ProfileTopFunctionsTimeseriesQueryBuilder(
dataset=Dataset.Functions,
params=params,
snuba_params=snuba_params,
interval=rollup,
top_events=top_events["data"],
other=False,
Expand All @@ -186,6 +189,7 @@ def top_events_timeseries(
top_functions_builder,
params,
rollup,
snuba_params=snuba_params,
top_events=top_events,
allow_empty=allow_empty,
zerofill_results=zerofill_results,
Expand All @@ -198,13 +202,17 @@ def format_top_events_timeseries_results(
query_builder,
params,
rollup,
snuba_params=None,
top_events=None,
allow_empty=True,
zerofill_results=True,
result_key_order=None,
):
if top_events is None:
assert top_events, "Need to provide top events" # TODO: support this use case
if snuba_params is not None and len(params) == 0:
# Compatibility so its easier to convert to SnubaParams
params = snuba_params.filter_params

if not allow_empty and not len(result.get("data", [])):
return SnubaTSResult(
Expand Down
21 changes: 11 additions & 10 deletions src/sentry/tasks/check_am2_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from sentry.models.organization import Organization
from sentry.models.project import Project
from sentry.search.events.builder.metrics import MetricsQueryBuilder
from sentry.search.events.types import ParamsType, QueryBuilderConfig
from sentry.search.events.types import QueryBuilderConfig, SnubaParams
from sentry.silo.base import SiloMode
from sentry.snuba.dataset import Dataset
from sentry.snuba.discover import query as discover_query
Expand Down Expand Up @@ -468,21 +468,22 @@ def get_outdated_sdks(cls, found_sdks_per_project):
return outdated_sdks_per_project

@classmethod
def get_sdks_version_used(cls, organization_id, project_objects):
def get_sdks_version_used(cls, organization, project_objects):
# We use the count() operation in order to group by project, sdk.name and sdk.version.
selected_columns = ["count()", "project", "sdk.name", "sdk.version"]
params: ParamsType = {
"organization_id": organization_id,
"project_objects": project_objects,
"start": datetime.now(tz=timezone.utc) - timedelta(days=QUERY_TIME_RANGE_IN_DAYS),
"end": datetime.now(tz=timezone.utc),
}
params = SnubaParams(
start=datetime.now(tz=timezone.utc) - timedelta(days=QUERY_TIME_RANGE_IN_DAYS),
end=datetime.now(tz=timezone.utc),
organization=organization,
projects=project_objects,
)

try:
results = discover_query(
selected_columns=selected_columns,
query="event.type:transaction",
params=params,
params={},
snuba_params=params,
referrer="api.organization-events",
)

Expand Down Expand Up @@ -637,7 +638,7 @@ def run_compatibility_check(cls, org_id):
# We mark whether a metric is not supported.
unsupported_alerts.append((alert_id, aggregate, query))

outdated_sdks_per_project = cls.get_sdks_version_used(organization.id, all_projects)
outdated_sdks_per_project = cls.get_sdks_version_used(organization, all_projects)
if outdated_sdks_per_project is None:
with sentry_sdk.isolation_scope() as scope:
scope.set_tag("org_id", organization.id)
Expand Down
19 changes: 8 additions & 11 deletions src/sentry/tasks/on_demand_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from django.utils import timezone

from sentry import options
from sentry.api.utils import get_date_range_from_params
from sentry.models.dashboard_widget import (
DashboardWidgetQuery,
DashboardWidgetQueryOnDemand,
Expand All @@ -24,7 +23,7 @@
)
from sentry.search.events import fields
from sentry.search.events.builder.discover import DiscoverQueryBuilder
from sentry.search.events.types import EventsResponse, ParamsType, QueryBuilderConfig
from sentry.search.events.types import EventsResponse, QueryBuilderConfig, SnubaParams
from sentry.snuba.dataset import Dataset
from sentry.snuba.metrics.extraction import OnDemandMetricSpecVersioning
from sentry.snuba.referrer import Referrer
Expand Down Expand Up @@ -467,21 +466,19 @@ def _query_cardinality(
# Restrict period down to an allowlist so we're not slamming snuba with giant queries
if period not in [TASK_QUERY_PERIOD, DASHBOARD_QUERY_PERIOD]:
raise Exception("Cardinality can only be queried with 1h or 30m")
params: ParamsType = {
"statsPeriod": period,
"organization_id": organization.id,
"project_objects": list(Project.objects.filter(organization=organization)),
}
start, end = get_date_range_from_params(params)
params["start"] = start
params["end"] = end
params = SnubaParams(
stats_period=period,
organization=organization,
projects=list(Project.objects.filter(organization=organization)),
)

columns_to_check = [column for column in query_columns if not fields.is_function(column)]
unique_columns = [f"count_unique({column})" for column in columns_to_check]

query_builder = DiscoverQueryBuilder(
dataset=Dataset.Discover,
params=params,
params={},
snuba_params=params,
selected_columns=unique_columns,
config=QueryBuilderConfig(
transform_alias_to_input_format=True,
Expand Down
45 changes: 22 additions & 23 deletions src/sentry/tasks/statistical_detectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from sentry.models.project import Project
from sentry.models.statistical_detectors import RegressionType
from sentry.profiles.utils import get_from_profiling_service
from sentry.search.events.types import ParamsType
from sentry.search.events.types import SnubaParams
from sentry.seer.breakpoints import BreakpointData
from sentry.sentry_metrics import indexer
from sentry.sentry_metrics.use_case_id_registry import UseCaseID
Expand Down Expand Up @@ -503,12 +503,11 @@ def emit_function_regression_issue(
project_ids = [int(regression["project"]) for regression in regressions]
projects = [projects_by_id[project_id] for project_id in project_ids]

params: ParamsType = {
"start": start,
"end": start + timedelta(minutes=1),
"project_id": project_ids,
"project_objects": projects,
}
params = SnubaParams(
start=start,
end=start + timedelta(minutes=1),
projects=projects,
)

conditions = [
And(
Expand All @@ -523,7 +522,8 @@ def emit_function_regression_issue(
result = functions.query(
selected_columns=["project.id", "fingerprint", "examples()"],
query="is_application:1",
params=params,
params={},
snuba_params=params,
orderby=["project.id"],
limit=len(regressions),
referrer=Referrer.API_PROFILING_FUNCTIONS_STATISTICAL_DETECTOR_EXAMPLE.value,
Expand Down Expand Up @@ -878,12 +878,11 @@ def query_functions(projects: list[Project], start: datetime) -> list[DetectorPa
# we just need to query for the 1 minute of data.
start = start - timedelta(hours=1)
start = start.replace(minute=0, second=0, microsecond=0)
params: ParamsType = {
"start": start,
"end": start + timedelta(minutes=1),
"project_id": [project.id for project in projects],
"project_objects": projects,
}
params = SnubaParams(
start=start,
end=start + timedelta(minutes=1),
projects=projects,
)

# TODOs: handle any errors
query_results = functions.query(
Expand All @@ -895,7 +894,8 @@ def query_functions(projects: list[Project], start: datetime) -> list[DetectorPa
"p95()",
],
query="is_application:1",
params=params,
params={},
snuba_params=params,
orderby=["project.id", "-count()"],
limitby=("project.id", FUNCTIONS_PER_PROJECT),
limit=FUNCTIONS_PER_PROJECT * len(projects),
Expand Down Expand Up @@ -924,16 +924,14 @@ def query_functions_timeseries(
agg_function: str,
) -> Generator[tuple[int, int | str, SnubaTSResult], None, None]:
projects = [project for project, _ in functions_list]
project_ids = [project.id for project in projects]

# take the last 14 days as our window
end = start.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)
params: ParamsType = {
"start": end - timedelta(days=14),
"end": end,
"project_id": project_ids,
"project_objects": projects,
}
params = SnubaParams(
start=end - timedelta(days=14),
end=end,
projects=projects,
)
Comment on lines +930 to +934
Copy link
Member Author

Choose a reason for hiding this comment

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

Didn't use SnubaParams(stats_period= here since the existing functionality sets end to 1hr in the future

interval = 3600 # 1 hour

chunk: list[dict[str, Any]] = [
Expand All @@ -948,7 +946,8 @@ def query_functions_timeseries(
timeseries_columns=[agg_function],
selected_columns=["project.id", "fingerprint"],
user_query="is_application:1",
params=params,
params={},
snuba_params=params,
orderby=None, # unused because top events is specified
rollup=interval,
limit=len(chunk),
Expand Down
Loading