Просмотр исходного кода

feat:issueless events. Prepare data structures for issueless events (#13822)

This PR prepares the ground for skipping issue creation if the
event has no fingerprint by removing some assumption that the group
should always exists.
Filippo Pacifici 5 лет назад
Родитель
Сommit
618bb0cc6f

+ 16 - 0
src/sentry/api/bases/event.py

@@ -0,0 +1,16 @@
+from __future__ import absolute_import
+
+from sentry.api.bases.project import ProjectPermission
+
+
+class EventPermission(ProjectPermission):
+    scope_map = {
+        'GET': ['event:read', 'event:write', 'event:admin'],
+        'POST': ['event:write', 'event:admin'],
+        'PUT': ['event:write', 'event:admin'],
+        'DELETE': ['event:admin'],
+    }
+
+    def has_object_permission(self, request, view, event):
+        return super(EventPermission, self).has_object_permission(
+            request, view, event.project)

+ 3 - 3
src/sentry/api/endpoints/event_details.py

@@ -3,14 +3,14 @@ from __future__ import absolute_import
 from rest_framework.response import Response
 
 from sentry.api.base import Endpoint
-from sentry.api.bases.group import GroupPermission
+from sentry.api.bases.event import EventPermission
 from sentry.api.exceptions import ResourceDoesNotExist
 from sentry.api.serializers import DetailedEventSerializer, serialize
 from sentry.models import Event
 
 
 class EventDetailsEndpoint(Endpoint):
-    permission_classes = (GroupPermission, )
+    permission_classes = (EventPermission, )
 
     def get(self, request, event_id):
         """
@@ -27,7 +27,7 @@ class EventDetailsEndpoint(Endpoint):
         if event is None:
             raise ResourceDoesNotExist
 
-        self.check_object_permissions(request, event.group)
+        self.check_object_permissions(request, event)
 
         Event.objects.bind_nodes([event], 'data')
 

+ 2 - 2
src/sentry/api/serializers/models/event.py

@@ -247,7 +247,7 @@ class EventSerializer(Serializer):
 
         d = {
             'id': six.text_type(obj.id),
-            'groupID': six.text_type(obj.group_id),
+            'groupID': six.text_type(obj.group_id) if obj.group_id else None,
             'eventID': six.text_type(obj.event_id),
             'projectID': six.text_type(obj.project_id),
             'size': obj.size,
@@ -359,7 +359,7 @@ class SimpleEventSerializer(EventSerializer):
         return {
             'id': six.text_type(obj.id),
             'event.type': six.text_type(obj.type),
-            'groupID': six.text_type(obj.group_id),
+            'groupID': six.text_type(obj.group_id) if obj.group_id else None,
             'eventID': six.text_type(obj.event_id),
             'projectID': six.text_type(obj.project_id),
             # XXX for 'message' this doesn't do the proper resolution of logentry

+ 5 - 4
src/sentry/event_manager.py

@@ -725,7 +725,7 @@ class EventManager(object):
                     extra={
                         'event_uuid': event_id,
                         'project_id': project.id,
-                        'group_id': group.id,
+                        'group_id': group.id if group else None,
                         'model': EventMapping.__name__,
                     }
                 )
@@ -833,7 +833,7 @@ class EventManager(object):
                     extra={
                         'event_uuid': event_id,
                         'project_id': project.id,
-                        'group_id': group.id,
+                        'group_id': group.id if group else None,
                         'model': Event.__name__,
                     }
                 )
@@ -842,7 +842,7 @@ class EventManager(object):
             tagstore.delay_index_event_tags(
                 organization_id=project.organization_id,
                 project_id=project.id,
-                group_id=group.id,
+                group_id=group.id if group else None,
                 environment_id=environment.id,
                 event_id=event.id,
                 tags=event.tags,
@@ -885,7 +885,8 @@ class EventManager(object):
         if not raw:
             if not project.first_event:
                 project.update(first_event=date)
-                first_event_received.send_robust(project=project, group=group, sender=Project)
+                first_event_received.send_robust(
+                    project=project, event=event, sender=Project)
 
         eventstream.insert(
             group=group,

+ 17 - 7
src/sentry/models/event.py

@@ -89,6 +89,8 @@ class EventCommon(object):
     @property
     def group(self):
         from sentry.models import Group
+        if not self.group_id:
+            return None
         if not hasattr(self, '_group_cache'):
             self._group_cache = Group.objects.get(id=self.group_id)
         return self._group_cache
@@ -223,7 +225,9 @@ class EventCommon(object):
     @property
     def culprit(self):
         # For a while events did not save the culprit
-        return self.data.get('culprit') or self.group.culprit
+        if self.group_id:
+            return self.data.get('culprit') or self.group.culprit
+        return self.data.get('culprit')
 
     @property
     def location(self):
@@ -353,7 +357,7 @@ class EventCommon(object):
 
         # for a long time culprit was not persisted.  In those cases put
         # the culprit in from the group.
-        if data.get('culprit') is None:
+        if data.get('culprit') is None and self.group_id:
             data['culprit'] = self.group.culprit
 
         # Override title and location with dynamically generated data
@@ -370,12 +374,18 @@ class EventCommon(object):
     def level(self):
         # we might want to move to this:
         # return LOG_LEVELS_MAP.get(self.get_level_display()) or self.group.level
-        return self.group.level
+        if self.group:
+            return self.group.level
+        else:
+            return None
 
     def get_level_display(self):
         # we might want to move to this:
         # return self.get_tag('level') or self.group.get_level_display()
-        return self.group.get_level_display()
+        if self.group:
+            return self.group.get_level_display()
+        else:
+            return None
 
     # deprecated accessors
 
@@ -630,7 +640,7 @@ class SnubaEvent(EventCommon):
             conditions=conditions,
             filter_keys={
                 'project_id': [self.project_id],
-                'issue': [self.group_id],
+                'issue': [self.group_id] if self.group_id else [],
             },
             orderby=['timestamp', 'event_id'],
             limit=1,
@@ -660,7 +670,7 @@ class SnubaEvent(EventCommon):
             conditions=conditions,
             filter_keys={
                 'project_id': [self.project_id],
-                'issue': [self.group_id],
+                'issue': [self.group_id] if self.group_id else [],
             },
             orderby=['-timestamp', '-event_id'],
             limit=1,
@@ -778,7 +788,7 @@ class EventSubjectTemplateData(object):
             return self.event.project.get_full_name()
         elif name == 'projectID':
             return self.event.project.slug
-        elif name == 'shortID':
+        elif name == 'shortID' and self.event.group_id:
             return self.event.group.qualified_short_id
         elif name == 'orgID':
             return self.event.organization.slug

+ 1 - 1
src/sentry/receivers/features.py

@@ -50,7 +50,7 @@ DEFAULT_TAGS = frozenset(
 
 # First Event
 @first_event_received.connect(weak=False)
-def record_first_event(project, group, **kwargs):
+def record_first_event(project, **kwargs):
     FeatureAdoption.objects.record(
         organization_id=project.organization_id, feature_slug="first_event", complete=True
     )

+ 7 - 7
src/sentry/receivers/onboarding.py

@@ -93,7 +93,7 @@ def record_raven_installed(project, user, **kwargs):
 
 
 @first_event_received.connect(weak=False)
-def record_first_event(project, group, **kwargs):
+def record_first_event(project, event, **kwargs):
     """
     Requires up to 2 database calls, but should only run with the first event in
     any project, so performance should not be a huge bottleneck.
@@ -111,7 +111,7 @@ def record_first_event(project, group, **kwargs):
             'project_id': project.id,
             'date_completed': project.first_event,
             'data': {
-                'platform': group.platform
+                'platform': event.platform
             },
         }
     )
