Esempio n. 1
0
 def test_escaped_wildcard(self):
     assert get_snuba_query_args(
         'release:3.1.\\* user.email:\\*@example.com') == {
             'conditions': [
                 [[
                     'match',
                     ['tags[sentry:release]', "'(?i)^3\\.1\\.\\*$'"]
                 ], '=', 1],
                 [['match', ['email', "'(?i)^\*\\@example\\.com$'"]], '=',
                  1],
             ],
             'filter_keys': {},
         }
     assert get_snuba_query_args('release:\\\\\\*') == {
         'conditions': [
             [['match', ['tags[sentry:release]', "'(?i)^\\\\\\*$'"]], '=',
              1],
         ],
         'filter_keys': {},
     }
     assert get_snuba_query_args('release:\\\\*') == {
         'conditions': [
             [['match', ['tags[sentry:release]', "'(?i)^\\\\.*$'"]], '=',
              1],
         ],
         'filter_keys': {},
     }
Esempio n. 2
0
 def test_boolean_term_simple(self):
     assert get_snuba_query_args('user.email:[email protected] AND user.email:[email protected]') == {
         'conditions': [
             ['and', [
                 ['email', '=', '*****@*****.**'],
                 ['email', '=', '*****@*****.**']
             ]]
         ],
         'filter_keys': {},
         'has_boolean_terms': True,
     }
     assert get_snuba_query_args('user.email:[email protected] OR user.email:[email protected]') == {
         'conditions': [
             ['or', [
                 ['email', '=', '*****@*****.**'],
                 ['email', '=', '*****@*****.**']
             ]]
         ],
         'filter_keys': {},
         'has_boolean_terms': True,
     }
     assert get_snuba_query_args(
         'user.email:[email protected] AND user.email:[email protected] OR user.email:[email protected] AND user.email:[email protected] AND user.email:[email protected] OR user.email:[email protected] AND user.email:[email protected] OR user.email:[email protected] AND user.email:[email protected] AND user.email:[email protected]'
     ) == {
         'conditions': [
             ['or', [
                 ['and', [
                     ['email', '=', '*****@*****.**'],
                     ['email', '=', '*****@*****.**']
                 ]],
                 ['or', [
                     ['and', [
                         ['email', '=', '*****@*****.**'],
                         ['and', [
                             ['email', '=', '*****@*****.**'],
                             ['email', '=', '*****@*****.**']
                         ]]
                     ]],
                     ['or', [
                         ['and', [
                             ['email', '=', '*****@*****.**'],
                             ['email', '=', '*****@*****.**']
                         ]],
                         ['and', [
                             ['email', '=', '*****@*****.**'],
                             ['and', [
                                 ['email', '=', '*****@*****.**'],
                                 ['email', '=', '*****@*****.**']
                             ]]
                         ]]
                     ]]
                 ]]
             ]]
         ],
         'filter_keys': {},
         'has_boolean_terms': True,
     }
