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]) 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=SnubaEvent.minimal_columns, orderby='-timestamp', referrer='api.project-events', ) return self.paginate(request=request, on_results=lambda results: serialize( [SnubaEvent(row) for row in results], request.user), paginator=GenericOffsetPaginator(data_fn=data_fn))
def get_events( self, filter, additional_columns=None, orderby=None, limit=DEFAULT_LIMIT, offset=DEFAULT_OFFSET, referrer="eventstore.get_events", ): """ Get events from Snuba. """ assert filter, "You must provide a filter" cols = self.__get_columns(additional_columns) orderby = orderby or DESC_ORDERING result = snuba.dataset_query( selected_columns=cols, start=filter.start, end=filter.end, conditions=filter.conditions, filter_keys=filter.filter_keys, orderby=orderby, limit=limit, offset=offset, referrer=referrer, ) if "error" not in result: return [SnubaEvent(evt) for evt in result["data"]] return []
def get_oldest_or_latest_event_for_environments(ordering, environments=[], issue_id=None, project_id=None): from sentry.utils import snuba from sentry.models import SnubaEvent conditions = [] if len(environments) > 0: conditions.append(['environment', 'IN', environments]) result = snuba.raw_query( start=datetime.utcfromtimestamp(0), end=datetime.utcnow(), selected_columns=SnubaEvent.selected_columns, conditions=conditions, filter_keys={ 'issue': [issue_id], 'project_id': [project_id], }, orderby=ordering.value, limit=1, ) if 'error' not in result and len(result['data']) == 1: return SnubaEvent(result['data'][0]) return None
def get_oldest_or_latest_event_for_environments(ordering, environments=(), issue_id=None, project_id=None): from sentry.utils import snuba from sentry.models import SnubaEvent conditions = [] if len(environments) > 0: conditions.append(["environment", "IN", environments]) result = snuba.raw_query( selected_columns=SnubaEvent.selected_columns, conditions=conditions, filter_keys={ "issue": [issue_id], "project_id": [project_id] }, orderby=ordering.value, limit=1, referrer="Group.get_latest", ) if "error" not in result and len(result["data"]) == 1: return SnubaEvent(result["data"][0]) return None
def get_events( self, start=None, end=None, additional_columns=None, conditions=None, filter_keys=None, orderby=DEFAULT_ORDERBY, limit=DEFAULT_LIMIT, offset=DEFAULT_OFFSET, ): """ Get events from Snuba. """ cols = self.__get_columns(additional_columns) result = snuba.raw_query( start=start, end=end, selected_columns=cols, conditions=conditions, filter_keys=filter_keys, orderby=orderby, limit=limit, offset=offset, referrer='eventstore.get_events', ) if 'error' not in result: return [SnubaEvent(evt) for evt in result['data']] return []
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_event_by_id(self, project_id, event_id, additional_columns=None): """ Get an event given a project ID and event ID Returns None if an event cannot be found """ cols = self.__get_columns(additional_columns) return SnubaEvent.get_event(project_id, event_id, snuba_cols=cols)
def get(self, latest_or_oldest, request, organization): if not features.has( "organizations:events-v2", organization, actor=request.user): return Response(status=404) try: params = self.get_filter_params(request, organization) snuba_args = self.get_snuba_query_args(request, organization, params) except OrganizationEventsError as exc: return Response({"detail": exc.message}, status=400) except NoProjects: return Response(status=404) if latest_or_oldest == EventOrdering.LATEST: orderby = ["-timestamp", "-event_id"] else: orderby = ["timestamp", "event_id"] result = raw_query( start=snuba_args["start"], end=snuba_args["end"], selected_columns=SnubaEvent.selected_columns, conditions=snuba_args["conditions"], filter_keys=snuba_args["filter_keys"], orderby=orderby, limit=2, referrer="api.organization-event-details-latest-or-oldest", ) if "error" in result or len(result["data"]) == 0: return Response({"detail": "Event not found"}, status=404) try: project_id = result["data"][0]["project_id"] project_slug = Project.objects.get(organization=organization, id=project_id).slug except Project.DoesNotExist: project_slug = None data = serialize(SnubaEvent(result["data"][0])) data["previousEventID"] = None data["nextEventID"] = None data["projectSlug"] = project_slug if latest_or_oldest == EventOrdering.LATEST and len( result["data"]) == 2: data["previousEventID"] = six.text_type( result["data"][1]["event_id"]) if latest_or_oldest == EventOrdering.OLDEST and len( result["data"]) == 2: data["nextEventID"] = six.text_type(result["data"][1]["event_id"]) return Response(data)
def get(self, latest_or_oldest, request, organization): if not features.has( 'organizations:events-v2', organization, actor=request.user): return Response(status=404) try: params = self.get_filter_params(request, organization) snuba_args = self.get_snuba_query_args(request, organization, params) except OrganizationEventsError as exc: return Response({'detail': exc.message}, status=400) except NoProjects: return Response(status=404) if latest_or_oldest == EventOrdering.LATEST: orderby = ['-timestamp', '-event_id'] else: orderby = ['timestamp', 'event_id'] result = raw_query( start=snuba_args['start'], end=snuba_args['end'], selected_columns=SnubaEvent.selected_columns, conditions=snuba_args['conditions'], filter_keys=snuba_args['filter_keys'], orderby=orderby, limit=2, referrer='api.organization-event-details-latest-or-oldest', ) if 'error' in result or len(result['data']) == 0: return Response({'detail': 'Event not found'}, status=404) try: project_id = result['data'][0]['project_id'] project_slug = Project.objects.get(organization=organization, id=project_id).slug except Project.DoesNotExist: project_slug = None data = serialize(SnubaEvent(result['data'][0])) data['previousEventID'] = None data['nextEventID'] = None data['projectSlug'] = project_slug if latest_or_oldest == EventOrdering.LATEST and len( result['data']) == 2: data['previousEventID'] = six.text_type( result['data'][1]['event_id']) if latest_or_oldest == EventOrdering.OLDEST and len( result['data']) == 2: data['nextEventID'] = six.text_type(result['data'][1]['event_id']) return Response(data)
def __handle_result(self, user, project_id, group_id, result): event = { 'timestamp': result['latest_event_timestamp'], 'event_id': result['event_id'], 'group_id': group_id, 'project_id': project_id } return { 'id': result['primary_hash'], 'latestEvent': serialize(SnubaEvent(event), user, EventSerializer()) }
def __handle_result(self, user, project_id, group_id, result): event = { "timestamp": result["latest_event_timestamp"], "event_id": result["event_id"], "group_id": group_id, "project_id": project_id, } return { "id": result["primary_hash"], "latestEvent": serialize(SnubaEvent(event), user, EventSerializer()), }
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 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(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 _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): org = Organization(id=1, slug="organization", name="My Company") project = Project(id=1, organization=org, slug="project", name="My Project") group = next(make_group_generator(get_random(request), project)) data = dict(load_data("python")) data["message"] = group.message data.pop("logentry", None) event_manager = EventManager(data) event_manager.normalize() data = event_manager.get_data() event_type = event_manager.get_event_type() group.message = event_manager.get_search_message() group.data = { "type": event_type.key, "metadata": event_type.get_metadata(data) } event = SnubaEvent({ "event_id": "a" * 32, "project_id": project.id, "group_id": group.id, "message": event_manager.get_search_message(), "data": data.data, "timestamp": data["timestamp"], }) activity = Activity(group=group, project=event.project, **self.get_activity(request, event)) return render_to_response( "sentry/debug/mail/preview.html", context={ "preview": ActivityMailPreview(request, activity), "format": request.GET.get("format"), }, )
def get_direct_hit_response(request, query, snuba_params, referrer): """ Checks whether a query is a direct hit for an event, and if so returns a response. Otherwise returns None """ event_id = normalize_event_id(query) if event_id: snuba_args = get_snuba_query_args(query=u'id:{}'.format(event_id), params=snuba_params) results = raw_query(selected_columns=SnubaEvent.selected_columns, referrer=referrer, **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
def get_event_by_id(self, project_id, event_id, additional_columns=None): """ Get an event given a project ID and event ID Returns None if an event cannot be found """ cols = self.__get_columns(additional_columns) event_id = normalize_event_id(event_id) if not event_id: return None result = snuba.raw_query( selected_columns=cols, filter_keys={"event_id": [event_id], "project_id": [project_id]}, referrer="eventstore.get_event_by_id", limit=1, ) if "error" not in result and len(result["data"]) == 1: return SnubaEvent(result["data"][0]) return 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 = { '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))
def from_event_id(self, id_or_event_id, project_id): """ Get a SnubaEvent by either its id primary key or its hex event_id. Returns None if the event cannot be found under either scheme. Log any attempt to fetch a SnubaEvent by primary key and eventually remove. """ from sentry.models import SnubaEvent, Event if not is_event_id(id_or_event_id): logger.warning('Attempt to fetch SnubaEvent by primary key', exc_info=True, extra={ 'stack': True }) event = Event.objects.from_event_id(id_or_event_id, project_id) if not event: return None id_or_event_id = event.event_id return SnubaEvent.get_event(project_id, id_or_event_id)
def from_event_id(self, id_or_event_id, project_id): """ Get a SnubaEvent by either its id primary key or its hex event_id. Returns None if the event cannot be found under either scheme. Log any attempt to fetch a SnubaEvent by primary key and eventually remove. """ from sentry.models import SnubaEvent, Event if not is_event_id(id_or_event_id): logger.warning('Attempt to fetch SnubaEvent by primary key', exc_info=True, extra={'stack': True}) event = Event.objects.from_event_id(id_or_event_id, project_id) if not event: return None id_or_event_id = event.event_id return SnubaEvent.get_event(project_id, id_or_event_id)
def digest(request): random = get_random(request) # TODO: Refactor all of these into something more manageable. org = Organization(id=1, slug="example", name="Example Organization") project = Project(id=1, slug="example", name="Example Project", organization=org) rules = { i: Rule(id=i, project=project, label="Rule #%s" % (i, )) for i in range(1, random.randint(2, 4)) } state = { "project": project, "groups": {}, "rules": rules, "event_counts": {}, "user_counts": {}, } records = [] group_generator = make_group_generator(random, project) for i in range(random.randint(1, 30)): group = next(group_generator) state["groups"][group.id] = group offset = timedelta(seconds=0) for i in range(random.randint(1, 10)): offset += timedelta(seconds=random.random() * 120) data = dict(load_data("python")) data["message"] = group.message data.pop("logentry", None) event_manager = EventManager(data) event_manager.normalize() data = event_manager.get_data() timestamp = to_datetime( random.randint(to_timestamp(group.first_seen), to_timestamp(group.last_seen))) event = SnubaEvent({ "event_id": uuid.uuid4().hex, "project_id": project.id, "group_id": group.id, "message": group.message, "data": data.data, "timestamp": timestamp.strftime("%Y-%m-%dT%H:%M:%S"), }) event.group = group records.append( Record( event.event_id, Notification( event, random.sample(state["rules"], random.randint(1, len(state["rules"])))), to_timestamp(event.datetime), )) state["event_counts"][group.id] = random.randint(10, 1e4) state["user_counts"][group.id] = random.randint(10, 1e4) digest = build_digest(project, records, state) start, end, counts = get_digest_metadata(digest) context = { "project": project, "counts": counts, "digest": digest, "start": start, "end": end, "referrer": "digest_email", } add_unsubscribe_link(context) return MailPreview( html_template="sentry/emails/digests/body.html", text_template="sentry/emails/digests/body.txt", context=context, ).render(request)