@@ -124,7 +124,7 @@ def record_first_event(project, group, **kwargs):
             user_id=user.id,
             organization_id=project.organization_id,
             project_id=project.id,
-            platform=group.platform,
+            platform=event.platform,
         )
         return
 
@@ -138,8 +138,8 @@ def record_first_event(project, group, **kwargs):
 
     # Only counts if it's a new project and platform
     if oot.project_id != project.id and oot.data.get(
-        'platform', group.platform
-    ) != group.platform:
+        'platform', event.platform
+    ) != event.platform:
         rows_affected, created = OrganizationOnboardingTask.objects.create_or_update(
             organization_id=project.organization_id,
             task=OnboardingTask.SECOND_PLATFORM,
@@ -149,7 +149,7 @@ def record_first_event(project, group, **kwargs):
                 'project_id': project.id,
                 'date_completed': project.first_event,
                 'data': {
-                    'platform': group.platform
+                    'platform': event.platform
                 },
             }
         )
@@ -159,7 +159,7 @@ def record_first_event(project, group, **kwargs):
                 user_id=user.id,
                 organization_id=project.organization_id,
                 project_id=project.id,
-                platform=group.platform,
+                platform=event.platform,
             )
 
 

+ 1 - 1
src/sentry/signals.py

@@ -66,7 +66,7 @@ event_saved = BetterSignal(providing_args=["project"])
 # Organization Onboarding Signals
 project_created = BetterSignal(providing_args=["project", "user"])
 first_event_pending = BetterSignal(providing_args=["project", "user"])
-first_event_received = BetterSignal(providing_args=["project", "group"])
+first_event_received = BetterSignal(providing_args=["project", "event"])
 member_invited = BetterSignal(providing_args=["member", "user"])
 member_joined = BetterSignal(providing_args=["member", "organization"])
 issue_tracker_used = BetterSignal(providing_args=["plugin", "project", "user"])

+ 3 - 0
src/sentry/similarity/features.py

@@ -102,6 +102,9 @@ class FeatureSet(object):
 
         items = []
         for event in events:
+            # TODO: how we index events?
+            if not event.group_id:
+                continue
             for label, features in self.extract(event).items():
                 if scope is None:
                     scope = self.__get_scope(event.project)

+ 8 - 7
src/sentry/testutils/factories.py

@@ -447,11 +447,11 @@ class Factories(object):
         return useremail
 
     @staticmethod
-    def create_event(group, event_id=None, normalize=True, **kwargs):
+    def create_event(group=None, project=None, event_id=None, normalize=True, **kwargs):
         # XXX: Do not use this method for new tests! Prefer `store_event`.
         if event_id is None:
             event_id = uuid4().hex
-        kwargs.setdefault('project', group.project)
+        kwargs.setdefault('project', project if project else group.project)
         kwargs.setdefault('data', copy.deepcopy(DEFAULT_EVENT_DATA))
         kwargs.setdefault('platform', kwargs['data'].get('platform', 'python'))
         kwargs.setdefault('message', kwargs['data'].get('message', 'message'))
@@ -497,11 +497,12 @@ class Factories(object):
         )
 
         event = Event(event_id=event_id, group=group, **kwargs)
-        EventMapping.objects.create(
-            project_id=event.project.id,
-            event_id=event_id,
-            group=group,
-        )
+        if group:
+            EventMapping.objects.create(
+                project_id=event.project.id,
+                event_id=event_id,
+                group=group,
+            )
         # emulate EventManager refs
         event.data.bind_ref(event)
         event.save()

Некоторые файлы не были показаны из-за большого количества измененных файлов