Esempio n. 3
0
    def get_snuba_query_args(self, request, organization):
        params = self.get_filter_params(request, organization)

        group_ids = set(map(int, request.GET.getlist('group')))
        if group_ids:
            projects = Project.objects.filter(
                organization=organization,
                group__id__in=group_ids,
            ).distinct()
            if any(p for p in projects if not request.access.has_project_access(p)):
                raise PermissionDenied
            params['issue.id'] = list(group_ids)
            params['project_id'] = list(set([p.id for p in projects] + params['project_id']))

        query = request.GET.get('query')
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has(
            'organizations:boolean-search',
            organization,
            actor=request.user
        )
        if snuba_args.pop('has_boolean_terms', False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.')
        return snuba_args
Esempio n. 4
0
    def get_snuba_query_args_v2(self, request, organization):
        params = self.get_filter_params(request, organization)

        query = request.GET.get('query')
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        fields = request.GET.getlist('fields')
        if fields:
            snuba_args['selected_columns'] = fields
        else:
            raise OrganizationEventsError('No fields requested.')

        groupby = request.GET.getlist('groupby')
        if groupby:
            snuba_args['groupby'] = groupby

        orderby = request.GET.get('orderby')
        if orderby:
            snuba_args['orderby'] = orderby

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has('organizations:boolean-search',
                                           organization,
                                           actor=request.user)
        if snuba_args.pop('has_boolean_terms',
                          False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.'
            )
        return snuba_args
Esempio n. 5
0
def create_snuba_subscription(project, dataset, query, aggregations,
                              time_window, resolution):
    """
    Creates a subscription to a snuba query.

    :param project: The project we're applying the query to
    :param dataset: The snuba dataset to query and aggregate over
    :param query: An event search query that we can parse and convert into a
    set of Snuba conditions
    :param aggregations: A list of aggregations to calculate over the time
    window
    :param time_window: The time window to aggregate over
    :param resolution: How often to receive updates/bucket size
    :return: A uuid representing the subscription id.
    """
    # TODO: Might make sense to move this into snuba if we have wider use for
    # it.
    resp = safe_urlopen(
        settings.SENTRY_SNUBA + "/subscriptions",
        "POST",
        json={
            "project_id": project.id,
            "dataset": dataset.value,
            # We only care about conditions here. Filter keys only matter for
            # filtering to project and groups. Projects are handled with an
            # explicit param, and groups can't be queried here.
            "conditions": get_snuba_query_args(query)["conditions"],
            "aggregates":
            [alert_aggregation_to_snuba[agg] for agg in aggregations],
            "time_window": time_window,
            "resolution": resolution,
        },
    )
    resp.raise_for_status()
    return uuid.UUID(resp.json()["subscription_id"])
Esempio n. 6
0
 def get_snuba_query_args(self, request, organization):
     params = self.get_filter_params(request, organization)
     try:
         return get_snuba_query_args(query=request.GET.get('query'),
                                     params=params)
     except InvalidSearchQuery as exc:
         raise OrganizationEventsError(exc.message)
Esempio n. 7
0
    def get_snuba_query_args(self, request, organization, params):
        query = request.GET.get('query')

        group_ids = request.GET.getlist('group')
        if group_ids:
            # TODO(mark) This parameter should be removed in the long term.
            # Instead of using this parameter clients should use `issue.id`
            # in their query string.
            try:
                group_ids = set(map(int, filter(None, group_ids)))
            except ValueError:
                raise OrganizationEventsError('Invalid group parameter. Values must be numbers')

            projects = Project.objects.filter(
                organization=organization,
                group__id__in=group_ids,
            ).distinct()
            if any(p for p in projects if not request.access.has_project_access(p)):
                raise PermissionDenied
            params['issue.id'] = list(group_ids)
            params['project_id'] = list(set([p.id for p in projects] + params['project_id']))

        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        sort = request.GET.getlist('sort')
        if sort:
            snuba_args['orderby'] = sort

        # Deprecated. `sort` should be used as it is supported by
        # more endpoints.
        orderby = request.GET.getlist('orderby')
        if orderby and 'orderby' not in snuba_args:
            snuba_args['orderby'] = orderby

        if request.GET.get('rollup'):
            try:
                snuba_args['rollup'] = int(request.GET.get('rollup'))
            except ValueError:
                raise OrganizationEventsError('rollup must be an integer.')

        fields = request.GET.getlist('field')[:]
        if fields:
            try:
                snuba_args.update(resolve_field_list(fields, snuba_args))
            except InvalidSearchQuery as exc:
                raise OrganizationEventsError(exc.message)

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has(
            'organizations:boolean-search',
            organization,
            actor=request.user
        )
        if snuba_args.pop('has_boolean_terms', False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.')
        return snuba_args
Esempio n. 8
0
def bulk_build_incident_query_params(incidents, start=None, end=None):
    incident_groups = defaultdict(list)
    for incident_id, group_id in IncidentGroup.objects.filter(
            incident__in=incidents).values_list("incident_id", "group_id"):
        incident_groups[incident_id].append(group_id)
    incident_projects = defaultdict(list)
    for incident_id, project_id in IncidentProject.objects.filter(
            incident__in=incidents).values_list("incident_id", "project_id"):
        incident_projects[incident_id].append(project_id)

    query_args_list = []
    for incident in incidents:
        params = {
            "start": incident.date_started if start is None else start,
            "end": incident.current_end_date if end is None else end,
        }
        group_ids = incident_groups[incident.id]
        if group_ids:
            params["issue.id"] = group_ids
        project_ids = incident_projects[incident.id]
        if project_ids:
            params["project_id"] = project_ids
        query_args_list.append(get_snuba_query_args(incident.query, params))

    return query_args_list
Esempio n. 9
0
 def test_negation(self):
     assert get_snuba_query_args('!user.email:[email protected]') == {
         'conditions': [
             [['ifNull', ['email', "''"]], '!=', '*****@*****.**'],
         ],
         'filter_keys': {},
     }
Esempio n. 10
0
 def test_no_search(self):
     assert get_snuba_query_args(
         params={
             'project_id': [1, 2, 3],
             'start':
             datetime.datetime(2015, 5, 18, 10, 15, 1, tzinfo=timezone.utc),
             'end':
             datetime.datetime(2015, 5, 19, 10, 15, 1, tzinfo=timezone.utc),
         }) == {
             'conditions': [],
             'filter_keys': {
                 'project_id': [1, 2, 3]
             },
             'start': datetime.datetime(2015,
                                        5,
                                        18,
                                        10,
                                        15,
                                        1,
                                        tzinfo=timezone.utc),
             'end': datetime.datetime(2015,
                                      5,
                                      19,
                                      10,
                                      15,
                                      1,
                                      tzinfo=timezone.utc),
         }
Esempio n. 11
0
    def get_snuba_query_args(self, request, organization):
        params = self.get_filter_params(request, organization)

        group_ids = set(map(int, request.GET.getlist('group')))
        if group_ids:
            projects = Project.objects.filter(
                organization=organization,
                group__id__in=group_ids,
            ).distinct()
            if any(p for p in projects
                   if not request.access.has_project_access(p)):
                raise PermissionDenied
            params['issue.id'] = list(group_ids)
            params['project_id'] = list(
                set([p.id for p in projects] + params['project_id']))

        query = request.GET.get('query')
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has('organizations:boolean-search',
                                           organization,
                                           actor=request.user)
        if snuba_args.pop('has_boolean_terms',
                          False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.'
            )
        return snuba_args
Esempio n. 12
0
 def test_negation_get_snuba_query_args(self):
     assert get_snuba_query_args('!user.email:[email protected]') == {
         'conditions': [
             [['ifNull', ['email', "''"]], '!=', '*****@*****.**'],
         ],
         'filter_keys': {},
     }
Esempio n. 13
0
 def test_get_snuba_query_args(self):
     assert get_snuba_query_args('user.email:[email protected] release:1.2.1 hello') == {
         'conditions': [
             ['email', '=', '*****@*****.**'],
             ['sentry:release', '=', '1.2.1'],
             [['positionCaseInsensitive', ['message', "'hello'"]], '!=', 0],
         ]
     }
Esempio n. 14
0
 def test_wildcard(self):
     assert get_snuba_query_args('release:3.1.* user.email:*@example.com') == {
         'conditions': [
             [['match', ['tags[sentry:release]', "'(?i)^3\\.1\\..*$'"]], '=', 1],
             [['match', ['email', "'(?i)^.*\\@example\\.com$'"]], '=', 1],
         ],
         'filter_keys': {},
     }
Esempio n. 15
0
 def test_get_snuba_query_args_negated_wildcard(self):
     assert get_snuba_query_args('!release:3.1.* user.email:*@example.com') == {
         'conditions': [
             [['match', [['ifnull', ['tags[sentry:release]', "''"]], "'^3\\.1\\..*$'"]], '!=', 1],
             [['match', ['email', "'^.*\\@example\\.com$'"]], '=', 1],
         ],
         'filter_keys': {},
     }
Esempio n. 16
0
 def test_message_negative(self):
     assert get_snuba_query_args('!message:"post_process.process_error HTTPError 403"') == {
         'filter_keys': {},
         'conditions': [[
             ['positionCaseInsensitive', ['message', "'post_process.process_error HTTPError 403'"]],
             '=',
             0,
         ]]
     }
Esempio n. 17
0
 def test_message_negative(self):
     assert get_snuba_query_args('!message:"post_process.process_error HTTPError 403"') == {
         'filter_keys': {},
         'conditions': [[
             ['positionCaseInsensitive', ['message', "'post_process.process_error HTTPError 403'"]],
             '=',
             0,
         ]]
     }
Esempio n. 18
0
 def test_no_search(self):
     assert get_snuba_query_args(params={
         'project_id': [1, 2, 3],
         'start': datetime.datetime(2015, 5, 18, 10, 15, 1, tzinfo=timezone.utc),
         'end': datetime.datetime(2015, 5, 19, 10, 15, 1, tzinfo=timezone.utc),
     }) == {
         'conditions': [],
         'filter_keys': {'project_id': [1, 2, 3]},
         'start': datetime.datetime(2015, 5, 18, 10, 15, 1, tzinfo=timezone.utc),
         'end': datetime.datetime(2015, 5, 19, 10, 15, 1, tzinfo=timezone.utc),
     }
Esempio n. 19
0
    def get_snuba_query_args_v2(self, request, organization, params):
        query = request.GET.get('query')
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        fields = request.GET.getlist('field')[:]
        aggregations = []
        groupby = request.GET.getlist('groupby')
        special_fields = set()

        if fields:
            # If project.name is requested, get the project.id from Snuba so we
            # can use this to look up the name in Sentry
            if 'project.name' in fields:
                fields.remove('project.name')
                if 'project.id' not in fields:
                    fields.append('project.id')

            for field in fields[:]:
                if field in SPECIAL_FIELDS:
                    special_fields.add(field)
                    special_field = deepcopy(SPECIAL_FIELDS[field])
                    fields.remove(field)
                    fields.extend(special_field.get('fields', []))
                    aggregations.extend(special_field.get('aggregations', []))
                    groupby.extend(special_field.get('groupby', []))

            snuba_args['selected_columns'] = fields

        self._filter_unspecified_special_fields_in_conditions(
            snuba_args, special_fields)
        if aggregations:
            snuba_args['aggregations'] = aggregations

        if groupby:
            snuba_args['groupby'] = groupby

        orderby = request.GET.getlist('orderby')
        if orderby:
            snuba_args['orderby'] = orderby

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has('organizations:boolean-search',
                                           organization,
                                           actor=request.user)
        if snuba_args.pop('has_boolean_terms',
                          False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.'
            )
        return snuba_args
Esempio n. 20
0
    def test_project_name(self):
        p1 = self.create_project(organization=self.organization)
        p2 = self.create_project(organization=self.organization)

        params = {
            'project_id': [p1.id, p2.id],
        }
        assert get_snuba_query_args('project.name:{}'.format(p1.slug), params) == {
            'conditions': [['project_id', '=', p1.id]],
            'filter_keys': {
                'project_id': [p1.id, p2.id],
            }
        }
Esempio n. 21
0
    def test_issue_filter(self):
        assert get_snuba_query_args('issue.id:1') == {
            'conditions': [],
            'filter_keys': {
                'issue': [1],
            },
        }

        assert get_snuba_query_args('issue.id:1 issue.id:2 issue.id:3') == {
            'conditions': [],
            'filter_keys': {
                'issue': [1, 2, 3],
            },
        }

        assert get_snuba_query_args('issue.id:1 user.email:[email protected]') == {
            'conditions': [
                ['email', '=', '*****@*****.**']
            ],
            'filter_keys': {
                'issue': [1],
            },
        }
Esempio n. 22
0
    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))
