def _get_events_snuba(self, request, group, environments, query, tags, start, end): default_end = timezone.now() default_start = default_end - timedelta(days=90) params = { "issue.id": [group.id], "project_id": [group.project_id], "start": start if start else default_start, "end": end if end else default_end, } direct_hit_resp = get_direct_hit_response(request, query, params, "api.group-events") if direct_hit_resp: return direct_hit_resp if environments: params["environment"] = [env.name for env in environments] full = request.GET.get("full", False) snuba_filter = get_filter(request.GET.get("query", None), params) snuba_cols = None if full else eventstore.full_columns data_fn = partial( eventstore.get_events, additional_columns=snuba_cols, referrer="api.group-events", filter=snuba_filter, ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize(results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn), )
def test_no_group(self): """ Use the SimpleEventSerializer to serialize an event without group """ event = self.store_event( data={ "event_id": "a" * 32, "start_timestamp": iso_format(before_now(minutes=1)), "timestamp": iso_format(before_now(minutes=1)), "user": { "email": "*****@*****.**" }, "type": "transaction", "transaction": "api.issue.delete", "spans": [], "contexts": { "trace": { "op": "foobar", "trace_id": "a" * 32, "span_id": "a" * 16 } }, }, project_id=self.project.id, ) result = serialize(event, None, SimpleEventSerializer()) assert result["groupID"] is None
def _get_events_snuba(self, request, group, environments, query, tags, start, end): default_end = timezone.now() default_start = default_end - timedelta(days=90) params = { "group_ids": [group.id], "project_id": [group.project_id], "organization_id": group.project.organization_id, "start": start if start else default_start, "end": end if end else default_end, } direct_hit_resp = get_direct_hit_response(request, query, params, "api.group-events") if direct_hit_resp: return direct_hit_resp if environments: params["environment"] = [env.name for env in environments] full = request.GET.get("full", False) try: snuba_filter = get_filter(request.GET.get("query", None), params) except InvalidSearchQuery as e: raise ParseError(detail=str(e)) snuba_filter.conditions.append(["event.type", "!=", "transaction"]) data_fn = partial(eventstore.get_events, referrer="api.group-events", filter=snuba_filter) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize(results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn), )
def test_no_group(self): """ Use the SimpleEventSerializer to serialize an event without group """ event = SnubaEvent({ 'event_id': 'a', 'project_id': 1, 'message': 'hello there', 'title': 'hi', 'type': 'default', 'location': 'somewhere', 'culprit': 'foo', 'timestamp': '2011-01-01T00:00:00Z', 'user_id': '123', 'email': '*****@*****.**', 'username': '******', 'ip_address': '192.168.0.1', 'platform': 'asdf', 'group_id': None, 'tags.key': ['sentry:user'], 'tags.value': ['email:[email protected]'], }) result = serialize(event, None, SimpleEventSerializer()) assert result['groupID'] is None
def test_no_group(self): """ Use the SimpleEventSerializer to serialize an event without group """ event = SnubaEvent({ "event_id": "a", "project_id": 1, "message": "hello there", "title": "hi", "type": "default", "location": "somewhere", "culprit": "foo", "timestamp": "2011-01-01T00:00:00Z", "user_id": "123", "email": "*****@*****.**", "username": "******", "ip_address": "192.168.0.1", "platform": "asdf", "group_id": None, "tags.key": ["sentry:user"], "tags.value": ["email:[email protected]"], }) result = serialize(event, None, SimpleEventSerializer()) assert result["groupID"] is None
def _get_events_snuba(self, request, project): from sentry.api.paginator import GenericOffsetPaginator from sentry.models import SnubaEvent from sentry.utils.snuba import raw_query query = request.GET.get('query') conditions = [] if query: conditions.append( [['positionCaseInsensitive', ['message', "'%s'" % (query, )]], '!=', 0]) full = request.GET.get('full', False) snuba_cols = SnubaEvent.minimal_columns if full else SnubaEvent.selected_columns now = timezone.now() data_fn = partial( # extract 'data' from raw_query result lambda *args, **kwargs: raw_query(*args, **kwargs)['data'], start=now - timedelta(days=90), end=now, conditions=conditions, filter_keys={'project_id': [project.id]}, selected_columns=snuba_cols, orderby='-timestamp', referrer='api.project-events', ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn))
def get(self, request, organization): # Check for a direct hit on event ID query = request.GET.get("query", "").strip() try: direct_hit_resp = get_direct_hit_response( request, query, self.get_filter_params(request, organization), "api.organization-events-direct-hit", ) except (OrganizationEventsError, NoProjects): pass else: if direct_hit_resp: return direct_hit_resp full = request.GET.get("full", False) try: snuba_args = self.get_snuba_query_args_legacy( request, organization) except OrganizationEventsError as exc: return Response({"detail": exc.message}, status=400) except NoProjects: # return empty result if org doesn't have projects # or user doesn't have access to projects in org data_fn = lambda *args, **kwargs: [] else: cols = None if full else eventstore.full_columns data_fn = partial( eventstore.get_events, additional_columns=cols, referrer="api.organization-events", filter=eventstore.Filter( start=snuba_args["start"], end=snuba_args["end"], conditions=snuba_args["conditions"], project_ids=snuba_args["filter_keys"].get( "project_id", None), group_ids=snuba_args["filter_keys"].get("group_id", None), ), ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize(results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn), )
def _get_events_snuba(self, request, group, environments, query, tags, start, end): default_end = timezone.now() default_start = default_end - timedelta(days=90) params = { 'issue.id': [group.id], 'project_id': [group.project_id], 'start': start if start else default_start, 'end': end if end else default_end } direct_hit_resp = get_direct_hit_response(request, query, params, 'api.group-events') if direct_hit_resp: return direct_hit_resp if environments: params['environment'] = [env.name for env in environments] full = request.GET.get('full', False) snuba_args = get_snuba_query_args(request.GET.get('query', None), params) # TODO(lb): remove once boolean search is fully functional if snuba_args: has_boolean_op_flag = features.has('organizations:boolean-search', group.project.organization, actor=request.user) if snuba_args.pop('has_boolean_terms', False) and not has_boolean_op_flag: raise GroupEventsError( 'Boolean search operator OR and AND not allowed in this search.' ) snuba_cols = SnubaEvent.minimal_columns if full else SnubaEvent.selected_columns data_fn = partial( # extract 'data' from raw_query result lambda *args, **kwargs: raw_query(*args, **kwargs)['data'], selected_columns=snuba_cols, orderby='-timestamp', referrer='api.group-events', **snuba_args) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn))
def test_user(self): """ Use the SimpleEventSerializer to serialize an event """ group = self.create_group() event = SnubaEvent({ "event_id": "a", "project_id": 1, "message": "hello there", "title": "hi", "type": "default", "location": "somewhere", "culprit": "foo", "timestamp": "2011-01-01T00:00:00Z", "user_id": "123", "email": "*****@*****.**", "username": "******", "ip_address": "192.168.0.1", "platform": "asdf", "group_id": group.id, "tags.key": ["sentry:user"], "tags.value": ["email:[email protected]"], }) result = serialize(event, None, SimpleEventSerializer()) # Make sure we didn't have to call out to Nodestore to get the data # required to serialize this event and the NodeData is still empty. assert (event.data._node_data is None), "SimpleEventSerializer should not load Nodestore data." assert result["eventID"] == event.event_id assert result["projectID"] == six.text_type(event.project_id) assert result["groupID"] == six.text_type(group.id) assert result["message"] == event.message assert result["title"] == event.title assert result["location"] == event.location assert result["culprit"] == event.culprit assert result["dateCreated"] == event.datetime assert result["user"]["id"] == event.get_minimal_user().id assert result["user"]["email"] == event.get_minimal_user().email assert result["user"]["username"] == event.get_minimal_user().username assert result["user"]["ip_address"] == event.get_minimal_user( ).ip_address assert result["tags"] == [{ "key": "user", "value": "email:[email protected]", "query": 'user.email:"*****@*****.**"' }]
def get(self, request: Request, project) -> Response: """ List a Project's Events ``````````````````````` Return a list of events bound to a project. Note: This endpoint is experimental and may be removed without notice. :qparam bool full: if this is set to true then the event payload will include the full event body, including the stacktrace. Set to 1 to enable. :pparam string organization_slug: the slug of the organization the groups belong to. :pparam string project_slug: the slug of the project the groups belong to. """ from sentry.api.paginator import GenericOffsetPaginator query = request.GET.get("query") conditions = [] if query: conditions.append( [["positionCaseInsensitive", ["message", f"'{query}'"]], "!=", 0]) event_filter = eventstore.Filter(conditions=conditions, project_ids=[project.id]) if features.has("organizations:project-event-date-limit", project.organization, actor=request.user): event_filter.start = timezone.now() - timedelta(days=7) full = request.GET.get("full", False) data_fn = partial( eventstore.get_events, filter=event_filter, referrer="api.project-events", ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize(results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn), )
def get(self, request, project): """ List a Project's Events ``````````````````````` Return a list of events bound to a project. Note: This endpoint is experimental and may be removed without notice. :pparam string organization_slug: the slug of the organization the groups belong to. :pparam string project_slug: the slug of the project the groups belong to. """ from sentry.api.paginator import GenericOffsetPaginator from sentry.models import SnubaEvent from sentry.utils.snuba import raw_query query = request.GET.get('query') conditions = [] if query: conditions.append( [['positionCaseInsensitive', ['message', "'%s'" % (query, )]], '!=', 0]) full = request.GET.get('full', False) snuba_cols = SnubaEvent.minimal_columns if full else SnubaEvent.selected_columns now = timezone.now() data_fn = partial( # extract 'data' from raw_query result lambda *args, **kwargs: raw_query(*args, **kwargs)['data'], start=now - timedelta(days=90), end=now, conditions=conditions, filter_keys={'project_id': [project.id]}, selected_columns=snuba_cols, orderby='-timestamp', referrer='api.project-events', ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn))
def test_user(self): """ Use the SimpleEventSerializer to serialize an event """ group = self.create_group() event = SnubaEvent({ 'event_id': 'a', 'project_id': 1, 'message': 'hello there', 'title': 'hi', 'type': 'default', 'location': 'somewhere', 'culprit': 'foo', 'timestamp': '2011-01-01T00:00:00Z', 'user_id': '123', 'email': '*****@*****.**', 'username': '******', 'ip_address': '192.168.0.1', 'platform': 'asdf', 'group_id': group.id, 'tags.key': ['sentry:user'], 'tags.value': ['email:[email protected]'], }) result = serialize(event, None, SimpleEventSerializer()) # Make sure we didn't have to call out to Nodestore to get the data # required to serialize this event and the NodeData is still empty. assert event.data._node_data is None, "SimpleEventSerializer should not load Nodestore data." assert result['eventID'] == event.event_id assert result['projectID'] == six.text_type(event.project_id) assert result['groupID'] == six.text_type(group.id) assert result['message'] == event.message assert result['title'] == event.title assert result['location'] == event.location assert result['culprit'] == event.culprit assert result['dateCreated'] == event.datetime assert result['user']['id'] == event.user_id assert result['user']['email'] == event.email assert result['user']['username'] == event.username assert result['user']['ip_address'] == event.ip_address assert result['tags'] == [{ 'key': 'user', 'value': 'email:[email protected]', 'query': 'user.email:[email protected]', }]
def get(self, request, organization): if features.has('organizations:events-v2', organization, actor=request.user): return self.get_v2(request, organization) # Check for a direct hit on event ID query = request.GET.get('query', '').strip() try: direct_hit_resp = get_direct_hit_response( request, query, self.get_filter_params(request, organization), 'api.organization-events' ) except (OrganizationEventsError, NoProjects): pass else: if direct_hit_resp: return direct_hit_resp full = request.GET.get('full', False) try: snuba_args = self.get_snuba_query_args(request, organization) except OrganizationEventsError as exc: return Response({'detail': exc.message}, status=400) except NoProjects: # return empty result if org doesn't have projects # or user doesn't have access to projects in org data_fn = lambda *args, **kwargs: [] else: snuba_cols = SnubaEvent.minimal_columns if full else SnubaEvent.selected_columns data_fn = partial( # extract 'data' from raw_query result lambda *args, **kwargs: raw_query(*args, **kwargs)['data'], selected_columns=snuba_cols, orderby='-timestamp', referrer='api.organization-events', **snuba_args ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn) )
def _get_events_snuba(self, request, group, environments, query, tags, start, end): default_end = timezone.now() default_start = default_end - timedelta(days=90) params = { "issue.id": [group.id], "project_id": [group.project_id], "start": start if start else default_start, "end": end if end else default_end, } direct_hit_resp = get_direct_hit_response(request, query, params, "api.group-events") if direct_hit_resp: return direct_hit_resp if environments: params["environment"] = [env.name for env in environments] full = request.GET.get("full", False) snuba_args = get_snuba_query_args(request.GET.get("query", None), params) # TODO(lb): remove once boolean search is fully functional if snuba_args: has_boolean_op_flag = features.has("organizations:boolean-search", group.project.organization, actor=request.user) if snuba_args.pop("has_boolean_terms", False) and not has_boolean_op_flag: raise GroupEventsError( "Boolean search operator OR and AND not allowed in this search." ) snuba_cols = None if full else eventstore.full_columns data_fn = partial(eventstore.get_events, additional_columns=snuba_cols, referrer="api.group-events", **snuba_args) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize(results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn), )
def get(self, request, organization): # Check for a direct hit on event ID query = request.GET.get('query', '').strip() if is_event_id(query): try: snuba_args = get_snuba_query_args( query=u'id:{}'.format(query), params=self.get_filter_params(request, organization)) results = raw_query( selected_columns=SnubaEvent.selected_columns, referrer='api.organization-events', **snuba_args)['data'] if len(results) == 1: response = Response( serialize([SnubaEvent(row) for row in results], request.user)) response['X-Sentry-Direct-Hit'] = '1' return response except (OrganizationEventsError, NoProjects): pass try: snuba_args = self.get_snuba_query_args(request, organization) except OrganizationEventsError as exc: return Response({'detail': exc.message}, status=400) except NoProjects: # return empty result if org doesn't have projects # or user doesn't have access to projects in org data_fn = lambda *args, **kwargs: [] else: data_fn = partial( # extract 'data' from raw_query result lambda *args, **kwargs: raw_query(*args, **kwargs)['data'], selected_columns=SnubaEvent.selected_columns, orderby='-timestamp', referrer='api.organization-events', **snuba_args) serializer = SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn))
def _get_events_snuba(self, request, group, environments, query, tags, start, end): conditions = [] if query: msg_substr = [ 'positionCaseInsensitive', ['message', "'%s'" % (query, )] ] message_condition = [msg_substr, '!=', 0] if is_event_id(query): or_condition = [message_condition, ['event_id', '=', query]] conditions.append(or_condition) else: conditions.append(message_condition) if tags: for tag_name, tag_val in tags.items(): operator = 'IN' if isinstance(tag_val, list) else '=' conditions.append( [u'tags[{}]'.format(tag_name), operator, tag_val]) default_end = timezone.now() default_start = default_end - timedelta(days=90) data_fn = partial( # extract 'data' from raw_query result lambda *args, **kwargs: raw_query(*args, **kwargs)['data'], start=max(start, default_start) if start else default_start, end=min(end, default_end) if end else default_end, conditions=conditions, filter_keys={ 'project_id': [group.project_id], 'issue': [group.id] }, selected_columns=SnubaEvent.selected_columns, orderby='-timestamp', referrer='api.group-events', ) serializer = SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn))
def get(self, request, organization): logger.info("eventsv1.request", extra={"organization_id": organization.id}) # Check for a direct hit on event ID query = request.GET.get("query", "").strip() try: direct_hit_resp = get_direct_hit_response( request, query, self.get_filter_params(request, organization), "api.organization-events-direct-hit", ) except NoProjects: pass else: if direct_hit_resp: return direct_hit_resp full = request.GET.get("full", False) try: snuba_args = self.get_snuba_query_args_legacy(request, organization) except NoProjects: # return empty result if org doesn't have projects # or user doesn't have access to projects in org data_fn = lambda *args, **kwargs: [] else: data_fn = partial( eventstore.get_events, referrer="api.organization-events", filter=eventstore.Filter( start=snuba_args["start"], end=snuba_args["end"], conditions=snuba_args["conditions"], project_ids=snuba_args["filter_keys"].get("project_id", None), group_ids=snuba_args["filter_keys"].get("group_id", None), ), ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize(results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn), )
def get(self, request, project): """ List a Project's Events ``````````````````````` Return a list of events bound to a project. Note: This endpoint is experimental and may be removed without notice. :qparam bool full: if this is set to true then the event payload will include the full event body, including the stacktrace. Set to 1 to enable. :pparam string organization_slug: the slug of the organization the groups belong to. :pparam string project_slug: the slug of the project the groups belong to. """ from sentry.api.paginator import GenericOffsetPaginator query = request.GET.get("query") conditions = [] if query: conditions.append( [["positionCaseInsensitive", ["message", "'%s'" % (query,)]], "!=", 0] ) full = request.GET.get("full", False) cols = None if full else eventstore.full_columns data_fn = partial( eventstore.get_events, additional_columns=cols, filter=eventstore.Filter(conditions=conditions, project_ids=[project.id]), referrer="api.project-events", ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize(results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn), )
def test_user(self): """ Use the SimpleEventSerializer to serialize an event """ event = self.store_event( data={ "event_id": "a" * 32, "timestamp": iso_format(before_now(minutes=1)), "user": { "email": "*****@*****.**" }, }, project_id=self.project.id, ) result = serialize(event, None, SimpleEventSerializer()) assert result["eventID"] == event.event_id assert result["projectID"] == six.text_type(event.project_id) assert result["groupID"] == six.text_type(event.group.id) assert result["message"] == event.message assert result["title"] == event.title assert result["location"] == event.location assert result["culprit"] == event.culprit assert result["dateCreated"] == event.datetime assert result["user"]["id"] == event.get_minimal_user().id assert result["user"]["email"] == event.get_minimal_user().email assert result["user"]["username"] == event.get_minimal_user().username assert result["user"]["ip_address"] == event.get_minimal_user( ).ip_address assert result["tags"] == [ { "key": "level", "value": "error" }, { "key": "user", "value": "email:[email protected]", "query": 'user.email:"*****@*****.**"' }, ]
def get(self, request, project): """ List a Project's Events ``````````````````````` Return a list of events bound to a project. Note: This endpoint is experimental and may be removed without notice. :pparam string organization_slug: the slug of the organization the groups belong to. :pparam string project_slug: the slug of the project the groups belong to. """ from sentry.api.paginator import GenericOffsetPaginator query = request.GET.get('query') conditions = [] if query: conditions.append( [['positionCaseInsensitive', ['message', "'%s'" % (query, )]], '!=', 0]) full = request.GET.get('full', False) cols = None if full else eventstore.full_columns data_fn = partial( eventstore.get_events, conditions=conditions, filter_keys={'project_id': [project.id]}, additional_columns=cols, referrer='api.project-events', ) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate(request=request, on_results=lambda results: serialize( results, request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn))
def _get_events_snuba(self, request, group, environments, query, tags, start, end): default_end = timezone.now() default_start = default_end - timedelta(days=90) params = { 'issue.id': [group.id], 'project_id': [group.project_id], 'start': start if start else default_start, 'end': end if end else default_end } direct_hit_resp = get_direct_hit_response(request, query, params, 'api.group-events') if direct_hit_resp: return direct_hit_resp if environments: params['environment'] = [env.name for env in environments] full = request.GET.get('full', False) snuba_args = get_snuba_query_args(request.GET.get('query', None), params) snuba_cols = SnubaEvent.minimal_columns if full else SnubaEvent.selected_columns data_fn = partial( # extract 'data' from raw_query result lambda *args, **kwargs: raw_query(*args, **kwargs)['data'], selected_columns=snuba_cols, orderby='-timestamp', referrer='api.group-events', **snuba_args) serializer = EventSerializer() if full else SimpleEventSerializer() return self.paginate( request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user, serializer), paginator=GenericOffsetPaginator(data_fn=data_fn))