Skip to content

Commit 8cbfd1b

Browse files
authored
ref(querybuilder): Change profiling profiles to use snuba params (#75070)
- This updates the profiling profiles endpoint to use snuba params over the paramstype - Needed to add quantize_date_params as a param to be compatible
1 parent 927a142 commit 8cbfd1b

File tree

7 files changed

+72
-47
lines changed

7 files changed

+72
-47
lines changed

src/sentry/api/bases/organization_events.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ def get_dataset(self, request: Request) -> Any:
9090
return result
9191

9292
def get_snuba_dataclass(
93-
self, request: Request, organization: Organization, check_global_views: bool = True
93+
self,
94+
request: Request,
95+
organization: Organization,
96+
check_global_views: bool = True,
97+
quantize_date_params: bool = True,
9498
) -> tuple[SnubaParams, ParamsType]:
9599
"""This will eventually replace the get_snuba_params function"""
96100
with sentry_sdk.start_span(op="discover.endpoint", description="filter_params(dataclass)"):
@@ -104,7 +108,8 @@ def get_snuba_dataclass(
104108
)
105109

106110
filter_params: dict[str, Any] = self.get_filter_params(request, organization)
107-
filter_params = self.quantize_date_params(request, filter_params)
111+
if quantize_date_params:
112+
filter_params = self.quantize_date_params(request, filter_params)
108113
params = SnubaParams(
109114
start=filter_params["start"],
110115
end=filter_params["end"],

src/sentry/api/endpoints/organization_profiling_profiles.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ def get(self, request: Request, organization: Organization) -> HttpResponse:
6666
if not features.has(
6767
"organizations:continuous-profiling-compat", organization, actor=request.user
6868
):
69-
params = self.get_snuba_params(request, organization)
70-
project_ids = params["project_id"]
69+
snuba_params, _ = self.get_snuba_dataclass(request, organization)
70+
71+
project_ids = snuba_params.project_ids
7172
if len(project_ids) > 1:
7273
raise ParseError(detail="You cannot get a flamegraph from multiple projects.")
7374

@@ -79,12 +80,12 @@ def get(self, request: Request, organization: Organization) -> HttpResponse:
7980
organization.id,
8081
project_ids[0],
8182
function_fingerprint,
82-
params,
83+
snuba_params,
8384
request.GET.get("query", ""),
8485
)
8586
else:
8687
sentry_sdk.set_tag("dataset", "profiles")
87-
profile_ids = get_profile_ids(params, request.query_params.get("query", None))
88+
profile_ids = get_profile_ids(snuba_params, request.query_params.get("query", None))
8889

8990
return proxy_profiling_service(
9091
method="POST",
@@ -125,26 +126,28 @@ def get(self, request: Request, organization: Organization) -> HttpResponse:
125126
return Response(status=404)
126127

127128
# We disable the date quantizing here because we need the timestamps to be precise.
128-
params = self.get_snuba_params(request, organization, quantize_date_params=False)
129+
snuba_params, _ = self.get_snuba_dataclass(
130+
request, organization, quantize_date_params=False
131+
)
129132

130-
project_ids = params.get("project_id")
133+
project_ids = snuba_params.project_ids
131134
if project_ids is None or len(project_ids) != 1:
132135
raise ParseError(detail="one project_id must be specified.")
133136

134137
profiler_id = request.query_params.get("profiler_id")
135138
if profiler_id is None:
136139
raise ParseError(detail="profiler_id must be specified.")
137140

138-
chunk_ids = get_chunk_ids(params, profiler_id, project_ids[0])
141+
chunk_ids = get_chunk_ids(snuba_params, profiler_id, project_ids[0])
139142

140143
return proxy_profiling_service(
141144
method="POST",
142145
path=f"/organizations/{organization.id}/projects/{project_ids[0]}/chunks",
143146
json_data={
144147
"profiler_id": profiler_id,
145148
"chunk_ids": chunk_ids,
146-
"start": str(int(params["start"].timestamp() * 1e9)),
147-
"end": str(int(params["end"].timestamp() * 1e9)),
149+
"start": str(int(snuba_params.start_date.timestamp() * 1e9)),
150+
"end": str(int(snuba_params.end_date.timestamp() * 1e9)),
148151
},
149152
)
150153

@@ -155,10 +158,10 @@ def get(self, request: Request, organization: Organization) -> HttpResponse:
155158
if not features.has("organizations:profiling", organization, actor=request.user):
156159
return Response(status=404)
157160

158-
params = self.get_snuba_params(request, organization)
161+
snuba_params, _ = self.get_snuba_dataclass(request, organization)
159162

160-
project_ids = params.get("project_id")
161-
if project_ids is None or len(project_ids) != 1:
163+
project_ids = snuba_params.project_ids
164+
if len(project_ids) != 1:
162165
raise ParseError(detail="one project_id must be specified.")
163166

164167
span_group = request.query_params.get("span_group")
@@ -168,7 +171,7 @@ def get(self, request: Request, organization: Organization) -> HttpResponse:
168171
spans = get_spans_from_group(
169172
organization.id,
170173
project_ids[0],
171-
params,
174+
snuba_params,
172175
span_group,
173176
)
174177

src/sentry/profiles/flamegraph.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from sentry.search.events.builder.discover import DiscoverQueryBuilder
2626
from sentry.search.events.builder.profile_functions import ProfileFunctionsQueryBuilder
2727
from sentry.search.events.fields import resolve_datetime64
28-
from sentry.search.events.types import ParamsType, QueryBuilderConfig, SnubaParams
28+
from sentry.search.events.types import QueryBuilderConfig, SnubaParams
2929
from sentry.snuba import functions
3030
from sentry.snuba.dataset import Dataset, EntityKey, StorageKey
3131
from sentry.snuba.referrer import Referrer
@@ -42,12 +42,13 @@ class ProfileIds(TypedDict):
4242

4343

4444
def get_profile_ids(
45-
params: ParamsType,
45+
snuba_params: SnubaParams,
4646
query: str | None = None,
4747
) -> ProfileIds:
4848
builder = DiscoverQueryBuilder(
4949
dataset=Dataset.Discover,
50-
params=params,
50+
params={},
51+
snuba_params=snuba_params,
5152
query=query,
5253
selected_columns=["profile.id"],
5354
limit=options.get("profiling.flamegraph.profile-set.size"),
@@ -69,15 +70,16 @@ def get_profiles_with_function(
6970
organization_id: int,
7071
project_id: int,
7172
function_fingerprint: int,
72-
params: ParamsType,
73+
snuba_params: SnubaParams,
7374
query: str,
7475
) -> ProfileIds:
7576
conditions = [query, f"fingerprint:{function_fingerprint}"]
7677

7778
result = functions.query(
7879
selected_columns=["timestamp", "unique_examples()"],
7980
query=" ".join(cond for cond in conditions if cond),
80-
params=params,
81+
params={},
82+
snuba_params=snuba_params,
8183
limit=100,
8284
orderby=["-timestamp"],
8385
referrer=Referrer.API_PROFILING_FUNCTION_SCOPED_FLAMEGRAPH.value,
@@ -113,7 +115,7 @@ class IntervalMetadata(TypedDict):
113115
def get_spans_from_group(
114116
organization_id: int,
115117
project_id: int,
116-
params: ParamsType,
118+
snuba_params: SnubaParams,
117119
span_group: str,
118120
) -> dict[str, list[IntervalMetadata]]:
119121
query = Query(
@@ -152,8 +154,8 @@ def get_spans_from_group(
152154
],
153155
where=[
154156
Condition(Column("project_id"), Op.EQ, project_id),
155-
Condition(Column("timestamp"), Op.GTE, params["start"]),
156-
Condition(Column("timestamp"), Op.LT, params["end"]),
157+
Condition(Column("timestamp"), Op.GTE, snuba_params.start),
158+
Condition(Column("timestamp"), Op.LT, snuba_params.end),
157159
Condition(Column("group"), Op.EQ, span_group),
158160
Condition(Column("profiler_id"), Op.NEQ, ""),
159161
],

src/sentry/profiles/profile_chunks.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
from sentry import options
44
from sentry.search.events.fields import resolve_datetime64
5-
from sentry.search.events.types import ParamsType
5+
from sentry.search.events.types import SnubaParams
66
from sentry.snuba.dataset import Dataset, StorageKey
77
from sentry.snuba.referrer import Referrer
88
from sentry.utils.snuba import raw_snql_query
99

1010

1111
def get_chunk_ids(
12-
params: ParamsType,
12+
snuba_params: SnubaParams,
1313
profiler_id: str,
1414
project_id: int,
1515
) -> list[str]:
@@ -24,12 +24,12 @@ def get_chunk_ids(
2424
Condition(
2525
Column("end_timestamp"),
2626
Op.GTE,
27-
resolve_datetime64(params.get("start")),
27+
resolve_datetime64(snuba_params.start),
2828
),
2929
Condition(
3030
Column("start_timestamp"),
3131
Op.LT,
32-
resolve_datetime64(params.get("end")),
32+
resolve_datetime64(snuba_params.end),
3333
),
3434
Condition(Column("project_id"), Op.EQ, project_id),
3535
Condition(Column("profiler_id"), Op.EQ, profiler_id),
@@ -44,7 +44,7 @@ def get_chunk_ids(
4444
query=query,
4545
tenant_ids={
4646
"referrer": Referrer.API_PROFILING_CONTINUOUS_PROFILING_FLAMECHART.value,
47-
"organization_id": params["organization_id"],
47+
"organization_id": snuba_params.organization_id,
4848
},
4949
)
5050

src/sentry/search/events/types.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from snuba_sdk.function import CurriedFunction, Function
1616
from snuba_sdk.orderby import OrderBy
1717

18+
from sentry.exceptions import InvalidSearchQuery
1819
from sentry.models.environment import Environment
1920
from sentry.models.organization import Organization
2021
from sentry.models.project import Project
@@ -105,6 +106,19 @@ def parse_stats_period(self) -> None:
105106

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

109+
@property
110+
def start_date(self) -> datetime:
111+
# This and end_date are helper functions so callers don't have to check if either are defined for typing
112+
if self.start is None:
113+
raise InvalidSearchQuery("start is required")
114+
return self.start
115+
116+
@property
117+
def end_date(self) -> datetime:
118+
if self.end is None:
119+
raise InvalidSearchQuery("end is required")
120+
return self.end
121+
108122
@property
109123
def environment_names(self) -> list[str]:
110124
return (

tests/sentry/api/endpoints/test_organization_profiling_profiles.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def test_more_than_one_project(self):
4848
assert response.status_code == 400, response.data
4949
assert response.data == {
5050
"detail": ErrorDetail(
51-
"You cannot view events from multiple projects.",
51+
"You cannot get a flamegraph from multiple projects.",
5252
code="parse_error",
5353
),
5454
}

tests/sentry/profiles/test_flamegraph.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import timedelta, timezone
22

33
from sentry.profiles.flamegraph import get_profiles_with_function
4+
from sentry.search.events.types import SnubaParams
45
from sentry.testutils.cases import ProfilesSnubaTestCase
56
from sentry.testutils.helpers.datetime import before_now
67
from sentry.utils.samples import load_data
@@ -69,12 +70,12 @@ def test_get_profile_with_function(self):
6970
self.organization.id,
7071
self.project.id,
7172
self.function_fingerprint({"package": "foo", "function": "foo"}),
72-
{
73-
"organization_id": self.organization.id,
74-
"project_id": [self.project.id],
75-
"start": before_now(days=1),
76-
"end": self.now,
77-
},
73+
SnubaParams(
74+
organization=self.organization,
75+
projects=[self.project],
76+
start=before_now(days=1),
77+
end=self.now,
78+
),
7879
"",
7980
)
8081
assert len(profile_ids["profile_ids"]) == 4, profile_ids
@@ -84,12 +85,12 @@ def test_get_profile_with_function_with_transaction_filter(self):
8485
self.organization.id,
8586
self.project.id,
8687
self.function_fingerprint({"package": "foo", "function": "foo"}),
87-
{
88-
"organization_id": self.organization.id,
89-
"project_id": [self.project.id],
90-
"start": before_now(days=1),
91-
"end": self.now,
92-
},
88+
SnubaParams(
89+
organization=self.organization,
90+
projects=[self.project],
91+
start=before_now(days=1),
92+
end=self.now,
93+
),
9394
"transaction:foobar",
9495
)
9596
assert len(profile_ids["profile_ids"]) == 1, profile_ids
@@ -99,12 +100,12 @@ def test_get_profile_with_function_no_match(self):
99100
self.organization.id,
100101
self.project.id,
101102
self.function_fingerprint({"package": "foo", "function": "foo"}),
102-
{
103-
"organization_id": self.organization.id,
104-
"project_id": [self.project.id],
105-
"start": before_now(days=1),
106-
"end": self.now,
107-
},
103+
SnubaParams(
104+
organization=self.organization,
105+
projects=[self.project],
106+
start=before_now(days=1),
107+
end=self.now,
108+
),
108109
"transaction:foo",
109110
)
110111
assert len(profile_ids["profile_ids"]) == 0, profile_ids

0 commit comments

Comments
 (0)