Esempio n. 23
0
def build_incident_query_params(incident):
    params = {'start': incident.date_started, 'end': incident.current_end_date}
    group_ids = list(IncidentGroup.objects.filter(
        incident=incident,
    ).values_list('group_id', flat=True))
    if group_ids:
        params['issue.id'] = group_ids
    project_ids = list(IncidentProject.objects.filter(
        incident=incident,
    ).values_list('project_id', flat=True))
    if project_ids:
        params['project_id'] = project_ids

    return get_snuba_query_args(incident.query, params)
Esempio n. 24
0
 def test_get_snuba_query_args(self):
     assert get_snuba_query_args('user.email:[email protected] release:1.2.1 hello', {
         'project_id': [1, 2, 3],
         'start': datetime.datetime(2015, 5, 18, 10, 15, 1, tzinfo=timezone.utc),
         'end': datetime.datetime(2015, 5, 19, 10, 15, 1, tzinfo=timezone.utc),
     }) == {
         'conditions': [
             ['email', '=', '*****@*****.**'],
             ['sentry:release', '=', '1.2.1'],
             [['positionCaseInsensitive', ['message', "'hello'"]], '!=', 0],
         ],
         'filter_keys': {'project_id': [1, 2, 3]},
         'start': datetime.datetime(2015, 5, 18, 10, 15, 1, tzinfo=timezone.utc),
         'end': datetime.datetime(2015, 5, 19, 10, 15, 1, tzinfo=timezone.utc),
     }
