Skip to content

ref(analytics): Transform analytics events for TET-825 #95205

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

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8143000
ref(analytics): Transform analytics events for TET-825
constantinius Jul 10, 2025
724b035
fix(theme): Neutral chart color is white (#95201)
ArthurKnaus Jul 10, 2025
7712413
ref(onboarding): Move onboarding types out of step component (#95200)
ArthurKnaus Jul 10, 2025
8146e7c
fix(profiling-onboarding): iframe blocked by CSP (#95202)
ArthurKnaus Jul 10, 2025
1867317
fix(demo-mode): includes demo header in stacked nav layout (#95203)
obostjancic Jul 10, 2025
885e367
chore(dynamic-sampling): remove dynamic sampling minimum samplerate p…
shellmayr Jul 10, 2025
ca88475
fix(analytics): missing 'data' attribute exclusion
constantinius Jul 10, 2025
6234116
Revert "chore(dynamic-sampling): remove dynamic sampling minimum samp…
constantinius Jul 10, 2025
054dbdf
Revert "fix(demo-mode): includes demo header in stacked nav layout (#…
constantinius Jul 10, 2025
41841aa
Revert "fix(profiling-onboarding): iframe blocked by CSP (#95202)"
constantinius Jul 10, 2025
111464d
Revert "ref(onboarding): Move onboarding types out of step component …
constantinius Jul 10, 2025
c376be9
Revert "fix(theme): Neutral chart color is white (#95201)"
constantinius Jul 10, 2025
fd49aba
fix(analytics): fixing mypy issues
constantinius Jul 10, 2025
baf5a77
fix(analytics): exclude UUID from Event equality checks to allow for …
constantinius Jul 10, 2025
5755ef6
Merge branch 'master' into constantinius/ref/analytics/tet-825
constantinius Jul 11, 2025
e2a04cf
Revert "fix(analytics): exclude UUID from Event equality checks to al…
constantinius Jul 11, 2025
91d8172
test(analytics): fix tests for record calls
constantinius Jul 11, 2025
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
13 changes: 5 additions & 8 deletions src/sentry/analytics/events/eventuser_snuba_for_projects.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
from sentry import analytics


@analytics.eventclass("eventuser_snuba.for_projects")
class EventUserSnubaForProjects(analytics.Event):
type = "eventuser_snuba.for_projects"

attributes = (
analytics.Attribute("project_ids", type=list),
analytics.Attribute("total_tries", type=int),
analytics.Attribute("total_rows_returned", required=True, type=int),
analytics.Attribute("total_time_ms", type=int),
)
project_ids: list[int]
total_tries: int
total_rows_returned: int
total_time_ms: int


analytics.register(EventUserSnubaForProjects)
17 changes: 7 additions & 10 deletions src/sentry/analytics/events/eventuser_snuba_query.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
from sentry import analytics


@analytics.eventclass("eventuser_snuba.query")
class EventUserSnubaQuery(analytics.Event):
type = "eventuser_snuba.query"

attributes = (
analytics.Attribute("project_ids", type=list),
analytics.Attribute("query"),
analytics.Attribute("query_try", type=int),
analytics.Attribute("count_rows_returned", required=True, type=int),
analytics.Attribute("count_rows_filtered", required=True, type=int),
analytics.Attribute("query_time_ms", type=int),
)
project_ids: list[int]
query: str
query_try: int
count_rows_returned: int
count_rows_filtered: int
query_time_ms: int


analytics.register(EventUserSnubaQuery)
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
from sentry import analytics


@analytics.eventclass("grouping.experiments.parameterization")
class GroupingParameterizationExperiment(analytics.Event):
type = "grouping.experiments.parameterization"

attributes = (
analytics.Attribute("experiment_name"),
analytics.Attribute("project_id"),
analytics.Attribute("event_id"),
)
experiment_name: str
project_id: str
event_id: str
Comment on lines +7 to +8
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't these be ints?



analytics.register(GroupingParameterizationExperiment)
11 changes: 4 additions & 7 deletions src/sentry/analytics/events/notifications_settings_updated.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
from sentry import analytics


@analytics.eventclass("notifications.settings_updated")
class NotificationSettingsUpdated(analytics.Event):
type = "notifications.settings_updated"

attributes = (
analytics.Attribute("target_type"),
analytics.Attribute("actor_id", required=False),
analytics.Attribute("id"),
)
target_type: str
actor_id: str | None = None
id: str
Comment on lines +7 to +8
Copy link
Member

Choose a reason for hiding this comment

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

Same as above - are these ints or str?



analytics.register(NotificationSettingsUpdated)
25 changes: 11 additions & 14 deletions src/sentry/mail/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@


# TODO: should have same base class as SlackIntegrationNotificationSent
@analytics.eventclass("integrations.email.notification_sent")
class EmailNotificationSent(analytics.Event):
type = "integrations.email.notification_sent"

attributes = (
analytics.Attribute("organization_id"),
analytics.Attribute("project_id", required=False),
analytics.Attribute("category"),
analytics.Attribute("actor_id", required=False),
analytics.Attribute("user_id", required=False),
analytics.Attribute("group_id", required=False),
analytics.Attribute("id"),
analytics.Attribute("actor_type"),
analytics.Attribute("notification_uuid"),
analytics.Attribute("alert_id", required=False),
)
organization_id: str
project_id: str | None = None
category: str
actor_id: str | None = None
user_id: str | None = None
group_id: str | None = None
id: str
actor_type: str
notification_uuid: str
alert_id: str | None = None


analytics.register(EmailNotificationSent)
28 changes: 16 additions & 12 deletions src/sentry/utils/eventuser.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
)

from sentry import analytics
from sentry.analytics.events.eventuser_snuba_for_projects import EventUserSnubaForProjects
from sentry.analytics.events.eventuser_snuba_query import EventUserSnubaQuery
from sentry.eventstore.models import Event, GroupEvent
from sentry.models.project import Project
from sentry.snuba.dataset import Dataset, EntityKey
Expand Down Expand Up @@ -233,13 +235,14 @@ def for_projects(
query_end_time = time.time()

analytics.record(
"eventuser_snuba.query",
project_ids=[p.id for p in projects],
query=query.print(),
query_try=tries,
count_rows_returned=len(data_results),
count_rows_filtered=len(data_results) - len(unique_event_users),
query_time_ms=int((query_end_time - query_start_time) * 1000),
EventUserSnubaQuery(
project_ids=[p.id for p in projects],
query=query.print(),
query_try=tries,
count_rows_returned=len(data_results),
count_rows_filtered=len(data_results) - len(unique_event_users),
query_time_ms=int((query_end_time - query_start_time) * 1000),
)
)
tries += 1
if (
Expand All @@ -252,11 +255,12 @@ def for_projects(

end_time = time.time()
analytics.record(
"eventuser_snuba.for_projects",
project_ids=[p.id for p in projects],
total_tries=tries,
total_rows_returned=len(full_results),
total_time_ms=int((end_time - start_time) * 1000),
EventUserSnubaForProjects(
project_ids=[p.id for p in projects],
total_tries=tries,
total_rows_returned=len(full_results),
total_time_ms=int((end_time - start_time) * 1000),
)
)

if result_limit:
Expand Down
34 changes: 16 additions & 18 deletions tests/sentry/utils/test_eventuser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

from datetime import timedelta
from unittest import mock
from unittest.mock import call

from django.utils import timezone
from snuba_sdk import BooleanOp

from sentry.analytics.events.eventuser_snuba_for_projects import EventUserSnubaForProjects
from sentry.analytics.events.eventuser_snuba_query import EventUserSnubaQuery
from sentry.testutils.cases import APITestCase, SnubaTestCase
from sentry.testutils.helpers.analytics import assert_analytics_events_recorded
from sentry.testutils.helpers.datetime import before_now, freeze_time
from sentry.utils.eventuser import EventUser

Expand Down Expand Up @@ -70,10 +72,10 @@ def test_for_projects_query_filter_id(self, mock_record):
assert euser[0].user_ident == self.event_2.data.get("user").get("id")
assert euser[0].email == self.event_2.data.get("user").get("email")

mock_record.assert_has_calls(
assert_analytics_events_recorded(
mock_record,
[
call(
"eventuser_snuba.query",
EventUserSnubaQuery(
project_ids=[self.project.id],
query=f"MATCH (events)\nSELECT project_id, ip_address_v6, ip_address_v4, user_id, user_name, "
f"user_email, max(timestamp) AS `latest_timestamp`\nBY project_id, ip_address_v6, "
Expand All @@ -88,8 +90,7 @@ def test_for_projects_query_filter_id(self, mock_record):
count_rows_filtered=0,
query_time_ms=0,
),
call(
"eventuser_snuba.for_projects",
EventUserSnubaForProjects(
project_ids=[self.project.id],
total_tries=1,
total_rows_returned=1,
Expand Down Expand Up @@ -281,10 +282,10 @@ def test_for_projects_query_with_multiple_eventuser_entries_different_ips_query_
assert eusers[1].email == self.event_3.data.get("user").get("email")
assert eusers[1].ip_address == self.event_3.data.get("user").get("ip_address")

mock_record.assert_has_calls(
assert_analytics_events_recorded(
mock_record,
[
call(
"eventuser_snuba.query",
EventUserSnubaQuery(
project_ids=[self.project.id],
query=f"MATCH (events)\nSELECT project_id, ip_address_v6, ip_address_v4, user_id, user_name, "
f"user_email, max(timestamp) AS `latest_timestamp`\nBY project_id, ip_address_v6, "
Expand All @@ -298,8 +299,7 @@ def test_for_projects_query_with_multiple_eventuser_entries_different_ips_query_
count_rows_filtered=19,
query_time_ms=0,
),
call(
"eventuser_snuba.for_projects",
EventUserSnubaForProjects(
project_ids=[self.project.id],
total_tries=1,
total_rows_returned=2,
Expand Down Expand Up @@ -361,10 +361,10 @@ def test_for_projects_multiple_query(self, mock_record):
assert eusers[1].email == email_2
assert eusers[1].ip_address == "2001:db8:0:85a3::ac1f:8005"

mock_record.assert_has_calls(
assert_analytics_events_recorded(
mock_record,
[
call(
"eventuser_snuba.query",
EventUserSnubaQuery(
project_ids=[self.project.id],
query=f"MATCH (events)\nSELECT project_id, ip_address_v6, ip_address_v4, user_id, user_name, "
f"user_email, max(timestamp) AS `latest_timestamp`\nBY project_id, ip_address_v6, "
Expand All @@ -379,8 +379,7 @@ def test_for_projects_multiple_query(self, mock_record):
count_rows_filtered=4,
query_time_ms=0,
),
call(
"eventuser_snuba.query",
EventUserSnubaQuery(
project_ids=[self.project.id],
query=f"MATCH (events)\nSELECT project_id, ip_address_v6, ip_address_v4, user_id, user_name, "
f"user_email, max(timestamp) AS `latest_timestamp`\nBY project_id, ip_address_v6, "
Expand All @@ -395,8 +394,7 @@ def test_for_projects_multiple_query(self, mock_record):
count_rows_filtered=3,
query_time_ms=0,
),
call(
"eventuser_snuba.for_projects",
EventUserSnubaForProjects(
project_ids=[self.project.id],
total_tries=2,
total_rows_returned=2,
Expand Down
Loading