Repository: getsentry/sentry

Issue:
Search related events by event ID

![image](https://user-images.githubusercontent.com/2153/29005586-1dfdfbf6-7a93-11e7-9127-c82c0356b4c6.png)

Right now you can search [by message or tags](https://github.com/getsentry/sentry/blob/master/src/sentry/api/endpoints/group_events.py#L104), but not individual event ID. This is useful when trying to locate a specific event. More useful now that sampling has been disabled by default.

We should also add a column for event ID here.

Refs #3147


Discussion:

Resolving patch:
diff --git a/src/sentry/api/endpoints/group_events.py b/src/sentry/api/endpoints/group_events.py
--- a/src/sentry/api/endpoints/group_events.py
+++ b/src/sentry/api/endpoints/group_events.py
@@ -12,6 +12,7 @@
 from sentry.utils.apidocs import scenario, attach_scenarios
 from rest_framework.response import Response
 from sentry.search.utils import InvalidQuery
+from django.db.models import Q
 
 
 @scenario('ListAvailableSamples')
@@ -40,6 +41,7 @@ def get(self, request, group):
         )
 
         query = request.GET.get('query')
+
         if query:
             try:
                 query_kwargs = parse_query(group.project, query, request.user)
@@ -47,9 +49,12 @@ def get(self, request, group):
                 return Response({'detail': six.text_type(exc)}, status=400)
 
             if query_kwargs['query']:
-                events = events.filter(
-                    message__icontains=query_kwargs['query'],
-                )
+                q = Q(message__icontains=query_kwargs['query'])
+
+                if len(query) == 32:
+                    q |= Q(event_id__exact=query_kwargs['query'])
+
+                events = events.filter(q)
 
             if query_kwargs['tags']:
                 try:


Test patch:
diff --git a/tests/sentry/api/endpoints/test_group_events.py b/tests/sentry/api/endpoints/test_group_events.py
--- a/tests/sentry/api/endpoints/test_group_events.py
+++ b/tests/sentry/api/endpoints/test_group_events.py
@@ -120,3 +120,51 @@ def test_tags(self):
 
         assert response.status_code == 200, response.content
         assert len(response.data) == 0
+
+    def test_search_event_by_id(self):
+        self.login_as(user=self.user)
+
+        group = self.create_group()
+        event_1 = self.create_event('a' * 32, group=group)
+        self.create_event('b' * 32, group=group)
+        query = event_1.event_id
+
+        url = '/api/0/issues/{}/events/?query={}'.format(group.id, query)
+        response = self.client.get(url, format='json')
+
+        assert response.status_code == 200, response.content
+        assert len(response.data) == 1
+        assert response.data[0]['eventID'] == event_1.event_id
+
+    def test_search_event_by_message(self):
+        self.login_as(user=self.user)
+
+        group = self.create_group()
+        event_1 = self.create_event(event_id='a' * 32, group=group, message="foo bar hello world")
+
+        event_2 = self.create_event(event_id='b' * 32, group=group, message='this bar hello world ')
+
+        query_1 = "foo"
+        query_2 = "hello+world"
+
+        # Single Word Query
+        url = '/api/0/issues/{}/events/?query={}'.format(group.id, query_1)
+        response = self.client.get(url, format='json')
+
+        assert response.status_code == 200, response.content
+        assert len(response.data) == 1
+        assert response.data[0]['id'] == six.text_type(
+            event_1.id) and response.data[0]['eventID'] == event_1.event_id
+
+        # Multiple Word Query
+        url = '/api/0/issues/{}/events/?query={}'.format(group.id, query_2)
+        response = self.client.get(url, format='json')
+
+        assert response.status_code == 200, response.content
+        assert len(response.data) == 2
+        assert sorted(map(lambda x: x['id'], response.data)) == sorted(
+            [
+                six.text_type(event_1.id),
+                six.text_type(event_2.id),
+            ]
+        )