Esempio n. 25
0
    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
            )

        return self.paginate(
            request=request,
            on_results=lambda results: serialize(
                [SnubaEvent(row) for row in results], request.user),
            paginator=GenericOffsetPaginator(data_fn=data_fn)
        )
Esempio n. 26
0
    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)
        )
Esempio n. 27
0
 def test_simple(self):
     assert get_snuba_query_args('user.email:[email protected] release:1.2.1 fruit:apple hello', {
         'project_id': [1, 2, 3],
         'start': datetime.datetime(2015, 5, 18, 10, 15, 1, tzinfo=timezone.utc),
         'end': datetime.datetime(2015, 5, 19, 10, 15, 1, tzinfo=timezone.utc),
     }) == {
         'conditions': [
             ['email', '=', '*****@*****.**'],
             ['tags[sentry:release]', '=', '1.2.1'],
             [['ifNull', ['tags[fruit]', "''"]], '=', 'apple'],
             [['positionCaseInsensitive', ['message', "'hello'"]], '!=', 0],
         ],
         'filter_keys': {'project_id': [1, 2, 3]},
         'start': datetime.datetime(2015, 5, 18, 10, 15, 1, tzinfo=timezone.utc),
         'end': datetime.datetime(2015, 5, 19, 10, 15, 1, tzinfo=timezone.utc),
     }
