Skip to content

Commit f30e2e0

Browse files
authored
ref(event_manager): Inline signals into _record_transaction_info (#86604)
Centralizes all transaction-related side effects in `_record_transaction_info` so it can be moved into the new spans consumer. - Two signals were emitted directly in `event_manager.save`. The underlying functions are now called directly and the calls have been moved in. - We no longer connect the `record_*` functions that were called directly to their old signals.
1 parent f2d672c commit f30e2e0

File tree

5 files changed

+93
-49
lines changed

5 files changed

+93
-49
lines changed

src/sentry/event_manager.py

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,16 @@
103103
from sentry.plugins.base import plugins
104104
from sentry.quotas.base import index_data_category
105105
from sentry.receivers.features import record_event_processed
106-
from sentry.receivers.onboarding import record_release_received
106+
from sentry.receivers.onboarding import (
107+
record_first_insight_span,
108+
record_first_transaction,
109+
record_release_received,
110+
)
107111
from sentry.reprocessing2 import is_reprocessed_event
108112
from sentry.seer.signed_seer_api import make_signed_seer_api_request
109113
from sentry.signals import (
110114
first_event_received,
111115
first_event_with_minified_stack_trace_received,
112-
first_insight_span_received,
113-
first_transaction_received,
114116
issue_unresolved,
115117
)
116118
from sentry.tasks.process_buffer import buffer_incr
@@ -454,23 +456,11 @@ def save(
454456
event_type = self._data.get("type")
455457
if event_type == "transaction":
456458
job["data"]["project"] = project.id
457-
jobs = save_transaction_events([job], projects)
458-
459-
if not project.flags.has_transactions and not skip_send_first_transaction:
460-
first_transaction_received.send_robust(
461-
project=project, event=jobs[0]["event"], sender=Project
462-
)
463-
464-
for module, is_module in INSIGHT_MODULE_FILTERS.items():
465-
if not get_project_insight_flag(project, module) and is_module(job["data"]):
466-
first_insight_span_received.send_robust(
467-
project=project, module=module, sender=Project
468-
)
459+
jobs = save_transaction_events([job], projects, skip_send_first_transaction)
469460
return jobs[0]["event"]
470461
elif event_type == "generic":
471462
job["data"]["project"] = project.id
472463
jobs = save_generic_events([job], projects)
473-
474464
return jobs[0]["event"]
475465
else:
476466
project = job["event"].project
@@ -2459,7 +2449,9 @@ def _detect_performance_problems(jobs: Sequence[Job], projects: ProjectsMapping)
24592449

24602450

24612451
@sentry_sdk.tracing.trace
2462-
def _record_transaction_info(jobs: Sequence[Job], projects: ProjectsMapping) -> None:
2452+
def _record_transaction_info(
2453+
jobs: Sequence[Job], projects: ProjectsMapping, skip_send_first_transaction: bool
2454+
) -> None:
24632455
for job in jobs:
24642456
try:
24652457
event = job["event"]
@@ -2468,16 +2460,19 @@ def _record_transaction_info(jobs: Sequence[Job], projects: ProjectsMapping) ->
24682460
with sentry_sdk.start_span(op="event_manager.record_transaction_name_for_clustering"):
24692461
record_transaction_name_for_clustering(project, event.data)
24702462

2463+
record_event_processed(project, event)
2464+
2465+
if not skip_send_first_transaction:
2466+
record_first_transaction(project, event.datetime)
2467+
2468+
for module, is_module in INSIGHT_MODULE_FILTERS.items():
2469+
if not get_project_insight_flag(project, module) and is_module(job["data"]):
2470+
record_first_insight_span(project, module)
2471+
24712472
if job["release"]:
24722473
environment = job["data"].get("environment") or None # coorce "" to None
24732474
record_latest_release(project, job["release"], environment)
2474-
2475-
# these are what the "transaction_processed" signal hooked into
2476-
# we should not use signals here, so call the recievers directly
2477-
# instead of sending a signal. we should consider potentially
2478-
# deleting these
2479-
record_event_processed(project, event)
2480-
record_release_received(project, event)
2475+
record_release_received(project, job["release"].version)
24812476
except Exception:
24822477
sentry_sdk.capture_exception()
24832478

@@ -2546,7 +2541,11 @@ def _send_occurrence_to_platform(jobs: Sequence[Job], projects: ProjectsMapping)
25462541

25472542

25482543
@sentry_sdk.tracing.trace
2549-
def save_transaction_events(jobs: Sequence[Job], projects: ProjectsMapping) -> Sequence[Job]:
2544+
def save_transaction_events(
2545+
jobs: Sequence[Job],
2546+
projects: ProjectsMapping,
2547+
skip_send_first_transaction: bool = False,
2548+
) -> Sequence[Job]:
25502549
from .ingest.types import ConsumerType
25512550

25522551
organization_ids = {project.organization_id for project in projects.values()}
@@ -2589,7 +2588,7 @@ def save_transaction_events(jobs: Sequence[Job], projects: ProjectsMapping) -> S
25892588
_track_outcome_accepted_many(jobs)
25902589
_detect_performance_problems(jobs, projects)
25912590
_send_occurrence_to_platform(jobs, projects)
2592-
_record_transaction_info(jobs, projects)
2591+
_record_transaction_info(jobs, projects, skip_send_first_transaction)
25932592

25942593
return jobs
25952594

src/sentry/receivers/features.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,42 +96,62 @@ def record_first_event(project, **kwargs):
9696

9797

9898
def record_event_processed(project, event, **kwargs):
99-
feature_slugs = []
99+
return record_generic_event_processed(
100+
project,
101+
platform=event.group.platform if event.group else event.platform,
102+
release=event.get_tag("sentry:release"),
103+
environment=event.get_tag("environment"),
104+
user_keys=event.data.get("user", {}).keys(),
105+
tag_keys={tag[0] for tag in event.tags},
106+
has_sourcemap=has_sourcemap(event),
107+
has_breadcrumbs=event.data.get("breadcrumbs"),
108+
)
100109

101-
platform = event.group.platform if event.group else event.platform
110+
111+
def record_generic_event_processed(
112+
project,
113+
platform=None,
114+
release=None,
115+
environment=None,
116+
user_keys=None,
117+
tag_keys=None,
118+
has_sourcemap=False,
119+
has_breadcrumbs=False,
120+
**kwargs,
121+
):
122+
feature_slugs = []
102123

103124
# Platform
104125
if platform in manager.location_slugs("language"):
105126
feature_slugs.append(platform)
106127

107128
# Release Tracking
108-
if event.get_tag("sentry:release"):
129+
if release:
109130
feature_slugs.append("release_tracking")
110131

111132
# Environment Tracking
112-
if event.get_tag("environment"):
133+
if environment:
113134
feature_slugs.append("environment_tracking")
114135

115136
# User Tracking
116-
user_context = event.data.get("user")
117137
# We'd like them to tag with id or email.
118138
# Certain SDKs automatically tag with ip address.
119139
# Check to make sure more the ip address is being sent.
120140
# testing for this in test_no_user_tracking_for_ip_address_only
121141
# list(d.keys()) pattern is to make this python3 safe
122-
if user_context and len(user_context.keys() - {"ip_address", "sentry_user"}) > 0:
142+
if user_keys and len(set(user_keys) - {"ip_address", "sentry_user"}) > 0:
123143
feature_slugs.append("user_tracking")
124144

125145
# Custom Tags
126-
if {tag[0] for tag in event.tags} - DEFAULT_TAGS:
146+
if tag_keys and set(tag_keys) - DEFAULT_TAGS:
127147
feature_slugs.append("custom_tags")
128148

129149
# Sourcemaps
130-
if has_sourcemap(event):
150+
if has_sourcemap:
131151
feature_slugs.append("source_maps")
132152

133153
# Breadcrumbs
134-
if event.data.get("breadcrumbs"):
154+
if has_breadcrumbs:
135155
feature_slugs.append("breadcrumbs")
136156

137157
if not feature_slugs:

src/sentry/receivers/onboarding.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,21 @@ def record_first_event(project, event, **kwargs):
224224

225225

226226
@first_transaction_received.connect(weak=False)
227-
def record_first_transaction(project, event, **kwargs):
227+
def _record_first_transaction(project, event, **kwargs):
228+
return record_first_transaction(project, event.datetime, **kwargs)
229+
230+
231+
def record_first_transaction(project, datetime, **kwargs):
232+
if project.flags.has_transactions:
233+
return
234+
228235
project.update(flags=F("flags").bitor(Project.flags.has_transactions))
229236

230237
OrganizationOnboardingTask.objects.record(
231238
organization_id=project.organization_id,
232239
task=OnboardingTask.FIRST_TRANSACTION,
233240
status=OnboardingTaskStatus.COMPLETE,
234-
date_completed=event.datetime,
241+
date_completed=datetime,
235242
)
236243

237244
try:
@@ -430,8 +437,12 @@ def record_member_joined(organization_id: int, organization_member_id: int, **kw
430437
)
431438

432439

433-
def record_release_received(project, event, **kwargs):
434-
if not event.data.get("release"):
440+
def _record_release_received(project, event, **kwargs):
441+
return record_release_received(project, event.data.get("release"), **kwargs)
442+
443+
444+
def record_release_received(project, release, **kwargs):
445+
if not release:
435446
return
436447

437448
success = OrganizationOnboardingTask.objects.record(
@@ -459,8 +470,8 @@ def record_release_received(project, event, **kwargs):
459470
)
460471

461472

462-
event_processed.connect(record_release_received, weak=False)
463-
transaction_processed.connect(record_release_received, weak=False)
473+
event_processed.connect(_record_release_received, weak=False)
474+
transaction_processed.connect(_record_release_received, weak=False)
464475

465476

466477
@first_event_with_minified_stack_trace_received.connect(weak=False)

src/sentry/spans/consumers/process_segments/message.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,6 @@ def process_segment(spans: list[Span]) -> list[Span]:
237237
job: Job = {"data": event, "project_id": project.id, "raw": False, "start_time": None}
238238

239239
_pull_out_data([job], projects)
240-
_record_transaction_info([job], projects)
240+
_record_transaction_info([job], projects, skip_send_first_transaction=False)
241241

242242
return spans

tests/sentry/event_manager/test_event_manager.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
from arroyo.types import Partition, Topic
1717
from django.conf import settings
1818
from django.core.cache import cache
19+
from django.db.models import F
1920
from django.utils import timezone
2021

2122
from sentry import eventstore, nodestore, tsdb
2223
from sentry.attachments import CachedAttachment, attachment_cache
23-
from sentry.constants import MAX_VERSION_LENGTH, DataCategory
24+
from sentry.constants import MAX_VERSION_LENGTH, DataCategory, InsightModules
2425
from sentry.dynamic_sampling import (
2526
ExtendedBoostedRelease,
2627
Platform,
@@ -59,6 +60,7 @@
5960
from sentry.models.grouprelease import GroupRelease
6061
from sentry.models.groupresolution import GroupResolution
6162
from sentry.models.grouptombstone import GroupTombstone
63+
from sentry.models.project import Project
6264
from sentry.models.pullrequest import PullRequest, PullRequestCommit
6365
from sentry.models.release import Release
6466
from sentry.models.releasecommit import ReleaseCommit
@@ -1577,15 +1579,19 @@ def test_transaction_sampler_and_receive(self) -> None:
15771579
manager.normalize()
15781580
manager.save(self.project.id)
15791581

1580-
@patch("sentry.event_manager.record_event_processed")
1582+
@patch("sentry.event_manager.record_first_transaction")
1583+
@patch("sentry.event_manager.record_first_insight_span")
15811584
@patch("sentry.event_manager.record_release_received")
15821585
@patch("sentry.ingest.transaction_clusterer.datasource.redis._record_sample")
15831586
def test_transaction_sampler_and_receive_mock_called(
15841587
self,
15851588
mock_record_sample: mock.MagicMock,
15861589
mock_record_release: mock.MagicMock,
1587-
mock_record_event: mock.MagicMock,
1590+
mock_record_insight: mock.MagicMock,
1591+
mock_record_transaction: mock.MagicMock,
15881592
) -> None:
1593+
self.project.update(flags=F("flags").bitand(~Project.flags.has_transactions))
1594+
15891595
manager = EventManager(
15901596
make_event(
15911597
**{
@@ -1606,8 +1612,14 @@ def test_transaction_sampler_and_receive_mock_called(
16061612
"start_timestamp": 0,
16071613
"timestamp": 1,
16081614
"same_process_as_parent": True,
1609-
"op": "default",
1610-
"description": "span a",
1615+
"op": "db.redis",
1616+
"description": "EXEC *",
1617+
"sentry_tags": {
1618+
"description": "EXEC *",
1619+
"category": "db",
1620+
"op": "db.redis",
1621+
"transaction": "/app/index",
1622+
},
16111623
},
16121624
{
16131625
"trace_id": "a0fa8803753e40fd8124b21eeb2986b5",
@@ -1633,6 +1645,7 @@ def test_transaction_sampler_and_receive_mock_called(
16331645
"timestamp": "2019-06-14T14:01:40Z",
16341646
"start_timestamp": "2019-06-14T14:01:40Z",
16351647
"type": "transaction",
1648+
"release": "foo@1.0.0",
16361649
"transaction_info": {
16371650
"source": "url",
16381651
},
@@ -1642,8 +1655,9 @@ def test_transaction_sampler_and_receive_mock_called(
16421655
manager.normalize()
16431656
event = manager.save(self.project.id)
16441657

1645-
mock_record_event.assert_called_once_with(self.project, event)
1646-
mock_record_release.assert_called_once_with(self.project, event)
1658+
mock_record_release.assert_called_once_with(self.project, "foo@1.0.0")
1659+
mock_record_insight.assert_called_once_with(self.project, InsightModules.DB)
1660+
mock_record_transaction.assert_called_once_with(self.project, event.datetime)
16471661
assert mock_record_sample.mock_calls == [
16481662
mock.call(ClustererNamespace.TRANSACTIONS, self.project, "wait")
16491663
]

0 commit comments

Comments
 (0)