Browse Source

feat(feedback): shim reports to feedbacks in post_process (#70200)

Shim user reports to feedback here in post process. a re-do of
https://github.com/getsentry/sentry/pull/70117 but not in ingestion
hotpath

Follow up: instead of calling shim directly, create a celery task and
call the celery task instead. so that way when we enable spam detection,
any latency there will not affect post process workers
Josh Ferge 10 months ago
parent
commit
204c222e0b

+ 2 - 2
src/sentry/feedback/usecases/create_feedback.py

@@ -10,7 +10,7 @@ import jsonschema
 
 from sentry import features, options
 from sentry.constants import DataCategory
-from sentry.eventstore.models import Event
+from sentry.eventstore.models import Event, GroupEvent
 from sentry.feedback.usecases.spam_detection import is_spam
 from sentry.issues.grouptype import FeedbackGroup
 from sentry.issues.issue_occurrence import IssueEvidence, IssueOccurrence
@@ -297,7 +297,7 @@ class UserReportShimDict(TypedDict):
 
 def shim_to_feedback(
     report: UserReportShimDict,
-    event: Event,
+    event: Event | GroupEvent,
     project: Project,
     source: FeedbackCreationSource,
 ):

+ 14 - 0
src/sentry/tasks/post_process.py

@@ -1390,6 +1390,7 @@ def check_has_high_priority_alerts(job: PostProcessJob) -> None:
 
 
 def link_event_to_user_report(job: PostProcessJob) -> None:
+    from sentry.feedback.usecases.create_feedback import FeedbackCreationSource, shim_to_feedback
     from sentry.models.userreport import UserReport
 
     event = job["event"]
@@ -1408,6 +1409,19 @@ def link_event_to_user_report(job: PostProcessJob) -> None:
             group_id__isnull=True,
             environment_id__isnull=True,
         )
+        for report in user_reports_without_group:
+            shim_to_feedback(
+                {
+                    "name": report.name,
+                    "email": report.email,
+                    "comments": report.comments,
+                    "event_id": report.event_id,
+                    "level": "error",
+                },
+                event,
+                project,
+                FeedbackCreationSource.USER_REPORT_ENVELOPE,
+            )
 
         user_reports_updated = user_reports_without_group.update(
             group_id=group.id, environment_id=event.get_environment().id

+ 89 - 1
tests/sentry/tasks/test_post_process.py

@@ -2051,7 +2051,6 @@ class UserReportEventLinkTestMixin(BasePostProgressGroupMixin):
 
     def test_user_report_gets_environment_with_new_link_features(self):
         with self.feature("organizations:user-feedback-event-link-ingestion-changes"):
-
             project = self.create_project()
             environment = Environment.objects.create(
                 organization_id=project.organization_id, name="production"
@@ -2080,6 +2079,95 @@ class UserReportEventLinkTestMixin(BasePostProgressGroupMixin):
 
         assert UserReport.objects.get(event_id=event_id).environment_id == environment.id
 
+    @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka")
+    def test_user_report_shims_to_feedback(self, mock_produce_occurrence_to_kafka):
+        with self.feature("organizations:user-feedback-event-link-ingestion-changes"):
+            project = self.create_project()
+            environment = Environment.objects.create(
+                organization_id=project.organization_id, name="production"
+            )
+            environment.add_project(project)
+
+            event_id = "a" * 32
+
+            UserReport.objects.create(
+                project_id=project.id,
+                event_id=event_id,
+                name="Foo Bar",
+                email="bar@example.com",
+                comments="It Broke!!!",
+            )
+
+            event = self.store_event(
+                data={"environment": environment.name, "event_id": event_id},
+                project_id=project.id,
+            )
+
+            self.call_post_process_group(
+                is_new=True,
+                is_regression=False,
+                is_new_group_environment=True,
+                event=event,
+            )
+
+            report1 = UserReport.objects.get(project_id=project.id, event_id=event.event_id)
+            assert report1.group_id == event.group_id
+            assert report1.environment_id == event.get_environment().id
+
+            assert len(mock_produce_occurrence_to_kafka.mock_calls) == 1
+            mock_event_data = mock_produce_occurrence_to_kafka.call_args_list[0][1]["event_data"]
+
+            assert mock_event_data["contexts"]["feedback"]["contact_email"] == "bar@example.com"
+            assert mock_event_data["contexts"]["feedback"]["message"] == "It Broke!!!"
+            assert mock_event_data["contexts"]["feedback"]["name"] == "Foo Bar"
+            assert mock_event_data["environment"] == environment.name
+            assert mock_event_data["tags"] == [
+                ["environment", environment.name],
+                ["level", "error"],
+            ]
+
+            assert mock_event_data["platform"] == "other"
+            assert mock_event_data["contexts"]["feedback"]["associated_event_id"] == event.event_id
+            assert mock_event_data["level"] == "error"
+
+    @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka")
+    def test_user_reports_no_shim_if_group_exists_on_report(self, mock_produce_occurrence_to_kafka):
+        with self.feature("organizations:user-feedback-event-link-ingestion-changes"):
+            project = self.create_project()
+            environment = Environment.objects.create(
+                organization_id=project.organization_id, name="production"
+            )
+            environment.add_project(project)
+
+            event_id = "a" * 32
+
+            UserReport.objects.create(
+                project_id=project.id,
+                event_id=event_id,
+                name="Foo Bar",
+                email="bar@example.com",
+                comments="It Broke!!!",
+                environment_id=environment.id,
+            )
+
+            event = self.store_event(
+                data={"environment": environment.name, "event_id": event_id},
+                project_id=project.id,
+            )
+
+            self.call_post_process_group(
+                is_new=True,
+                is_regression=False,
+                is_new_group_environment=True,
+                event=event,
+            )
+
+            # since the environment already exists on this user report, we know that
+            # the report and the event have already been linked, so no feedback shim should be produced
+            report1 = UserReport.objects.get(project_id=project.id, event_id=event.event_id)
+            assert report1.environment_id == event.get_environment().id
+            assert len(mock_produce_occurrence_to_kafka.mock_calls) == 0
+
 
 class DetectNewEscalationTestMixin(BasePostProgressGroupMixin):
     @patch("sentry.tasks.post_process.run_post_process_job", side_effect=run_post_process_job)