Esempio n. 28
0
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 = eventstore.get_events(referrer=referrer, **snuba_args)

        if len(results) == 1:
            response = Response(serialize(results, request.user))
            response["X-Sentry-Direct-Hit"] = "1"
            return response
Esempio n. 29
0
    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),
        )
Esempio n. 30
0
    def get_snuba_query_args(self, request, organization, params):
        query = request.GET.get("query")
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        sort = request.GET.getlist("sort")
        if sort:
            snuba_args["orderby"] = sort

        # Deprecated. `sort` should be used as it is supported by
        # more endpoints.
        orderby = request.GET.getlist("orderby")
        if orderby and "orderby" not in snuba_args:
            snuba_args["orderby"] = orderby

        if request.GET.get("rollup"):
            try:
                snuba_args["rollup"] = int(request.GET.get("rollup"))
            except ValueError:
                raise OrganizationEventsError("rollup must be an integer.")

        fields = request.GET.getlist("field")[:]
        if fields:
            try:
                snuba_args.update(resolve_field_list(fields, snuba_args))
            except InvalidSearchQuery as exc:
                raise OrganizationEventsError(exc.message)

        reference_event_id = request.GET.get("referenceEvent")
        if reference_event_id:
            reference_event = find_reference_event(snuba_args,
                                                   reference_event_id)
            snuba_args["conditions"] = get_reference_event_conditions(
                snuba_args, reference_event.snuba_data)

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has("organizations:boolean-search",
                                           organization,
                                           actor=request.user)
        if snuba_args.pop("has_boolean_terms",
                          False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                "Boolean search operator OR and AND not allowed in this search."
            )
        return snuba_args
Esempio n. 31
0
    def get_snuba_query_args(self, request, organization):
        params = self.get_filter_params(request, organization)
        query = request.GET.get('query')

        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has('organizations:boolean-search',
                                           organization,
                                           actor=request.user)
        if snuba_args.pop('has_boolean_terms',
                          False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.'
            )
        return snuba_args
Esempio n. 32
0
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
Esempio n. 33
0
    def get_snuba_query_args(self, request, organization):
        params = self.get_filter_params(request, organization)

        group_ids = request.GET.getlist('group')
        if group_ids:
            try:
                group_ids = set(map(int, filter(None, group_ids)))
            except ValueError:
                raise OrganizationEventsError('Invalid group parameter. Values must be numbers')

            projects = Project.objects.filter(
                organization=organization,
                group__id__in=group_ids,
            ).distinct()
            if any(p for p in projects if not request.access.has_project_access(p)):
                raise PermissionDenied
            params['issue.id'] = list(group_ids)
            params['project_id'] = list(set([p.id for p in projects] + params['project_id']))

        query = request.GET.get('query')
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        # Filter out special aggregates.
        conditions = []
        for condition in snuba_args.get('conditions', []):
            field_name = condition[0]
            if isinstance(field_name, (list, tuple)) or field_name not in SPECIAL_FIELDS:
                conditions.append(condition)
        snuba_args['conditions'] = conditions

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has(
            'organizations:boolean-search',
            organization,
            actor=request.user
        )
        if snuba_args.pop('has_boolean_terms', False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.')
        return snuba_args
Esempio n. 34
0
    def get_snuba_query_args_v2(self, request, organization, params):
        query = request.GET.get('query')
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        fields = request.GET.getlist('field')[:]
        if fields:
            # If project.name is requested, get the project.id from Snuba so we
            # can use this to look up the name in Sentry
            if 'project.name' in fields:
                fields.remove('project.name')
                if 'project.id' not in fields:
                    fields.append('project.id')

            snuba_args['selected_columns'] = fields

        aggregations = request.GET.getlist('aggregation')
        if aggregations:
            snuba_args['aggregations'] = [
                aggregation.split(',') for aggregation in aggregations
            ]

        groupby = request.GET.getlist('groupby')
        if groupby:
            snuba_args['groupby'] = groupby

        orderby = request.GET.get('orderby')
        if orderby:
            snuba_args['orderby'] = orderby

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has('organizations:boolean-search',
                                           organization,
                                           actor=request.user)
        if snuba_args.pop('has_boolean_terms',
                          False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.'
            )
        return snuba_args
Esempio n. 35
0
    def get_snuba_query_args_legacy(self, request, organization):
        params = self.get_filter_params(request, organization)

        group_ids = request.GET.getlist('group')
        if group_ids:
            # TODO(mark) This parameter should be removed in the long term.
            # Instead of using this parameter clients should use `issue.id`
            # in their query string.
            try:
                group_ids = set(map(int, filter(None, group_ids)))
            except ValueError:
                raise OrganizationEventsError('Invalid group parameter. Values must be numbers')

            projects = Project.objects.filter(
                organization=organization,
                group__id__in=group_ids,
            ).distinct()
            if any(p for p in projects if not request.access.has_project_access(p)):
                raise PermissionDenied
            params['issue.id'] = list(group_ids)
            params['project_id'] = list(set([p.id for p in projects] + params['project_id']))

        query = request.GET.get('query')
        try:
            snuba_args = get_snuba_query_args(query=query, params=params)
        except InvalidSearchQuery as exc:
            raise OrganizationEventsError(exc.message)

        # Filter out special aggregates.
        self._filter_unspecified_special_fields_in_conditions(snuba_args, set())

        # TODO(lb): remove once boolean search is fully functional
        has_boolean_op_flag = features.has(
            'organizations:boolean-search',
            organization,
            actor=request.user
        )
        if snuba_args.pop('has_boolean_terms', False) and not has_boolean_op_flag:
            raise OrganizationEventsError(
                'Boolean search operator OR and AND not allowed in this search.')
        return snuba_args
Esempio n. 36
0
def _create_in_snuba(project, dataset, query, aggregation, time_window,
                     resolution):
    response = _snuba_pool.urlopen(
        "POST",
        "/subscriptions",
        body=json.dumps({
            "project_id": project.id,
            "dataset": dataset.value,
            # We only care about conditions here. Filter keys only matter for
            # filtering to project and groups. Projects are handled with an
            # explicit param, and groups can't be queried here.
            "conditions": get_snuba_query_args(query)["conditions"],
            "aggregates": [query_aggregation_to_snuba[aggregation]],
            "time_window": time_window,
            "resolution": resolution,
        }),
        retries=False,
    )
    if response.status != 202:
        raise SnubaError("HTTP %s response from Snuba!" % response.status)
    return json.loads(response.data)["subscription_id"]
Esempio n. 37
0
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
    """
    if is_event_id(query):
        snuba_args = get_snuba_query_args(
            query=u'id:{}'.format(query),
            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
Esempio n. 38
0
    def get(self, request, organization):
        try:
            start, end = get_date_range_from_params(request.GET)
        except InvalidParams as exc:
            return Response({'detail': exc.message}, status=400)

        try:
            project_ids = self.get_project_ids(request, organization)
        except ValueError:
            return Response({'detail': 'Invalid project ids'}, status=400)

        environments = self.get_environments(request, organization)
        params = {
            'start': start,
            'end': end,
            'project_id': project_ids,
        }
        if environments:
            params['environment'] = environments

        try:
            snuba_args = get_snuba_query_args(query=request.GET.get('query'),
                                              params=params)
        except InvalidSearchQuery as exc:
            return Response({'detail': exc.message}, status=400)

        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)

        return self.paginate(request=request,
                             on_results=lambda results: serialize(
                                 [SnubaEvent(row)
                                  for row in results], request.user),
                             paginator=GenericOffsetPaginator(data_fn=data_fn))
Esempio n. 39
0
 def get_snuba_query_args(self, request, organization):
     params = self.get_filter_params(request, organization)
     try:
         return get_snuba_query_args(query=request.GET.get('query'), params=params)
     except InvalidSearchQuery as exc:
         raise OrganizationEventsError(exc.message)
Esempio n. 40
0
 def test_not_has(self):
     assert get_snuba_query_args('!has:release') == {
         'filter_keys': {},
         'conditions': [[['isNull', ['tags[sentry:release]']], '=', 1]]
     }
Esempio n. 41
0
 def test_get_snuba_query_args_has(self):
     assert get_snuba_query_args('has:release') == {
         'filter_keys': {},
         'conditions': [[['ifNull', ['tags[sentry:release]', "''"]], '!=', '']]
     }