Exemple #1
0
    def test_get_db_engine(self):
        from sentry.utils.db import get_db_engine
        _databases = getattr(django_settings, 'DATABASES', {}).copy()

        django_settings.DATABASES['default'] = {'ENGINE': 'blah.sqlite3'}

        self.assertEquals(get_db_engine(), 'sqlite3')

        django_settings.DATABASES['default'] = {'ENGINE': 'blah.mysql'}

        self.assertEquals(get_db_engine(), 'mysql')

        django_settings.DATABASES = _databases
Exemple #2
0
def get_priority_sort_expression(model):
    engine = get_db_engine(router.db_for_read(model))
    table = get_sql_table(model)
    if 'postgres' in engine:
        return u'log({table}.times_seen) * 600 + {table}.last_seen::abstime::int'.format(table=table)
    else:
        # TODO: This should be improved on other databases where possible.
        # (This doesn't work on some databases: SQLite for example doesn't
        # have a built-in logarithm function.)
        return u'{}.times_seen'.format(table)
Exemple #3
0
def get_sql_date_trunc(col, db='default'):
    conn = connections[db]

    engine = get_db_engine(db)
    # TODO: does extract work for sqlite?
    if engine.startswith('oracle'):
        method = conn.ops.date_trunc_sql('hh24', col)
    else:
        method = conn.ops.date_trunc_sql('hour', col)

    return method
Exemple #4
0
    def evaluate(self, node, qn, connection):
        engine = get_db_engine(getattr(connection, 'alias', 'default'))
        if engine.startswith('postgresql'):
            sql = 'log(times_seen) * 600 + last_seen::abstime::int'
        elif engine.startswith('mysql'):
            sql = 'log(times_seen) * 600 + unix_timestamp(last_seen)'
        else:
            # XXX: if we cant do it atomically let's do it the best we can
            sql = int(self)

        return (sql, [])
Exemple #5
0
        def as_sql(self, compiler, connection, function=None, template=None):
            engine = get_db_engine(getattr(connection, 'alias', 'default'))
            if engine.startswith('postgresql'):
                sql = 'log(times_seen) * 600 + last_seen::abstime::int'
            elif engine.startswith('mysql'):
                sql = 'log(times_seen) * 600 + unix_timestamp(last_seen)'
            else:
                # XXX: if we cant do it atomically let's do it the best we can
                sql = int(self)

            return (sql, [])
Exemple #6
0
def get_sql_date_trunc(col, db='default', grouper='hour'):
    conn = connections[db]

    engine = get_db_engine(db)
    # TODO: does extract work for sqlite?
    if engine.startswith('oracle'):
        method = DATE_TRUNC_GROUPERS['oracle'].get(grouper, DATE_TRUNC_GROUPERS['default'][grouper])
    else:
        method = DATE_TRUNC_GROUPERS['default'][grouper]

    return conn.ops.date_trunc_sql(method, col)
Exemple #7
0
    def evaluate(self, node, qn, connection):
        engine = get_db_engine(getattr(connection, "alias", "default"))
        if engine.startswith("postgresql"):
            sql = "log(times_seen) * 600 + last_seen::abstime::int"
        elif engine.startswith("mysql"):
            sql = "log(times_seen) * 600 + unix_timestamp(last_seen)"
        else:
            # XXX: if we cant do it atomicly let's do it the best we can
            sql = self.group.get_score()

        return (sql, [])
Exemple #8
0
def get_sort_clause(sort_by):
    engine = get_db_engine('default')
    if engine.startswith('sqlite'):
        return SQLITE_SORT_CLAUSES[sort_by]
    elif engine.startswith('mysql'):
        return MYSQL_SORT_CLAUSES[sort_by]
    elif engine.startswith('oracle'):
        return ORACLE_SORT_CLAUSES[sort_by]
    elif engine in MSSQL_ENGINES:
        return MSSQL_SORT_CLAUSES[sort_by]
    else:
        return SORT_CLAUSES[sort_by]
Exemple #9
0
def get_sql_date_trunc(col, db="default", grouper="hour"):
    conn = connections[db]

    engine = get_db_engine(db)
    # TODO: does extract work for sqlite?
    if engine.startswith("oracle"):
        method = DATE_TRUNC_GROUPERS["oracle"].get(grouper, DATE_TRUNC_GROUPERS["default"][grouper])
        if '"' not in col:
            col = '"%s"' % col.upper()
    else:
        method = DATE_TRUNC_GROUPERS["default"][grouper]
    return conn.ops.date_trunc_sql(method, col)
Exemple #10
0
    def get_accelerated(self, queryset=None, minutes=15):
        # mintues should
        from sentry.models import MessageCountByMinute
        mcbm_tbl = MessageCountByMinute._meta.db_table
        if queryset is None:
            queryset = self

        assert minutes >= settings.MINUTE_NORMALIZATION

        engine = get_db_engine(queryset.db)
        if engine.startswith('mysql'):
            minute_clause = "interval %s minute"
        else:
            minute_clause = "interval '%s minutes'"

        queryset = queryset.extra(
            where=["%s.date >= now() - %s" % (mcbm_tbl, minute_clause % (minutes, ))],
        ).annotate(x=Sum('messagecountbyminute__times_seen')).order_by('id')

        sql, params = queryset.query.get_compiler(queryset.db).as_sql()
        before_select, after_select = str(sql).split('SELECT ', 1)
        before_where, after_where = after_select.split(' WHERE ', 1)
        before_group, after_group = after_where.split(' GROUP BY ', 1)

        # Ensure we remove any ordering clause
        after_group = after_group.split(' ORDER BY ')[0]

        query = """
        SELECT (SUM(%(mcbm_tbl)s.times_seen) + 1.0) / (COALESCE(z.accel, 0) + 1.0) as accel,
               z.accel as prev_accel,
               %(before_where)s
        LEFT JOIN (SELECT a.group_id, SUM(a.times_seen) / 3.0 as accel
            FROM %(mcbm_tbl)s as a
            WHERE a.date BETWEEN now() - %(min_time)s
            AND now() - %(min_time)s
            GROUP BY a.group_id) as z
        ON z.group_id = %(mcbm_tbl)s.group_id
        WHERE %(before_group)s
        GROUP BY prev_accel, %(after_group)s
        HAVING SUM(%(mcbm_tbl)s.times_seen) > 0
        ORDER BY accel DESC
        """ % dict(
            mcbm_tbl=mcbm_tbl,
            before_where=before_where,
            before_group=before_group,
            after_group=after_group,
            min_time=minute_clause % (minutes + 1,),
            max_time=minute_clause % (minutes * 4,),
        )
        return RawQuerySet(self, query, params)
Exemple #11
0
    def get(self, request, team):
        """
        Return a list of the newest groups for a given team.

        The resulting query will find groups which have been seen since the
        cutoff date, and then sort those by score, returning the highest scoring
        groups first.
        """
        minutes = int(request.REQUEST.get('minutes', 15))
        limit = min(100, int(request.REQUEST.get('limit', 10)))

        project_list = Project.objects.get_for_user(user=request.user, team=team)

        project_dict = dict((p.id, p) for p in project_list)

        cutoff = timedelta(minutes=minutes)
        cutoff_dt = timezone.now() - cutoff

        if get_db_engine('default') == 'sqlite':
            sort_value = 'times_seen'
        else:
            sort_value = 'score'

        group_list = list(
            Group.objects.filter(
                project__in=project_dict.keys(),
                status=GroupStatus.UNRESOLVED,
                active_at__gte=cutoff_dt,
            ).extra(
                select={'sort_value': sort_value},
            ).order_by('-{}'.format(sort_value), '-first_seen')[:limit]
        )

        for group in group_list:
            group._project_cache = project_dict.get(group.project_id)

        return Response(
            serialize(
                group_list,
                request.user,
                GroupSerializer(
                    environment_func=self._get_environment_func(request, team.organization_id)
                )
            )
        )
Exemple #12
0
def get_group_tags(request, team, project, group_id, tag_name):
    # XXX(dcramer): Consider this API deprecated as soon as it was implemented
    cutoff = timezone.now() - timedelta(days=7)

    engine = get_db_engine('default')
    if 'postgres' in engine:
        # This doesnt guarantee percentage is accurate, but it does ensure
        # that the query has a maximum cost
        cursor = connections['default'].cursor()
        cursor.execute("""
            SELECT SUM(t)
            FROM (
                SELECT times_seen as t
                FROM sentry_messagefiltervalue
                WHERE group_id = %s
                AND key = %s
                AND last_seen > NOW() - INTERVAL '7 days'
                LIMIT 10000
            ) as a
        """, [group_id, tag_name])
        total = cursor.fetchone()[0] or 0
    else:
        total = GroupTagValue.objects.filter(
            group=group_id,
            key=tag_name,
            last_seen__gte=cutoff,
        ).aggregate(t=Sum('times_seen'))['t'] or 0

    unique_tags = GroupTagValue.objects.filter(
        group=group_id,
        key=tag_name,
        last_seen__gte=cutoff,
    ).values_list('value', 'times_seen').order_by('-times_seen')[:10]

    return json.dumps({
        'name': tag_name,
        'values': list(unique_tags),
        'total': total,
    })
Exemple #13
0
            event_list = event_list.filter(last_seen__gte=date_from)
        elif date_to:
            event_list = event_list.filter(last_seen__lte=date_to)

    sort = request.GET.get("sort") or request.session.get("streamsort")
    if sort not in SORT_OPTIONS:
        sort = DEFAULT_SORT_OPTION

    # Save last sort in session
    if sort != request.session.get("streamsort"):
        request.session["streamsort"] = sort

    if sort.startswith("accel_") and not has_trending():
        sort = DEFAULT_SORT_OPTION

    engine = get_db_engine("default")
    if engine.startswith("sqlite"):
        score_clause = SQLITE_SORT_CLAUSES.get(sort)
        filter_clause = SQLITE_SCORE_CLAUSES.get(sort)
    elif engine.startswith("mysql"):
        score_clause = MYSQL_SORT_CLAUSES.get(sort)
        filter_clause = MYSQL_SCORE_CLAUSES.get(sort)
    elif engine.startswith("oracle"):
        score_clause = ORACLE_SORT_CLAUSES.get(sort)
        filter_clause = ORACLE_SCORE_CLAUSES.get(sort)
    elif engine in ("django_pytds", "sqlserver_ado", "sql_server.pyodbc"):
        score_clause = MSSQL_SORT_CLAUSES.get(sort)
        filter_clause = MSSQL_SCORE_CLAUSES.get(sort)
    else:
        score_clause = SORT_CLAUSES.get(sort)
        filter_clause = SCORE_CLAUSES.get(sort)
Exemple #14
0
    def query(self, project, query=None, status=None, tags=None,
              bookmarked_by=None, sort_by='date', date_filter='last_seen',
              date_from=None, date_to=None, offset=0, limit=100):
        from sentry.models import Group

        queryset = Group.objects.filter(project=project)
        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(
                Q(message__icontains=query) |
                Q(culprit__icontains=query)
            )

        if status is not None:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if tags:
            for k, v in tags.iteritems():
                queryset = queryset.filter(**dict(
                    grouptag__key=k,
                    grouptag__value=v,
                ))

        if date_filter == 'first_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    first_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(first_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(first_seen__lte=date_to)
        elif date_filter == 'last_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    last_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(last_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(last_seen__lte=date_to)

        engine = get_db_engine('default')
        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
            filter_clause = SQLITE_SCORE_CLAUSES[sort_by]
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
            filter_clause = MYSQL_SCORE_CLAUSES[sort_by]
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
            filter_clause = ORACLE_SCORE_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
            filter_clause = MSSQL_SCORE_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]
            filter_clause = SCORE_CLAUSES[sort_by]

        if sort_by == 'tottime':
            queryset = queryset.filter(time_spent_count__gt=0)
        elif sort_by == 'avgtime':
            queryset = queryset.filter(time_spent_count__gt=0)

        queryset = queryset.extra(
            select={'sort_value': score_clause},
        )
        # HACK: don't sort by the same column twice
        if sort_by == 'date':
            queryset = queryset.order_by('-last_seen')
        else:
            queryset = queryset.order_by('-sort_value', '-last_seen')

        return SearchResult(instances=list(queryset[offset:offset + limit]))
Exemple #15
0
    def _build_queryset(
        self,
        project,
        query=None,
        status=None,
        tags=None,
        bookmarked_by=None,
        assigned_to=None,
        first_release=None,
        sort_by='date',
        unassigned=None,
        subscribed_by=None,
        age_from=None,
        age_from_inclusive=True,
        age_to=None,
        age_to_inclusive=True,
        last_seen_from=None,
        last_seen_from_inclusive=True,
        last_seen_to=None,
        last_seen_to_inclusive=True,
        date_from=None,
        date_from_inclusive=True,
        date_to=None,
        date_to_inclusive=True,
        active_at_from=None,
        active_at_from_inclusive=True,
        active_at_to=None,
        active_at_to_inclusive=True,
        times_seen=None,
        times_seen_lower=None,
        times_seen_lower_inclusive=True,
        times_seen_upper=None,
        times_seen_upper_inclusive=True,
        cursor=None,
        limit=None
    ):
        from sentry.models import Event, Group, GroupSubscription, GroupStatus

        engine = get_db_engine('default')

        queryset = Group.objects.filter(project=project)

        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(
                Q(message__icontains=query) | Q(culprit__icontains=query))

        if status is None:
            status_in = (
                GroupStatus.PENDING_DELETION, GroupStatus.DELETION_IN_PROGRESS,
                GroupStatus.PENDING_MERGE,
            )
            queryset = queryset.exclude(status__in=status_in)
        else:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if assigned_to:
            queryset = queryset.filter(
                assignee_set__project=project,
                assignee_set__user=assigned_to,
            )
        elif unassigned in (True, False):
            queryset = queryset.filter(
                assignee_set__isnull=unassigned,
            )

        if subscribed_by is not None:
            queryset = queryset.filter(
                id__in=GroupSubscription.objects.filter(
                    project=project,
                    user=subscribed_by,
                    is_active=True,
                ).values_list('group'),
            )

        if first_release:
            if first_release is EMPTY:
                return queryset.none()
            queryset = queryset.filter(
                first_release__organization_id=project.organization_id,
                first_release__version=first_release,
            )

        if tags:
            matches = tagstore.get_tags_for_search_filter(project.id, tags)
            if not matches:
                return queryset.none()
            queryset = queryset.filter(
                id__in=matches,
            )

        if age_from or age_to:
            params = {}
            if age_from:
                if age_from_inclusive:
                    params['first_seen__gte'] = age_from
                else:
                    params['first_seen__gt'] = age_from
            if age_to:
                if age_to_inclusive:
                    params['first_seen__lte'] = age_to
                else:
                    params['first_seen__lt'] = age_to
            queryset = queryset.filter(**params)

        if last_seen_from or last_seen_to:
            params = {}
            if last_seen_from:
                if last_seen_from_inclusive:
                    params['last_seen__gte'] = last_seen_from
                else:
                    params['last_seen__gt'] = last_seen_from
            if last_seen_to:
                if last_seen_to_inclusive:
                    params['last_seen__lte'] = last_seen_to
                else:
                    params['last_seen__lt'] = last_seen_to
            queryset = queryset.filter(**params)

        if active_at_from or active_at_to:
            params = {}
            if active_at_from:
                if active_at_from_inclusive:
                    params['active_at__gte'] = active_at_from
                else:
                    params['active_at__gt'] = active_at_from
            if active_at_to:
                if active_at_to_inclusive:
                    params['active_at__lte'] = active_at_to
                else:
                    params['active_at__lt'] = active_at_to
            queryset = queryset.filter(**params)

        if times_seen is not None:
            queryset = queryset.filter(times_seen=times_seen)

        if times_seen_lower is not None or times_seen_upper is not None:
            params = {}
            if times_seen_lower is not None:
                if times_seen_lower_inclusive:
                    params['times_seen__gte'] = times_seen_lower
                else:
                    params['times_seen__gt'] = times_seen_lower
            if times_seen_upper is not None:
                if times_seen_upper_inclusive:
                    params['times_seen__lte'] = times_seen_upper
                else:
                    params['times_seen__lt'] = times_seen_upper
            queryset = queryset.filter(**params)

        if date_from or date_to:
            params = {
                'project_id': project.id,
            }
            if date_from:
                if date_from_inclusive:
                    params['datetime__gte'] = date_from
                else:
                    params['datetime__gt'] = date_from
            if date_to:
                if date_to_inclusive:
                    params['datetime__lte'] = date_to
                else:
                    params['datetime__lt'] = date_to

            event_queryset = Event.objects.filter(**params)

            if query:
                event_queryset = event_queryset.filter(
                    message__icontains=query)

            # limit to the first 1000 results
            group_ids = event_queryset.distinct().values_list(
                'group_id', flat=True)[:1000]

            # if Event is not on the primary database remove Django's
            # implicit subquery by coercing to a list
            base = router.db_for_read(Group)
            using = router.db_for_read(Event)
            # MySQL also cannot do a LIMIT inside of a subquery
            if base != using or engine.startswith('mysql'):
                group_ids = list(group_ids)

            queryset = queryset.filter(
                id__in=group_ids,
            )

        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]

        queryset = queryset.extra(
            select={'sort_value': score_clause},
        )
        return queryset
Exemple #16
0
def get_group_tags(request, organization, project, group_id, tag_name):
    # XXX(dcramer): Consider this API deprecated as soon as it was implemented
    cutoff = timezone.now() - timedelta(days=7)

    engine = get_db_engine('default')
    if 'postgres' in engine:
        # This doesnt guarantee percentage is accurate, but it does ensure
        # that the query has a maximum cost
        cursor = connections['default'].cursor()
        cursor.execute("""
            SELECT SUM(t)
            FROM (
                SELECT times_seen as t
                FROM sentry_messagefiltervalue
                WHERE group_id = %s
                AND key = %s
                AND last_seen > NOW() - INTERVAL '7 days'
                LIMIT 10000
            ) as a
        """, [group_id, tag_name])
        total = cursor.fetchone()[0] or 0
    else:
        total = GroupTagValue.objects.filter(
            group=group_id,
            key=tag_name,
            last_seen__gte=cutoff,
        ).aggregate(t=Sum('times_seen'))['t'] or 0

    unique_tags = GroupTagValue.objects.filter(
        group=group_id,
        key=tag_name,
        last_seen__gte=cutoff,
    ).values_list('value', 'times_seen').order_by('-times_seen')[:10]

    # fetch TagValue instances so we can get proper labels
    tag_values = dict(
        (t.value, t)
        for t in TagValue.objects.filter(
            key=tag_name,
            project_id=project.id,
            value__in=[u[0] for u in unique_tags],
        )
    )

    values = []
    for tag, times_seen in unique_tags:
        try:
            tag_value = tag_values[tag]
        except KeyError:
            label = tag
        else:
            label = tag_value.get_label()

        values.append({
            'value': tag,
            'count': times_seen,
            'label': label,
        })

    return json.dumps({
        'name': tag_name,
        'values': values,
        'total': total,
    })
Exemple #17
0
    def query(self, project, query=None, status=None, tags=None,
              bookmarked_by=None, assigned_to=None, first_release=None,
              sort_by='date', date_filter='last_seen', date_from=None,
              date_to=None, cursor=None, limit=100):
        from sentry.models import Group, GroupStatus

        queryset = Group.objects.filter(project=project)
        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(
                Q(message__icontains=query) |
                Q(culprit__icontains=query)
            )

        if status is None:
            queryset = queryset.exclude(
                status__in=(
                    GroupStatus.PENDING_DELETION,
                    GroupStatus.DELETION_IN_PROGRESS,
                    GroupStatus.PENDING_MERGE,
                )
            )
        else:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if assigned_to:
            queryset = queryset.filter(
                assignee_set__project=project,
                assignee_set__user=assigned_to,
            )

        if first_release:
            queryset = queryset.filter(
                first_release__project=project,
                first_release__version=first_release,
            )

        if tags:
            for k, v in tags.iteritems():
                queryset = queryset.filter(**dict(
                    grouptag__key=k,
                    grouptag__value=v,
                ))

        if date_filter == 'first_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    first_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(first_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(first_seen__lte=date_to)
        elif date_filter == 'last_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    last_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(last_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(last_seen__lte=date_to)

        engine = get_db_engine('default')
        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]

        if sort_by == 'tottime':
            queryset = queryset.filter(time_spent_count__gt=0)
        elif sort_by == 'avgtime':
            queryset = queryset.filter(time_spent_count__gt=0)

        queryset = queryset.extra(
            select={'sort_value': score_clause},
        )

        # HACK: don't sort by the same column twice
        if sort_by == 'date':
            paginator_cls = DateTimePaginator
            sort_clause = '-last_seen'
        elif sort_by == 'priority':
            paginator_cls = Paginator
            sort_clause = '-score'
        elif sort_by == 'new':
            paginator_cls = DateTimePaginator
            sort_clause = '-first_seen'
        elif sort_by == 'freq':
            paginator_cls = Paginator
            sort_clause = '-times_seen'
        else:
            paginator_cls = Paginator
            sort_clause = '-sort_value'

        queryset = queryset.order_by(sort_clause)

        paginator = paginator_cls(queryset, sort_clause)
        return paginator.get_result(limit, cursor)
Exemple #18
0
    def query(self, project, query=None, status=None, tags=None,
              bookmarked_by=None, sort_by='date', date_filter='last_seen',
              date_from=None, date_to=None, cursor=None, limit=100):
        from sentry.models import Group

        queryset = Group.objects.filter(project=project)
        if query:
            queryset = queryset.filter(message__icontains=query)

        if status is not None:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if tags:
            for k, v in tags.iteritems():
                queryset = queryset.filter(**dict(
                    grouptag__key=k,
                    grouptag__value=v,
                ))

        if date_filter == 'first_seen':
            if date_from:
                queryset = queryset.filter(first_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(first_seen__lte=date_to)
        elif date_filter == 'last_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    last_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(last_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(last_seen__lte=date_to)

        engine = get_db_engine('default')
        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES.get(sort_by)
            filter_clause = SQLITE_SCORE_CLAUSES.get(sort_by)
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES.get(sort_by)
            filter_clause = MYSQL_SCORE_CLAUSES.get(sort_by)
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES.get(sort_by)
            filter_clause = ORACLE_SCORE_CLAUSES.get(sort_by)
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES.get(sort_by)
            filter_clause = MSSQL_SCORE_CLAUSES.get(sort_by)
        else:
            score_clause = SORT_CLAUSES.get(sort_by)
            filter_clause = SCORE_CLAUSES.get(sort_by)

        if sort_by == 'tottime':
            queryset = queryset.filter(time_spent_count__gt=0)
        elif sort_by == 'avgtime':
            queryset = queryset.filter(time_spent_count__gt=0)

        if score_clause:
            queryset = queryset.extra(
                select={'sort_value': score_clause},
            )
            # HACK: don't sort by the same column twice
            if sort_by == 'date':
                queryset = queryset.order_by('-last_seen')
            else:
                queryset = queryset.order_by('-sort_value', '-last_seen')

            if cursor:
                queryset = queryset.extra(
                    where=['%s > %%s' % filter_clause],
                    params=[float(cursor)],
                )

        # HACK:
        return SearchResult(instances=list(queryset[:limit]))
Exemple #19
0
    def query(self,
              project,
              query=None,
              status=None,
              tags=None,
              bookmarked_by=None,
              sort_by='date',
              date_filter='last_seen',
              date_from=None,
              date_to=None,
              cursor=None,
              limit=100):
        from sentry.models import Group

        queryset = Group.objects.filter(project=project)
        if query:
            queryset = queryset.filter(message__icontains=query)

        if status is not None:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if tags:
            for k, v in tags.iteritems():
                queryset = queryset.filter(**dict(
                    grouptag__key=k,
                    grouptag__value=v,
                ))

        if date_filter == 'first_seen':
            if date_from:
                queryset = queryset.filter(first_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(first_seen__lte=date_to)
        elif date_filter == 'last_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    last_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(last_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(last_seen__lte=date_to)

        engine = get_db_engine('default')
        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES.get(sort_by)
            filter_clause = SQLITE_SCORE_CLAUSES.get(sort_by)
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES.get(sort_by)
            filter_clause = MYSQL_SCORE_CLAUSES.get(sort_by)
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES.get(sort_by)
            filter_clause = ORACLE_SCORE_CLAUSES.get(sort_by)
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES.get(sort_by)
            filter_clause = MSSQL_SCORE_CLAUSES.get(sort_by)
        else:
            score_clause = SORT_CLAUSES.get(sort_by)
            filter_clause = SCORE_CLAUSES.get(sort_by)

        if sort_by == 'tottime':
            queryset = queryset.filter(time_spent_count__gt=0)
        elif sort_by == 'avgtime':
            queryset = queryset.filter(time_spent_count__gt=0)

        if score_clause:
            queryset = queryset.extra(select={'sort_value': score_clause}, )
            # HACK: don't sort by the same column twice
            if sort_by == 'date':
                queryset = queryset.order_by('-last_seen')
            else:
                queryset = queryset.order_by('-sort_value', '-last_seen')

            if cursor:
                queryset = queryset.extra(
                    where=['%s > %%s' % filter_clause],
                    params=[float(cursor)],
                )

        # HACK:
        return SearchResult(instances=queryset[:limit])
Exemple #20
0
    def query(
        self,
        project,
        query=None,
        status=None,
        tags=None,
        bookmarked_by=None,
        assigned_to=None,
        first_release=None,
        sort_by="date",
        age_from=None,
        age_to=None,
        unassigned=None,
        date_from=None,
        date_to=None,
        cursor=None,
        limit=100,
    ):
        from sentry.models import Event, Group, GroupStatus

        queryset = Group.objects.filter(project=project)
        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(Q(message__icontains=query) | Q(culprit__icontains=query))

        if status is None:
            queryset = queryset.exclude(
                status__in=(GroupStatus.PENDING_DELETION, GroupStatus.DELETION_IN_PROGRESS, GroupStatus.PENDING_MERGE)
            )
        else:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(bookmark_set__project=project, bookmark_set__user=bookmarked_by)

        if assigned_to:
            queryset = queryset.filter(assignee_set__project=project, assignee_set__user=assigned_to)
        elif unassigned in (True, False):
            queryset = queryset.filter(assignee_set__isnull=unassigned)

        if first_release:
            queryset = queryset.filter(first_release__project=project, first_release__version=first_release)

        if tags:
            for k, v in tags.iteritems():
                if v == ANY:
                    queryset = queryset.filter(grouptag__key=k)
                else:
                    queryset = queryset.filter(grouptag__key=k, grouptag__value=v)

        if age_from and age_to:
            queryset = queryset.filter(first_seen__gte=age_from, first_seen__lte=age_to)
        elif age_from:
            queryset = queryset.filter(first_seen__gte=age_from)
        elif age_to:
            queryset = queryset.filter(first_seen__lte=age_to)

        if date_from or date_to:
            if date_from and date_to:
                event_queryset = Event.objects.filter(
                    project_id=project.id, datetime__gte=date_from, datetime__lte=date_to
                )
            elif date_from:
                event_queryset = Event.objects.filter(project_id=project.id, datetime__gte=date_from)
            elif date_to:
                event_queryset = Event.objects.filter(project_id=project.id, datetime__lte=date_to)
            # limit to the first 1000 results
            group_ids = event_queryset.distinct().values_list("group_id", flat=True)[:1000]
            queryset = queryset.filter(id__in=group_ids)

        engine = get_db_engine("default")
        if engine.startswith("sqlite"):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
        elif engine.startswith("mysql"):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
        elif engine.startswith("oracle"):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]

        if sort_by == "tottime":
            queryset = queryset.filter(time_spent_count__gt=0)
        elif sort_by == "avgtime":
            queryset = queryset.filter(time_spent_count__gt=0)

        queryset = queryset.extra(select={"sort_value": score_clause})

        # HACK: don't sort by the same column twice
        if sort_by == "date":
            paginator_cls = DateTimePaginator
            sort_clause = "-last_seen"
        elif sort_by == "priority":
            paginator_cls = Paginator
            sort_clause = "-score"
        elif sort_by == "new":
            paginator_cls = DateTimePaginator
            sort_clause = "-first_seen"
        elif sort_by == "freq":
            paginator_cls = Paginator
            sort_clause = "-times_seen"
        else:
            paginator_cls = Paginator
            sort_clause = "-sort_value"

        queryset = queryset.order_by(sort_clause)

        paginator = paginator_cls(queryset, sort_clause)
        return paginator.get_result(limit, cursor)
Exemple #21
0
    def get_accelerated(self, queryset=None, minutes=15):
        # mintues should
        from sentry.models import MessageCountByMinute
        mcbm_tbl = MessageCountByMinute._meta.db_table
        if queryset is None:
            queryset = self

        normalization = float(settings.MINUTE_NORMALIZATION)
        assert minutes >= normalization

        engine = get_db_engine(queryset.db)
        # We technically only support mysql and postgresql, since there seems to be no standard
        # way to get the epoch from a datetime/interval
        if engine.startswith('mysql'):
            minute_clause = "interval %s minute"
            epoch_clause = "unix_timestamp(utc_timestamp()) - unix_timestamp(%(mcbm_tbl)s.date)"
            now_clause = 'utc_timestamp()'
        else:
            minute_clause = "interval '%s minutes'"
            epoch_clause = "extract(epoch from now()) - extract(epoch from %(mcbm_tbl)s.date)"
            now_clause = 'now()'

        epoch_clause = epoch_clause % dict(mcbm_tbl=mcbm_tbl)

        queryset = queryset.extra(
            where=[
                "%s.date >= %s - %s" % (mcbm_tbl, now_clause, minute_clause % (minutes + 1, )),
                "%s.date <= %s - %s" % (mcbm_tbl, now_clause, minute_clause % (1, ))
            ],
        ).annotate(x=Sum('messagecountbyminute__times_seen')).order_by('id')

        sql, params = queryset.query.get_compiler(queryset.db).as_sql()
        before_select, after_select = str(sql).split('SELECT ', 1)
        before_where, after_where = after_select.split(' WHERE ', 1)
        before_group, after_group = after_where.split(' GROUP BY ', 1)

        # Ensure we remove any ordering clause
        after_group = after_group.split(' ORDER BY ')[0]

        query = """
        SELECT DISTINCT (SUM(%(mcbm_tbl)s.times_seen) * (%(norm)f / (%(epoch_clause)s / 60)) + 1.0) / (COALESCE(z.rate, 0) + 1.0) as accel,
               (COALESCE(z.rate, 0) + 1.0) as prev_rate,
               %(before_where)s
        LEFT JOIN (SELECT a.group_id, SUM(a.times_seen) / COUNT(a.times_seen) / %(norm)f as rate
            FROM %(mcbm_tbl)s as a
            WHERE a.date BETWEEN %(now)s - %(max_time)s
            AND %(now)s - %(min_time)s
            GROUP BY a.group_id) as z
        ON z.group_id = %(mcbm_tbl)s.group_id
        WHERE %(mcbm_tbl)s.date BETWEEN %(now)s - %(min_time)s
        AND %(now)s - %(offset_time)s
        AND %(before_group)s
        GROUP BY prev_rate, %(mcbm_tbl)s.date, %(after_group)s
        HAVING SUM(%(mcbm_tbl)s.times_seen) > 0
        ORDER BY accel DESC
        """ % dict(
            mcbm_tbl=mcbm_tbl,
            before_where=before_where,
            before_group=before_group,
            after_group=after_group,
            offset_time=minute_clause % (1,),
            min_time=minute_clause % (minutes + 1,),
            max_time=minute_clause % (minutes * (60 / normalization),),
            norm=normalization,
            epoch_clause=epoch_clause,
            now=now_clause,
        )
        return RawQuerySet(self, query, params)
Exemple #22
0
 def test_with_dotted_path(self):
     with self.Settings(DATABASES={'default': {'ENGINE': 'blah.sqlite3'}}):
         self.assertEquals(get_db_engine(), 'sqlite3')
Exemple #23
0
 def test_no_path(self):
     with self.Settings(DATABASES={'default': {'ENGINE': 'mysql'}}):
         self.assertEquals(get_db_engine(), 'mysql')
Exemple #24
0
 def test_with_dotted_path(self):
     with self.settings(DATABASES={'default': {'ENGINE': 'blah.postgres'}}):
         self.assertEquals(get_db_engine(), 'postgres')
Exemple #25
0
    def query(self, project, query=None, status=None, tags=None,
              bookmarked_by=None, assigned_to=None, first_release=None,
              sort_by='date', unassigned=None,
              age_from=None, age_from_inclusive=True,
              age_to=None, age_to_inclusive=True,
              date_from=None, date_from_inclusive=True,
              date_to=None, date_to_inclusive=True,
              cursor=None, limit=100):
        from sentry.models import Event, Group, GroupStatus

        queryset = Group.objects.filter(project=project)
        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(
                Q(message__icontains=query) |
                Q(culprit__icontains=query)
            )

        if status is None:
            queryset = queryset.exclude(
                status__in=(
                    GroupStatus.PENDING_DELETION,
                    GroupStatus.DELETION_IN_PROGRESS,
                    GroupStatus.PENDING_MERGE,
                )
            )
        else:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if assigned_to:
            queryset = queryset.filter(
                assignee_set__project=project,
                assignee_set__user=assigned_to,
            )
        elif unassigned in (True, False):
            queryset = queryset.filter(
                assignee_set__isnull=unassigned,
            )

        if first_release:
            queryset = queryset.filter(
                first_release__project=project,
                first_release__version=first_release,
            )

        if tags:
            for k, v in tags.iteritems():
                if v == ANY:
                    queryset = queryset.filter(
                        grouptag__project=project,
                        grouptag__key=k,
                    )
                else:
                    queryset = queryset.filter(
                        grouptag__project=project,
                        grouptag__key=k,
                        grouptag__value=v,
                    )
            queryset = queryset.distinct()

        if age_from or age_to:
            params = {}
            if age_from:
                if age_from_inclusive:
                    params['first_seen__gte'] = age_from
                else:
                    params['first_seen__gt'] = age_from
            if age_to:
                if age_to_inclusive:
                    params['first_seen__lte'] = age_to
                else:
                    params['first_seen__lt'] = age_to
            queryset = queryset.filter(**params)

        if date_from or date_to:
            params = {
                'project_id': project.id,
            }
            if date_from:
                if date_from_inclusive:
                    params['datetime__gte'] = date_from
                else:
                    params['datetime__gt'] = date_from
            if date_to:
                if date_to_inclusive:
                    params['datetime__lte'] = date_to
                else:
                    params['datetime__lt'] = date_to

            event_queryset = Event.objects.filter(**params)
            # limit to the first 1000 results
            group_ids = event_queryset.distinct().values_list(
                'group_id',
                flat=True
            )[:1000]

            # if Event is not on the primary database remove Django's
            # implicit subquery by coercing to a list
            base = router.db_for_read(Group)
            using = router.db_for_read(Event)
            if base != using:
                group_ids = list(group_ids)

            queryset = queryset.filter(
                id__in=group_ids,
            )

        engine = get_db_engine('default')
        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]

        if sort_by == 'tottime':
            queryset = queryset.filter(time_spent_count__gt=0)
        elif sort_by == 'avgtime':
            queryset = queryset.filter(time_spent_count__gt=0)

        queryset = queryset.extra(
            select={'sort_value': score_clause},
        )

        # HACK: don't sort by the same column twice
        if sort_by == 'date':
            paginator_cls = DateTimePaginator
            sort_clause = '-last_seen'
        elif sort_by == 'priority':
            paginator_cls = Paginator
            sort_clause = '-score'
        elif sort_by == 'new':
            paginator_cls = DateTimePaginator
            sort_clause = '-first_seen'
        elif sort_by == 'freq':
            paginator_cls = Paginator
            sort_clause = '-times_seen'
        else:
            paginator_cls = Paginator
            sort_clause = '-sort_value'

        queryset = queryset.order_by(sort_clause)

        paginator = paginator_cls(queryset, sort_clause)
        return paginator.get_result(limit, cursor)
Exemple #26
0
    def _build_queryset(self,
                        project,
                        query=None,
                        status=None,
                        tags=None,
                        bookmarked_by=None,
                        assigned_to=None,
                        first_release=None,
                        sort_by='date',
                        unassigned=None,
                        age_from=None,
                        age_from_inclusive=True,
                        age_to=None,
                        age_to_inclusive=True,
                        date_from=None,
                        date_from_inclusive=True,
                        date_to=None,
                        date_to_inclusive=True,
                        cursor=None,
                        limit=None):
        from sentry.models import Event, Group, GroupStatus

        engine = get_db_engine('default')

        queryset = Group.objects.filter(project=project)
        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(
                Q(message__icontains=query) | Q(culprit__icontains=query))

        if status is None:
            queryset = queryset.exclude(status__in=(
                GroupStatus.PENDING_DELETION,
                GroupStatus.DELETION_IN_PROGRESS,
                GroupStatus.PENDING_MERGE,
            ))
        else:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if assigned_to:
            queryset = queryset.filter(
                assignee_set__project=project,
                assignee_set__user=assigned_to,
            )
        elif unassigned in (True, False):
            queryset = queryset.filter(assignee_set__isnull=unassigned, )

        if first_release:
            if first_release is EMPTY:
                return queryset.none()
            queryset = queryset.filter(
                first_release__project=project,
                first_release__version=first_release,
            )

        if tags:
            matches = self._tags_to_filter(project, tags)
            if not matches:
                return queryset.none()
            queryset = queryset.filter(id__in=matches, )

        if age_from or age_to:
            params = {}
            if age_from:
                if age_from_inclusive:
                    params['first_seen__gte'] = age_from
                else:
                    params['first_seen__gt'] = age_from
            if age_to:
                if age_to_inclusive:
                    params['first_seen__lte'] = age_to
                else:
                    params['first_seen__lt'] = age_to
            queryset = queryset.filter(**params)

        if date_from or date_to:
            params = {
                'project_id': project.id,
            }
            if date_from:
                if date_from_inclusive:
                    params['datetime__gte'] = date_from
                else:
                    params['datetime__gt'] = date_from
            if date_to:
                if date_to_inclusive:
                    params['datetime__lte'] = date_to
                else:
                    params['datetime__lt'] = date_to

            event_queryset = Event.objects.filter(**params)
            # limit to the first 1000 results
            group_ids = event_queryset.distinct().values_list('group_id',
                                                              flat=True)[:1000]

            # if Event is not on the primary database remove Django's
            # implicit subquery by coercing to a list
            base = router.db_for_read(Group)
            using = router.db_for_read(Event)
            # MySQL also cannot do a LIMIT inside of a subquery
            if base != using or engine.startswith('mysql'):
                group_ids = list(group_ids)

            queryset = queryset.filter(id__in=group_ids, )

        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]

        queryset = queryset.extra(select={'sort_value': score_clause}, )
        return queryset
Exemple #27
0
    def get_accelerated(self, project_ids, queryset=None, minutes=15):
        if not project_ids:
            return self.none()

        if queryset is None:
            queryset = self.filter(
                project__in=project_ids,
                status=STATUS_UNRESOLVED,
            )
        else:
            queryset = queryset._clone()
            queryset.query.select_related = False

        normalization = float(MINUTE_NORMALIZATION)

        assert minutes >= normalization

        intervals = 8

        engine = get_db_engine(queryset.db)
        # We technically only support mysql and postgresql, since there seems to be no standard
        # way to get the epoch from a datetime/interval
        if engine.startswith('mysql'):
            minute_clause = "interval %s minute"
            epoch_clause = "unix_timestamp(utc_timestamp()) - unix_timestamp(mcbm.date)"
            now_clause = 'utc_timestamp()'
        else:
            minute_clause = "interval '%s minutes'"
            epoch_clause = "extract(epoch from now()) - extract(epoch from mcbm.date)"
            now_clause = 'now()'

        sql, params = queryset.query.get_compiler(queryset.db).as_sql()
        before_select, after_select = str(sql).split('SELECT ', 1)
        after_where = after_select.split(' WHERE ', 1)[1]

        # Ensure we remove any ordering clause
        after_where = after_where.split(' ORDER BY ')[0]

        query = """
        SELECT ((mcbm.times_seen + 1) / ((%(epoch_clause)s) / 60)) / (COALESCE(z.rate, 0) + 1) as sort_value,
               %(fields)s
        FROM sentry_groupedmessage
        INNER JOIN sentry_messagecountbyminute as mcbm
            ON (sentry_groupedmessage.id = mcbm.group_id)
        LEFT JOIN (SELECT a.group_id, (SUM(a.times_seen)) / COUNT(a.times_seen) / %(norm)f as rate
            FROM sentry_messagecountbyminute as a
            WHERE a.date >=  %(now)s - %(max_time)s
            AND a.date < %(now)s - %(min_time)s
            AND a.project_id IN (%(project_ids)s)
            GROUP BY a.group_id) as z
        ON z.group_id = mcbm.group_id
        WHERE mcbm.date >= %(now)s - %(min_time)s
        AND mcbm.date < %(now)s - %(offset_time)s
        AND mcbm.times_seen > 0
        AND ((mcbm.times_seen + 1) / ((%(epoch_clause)s) / 60)) > (COALESCE(z.rate, 0) + 1)
        AND %(after_where)s
        GROUP BY z.rate, mcbm.times_seen, mcbm.date, %(fields)s
        ORDER BY sort_value DESC
        """ % dict(
            fields=self.model_fields_clause,
            after_where=after_where,
            offset_time=minute_clause % (1,),
            min_time=minute_clause % (minutes + 1,),
            max_time=minute_clause % (minutes * intervals + 1,),
            norm=normalization,
            epoch_clause=epoch_clause,
            now=now_clause,
            project_ids=', '.join((str(int(x)) for x in project_ids)),
        )
        return RawQuerySet(self, query, params)
Exemple #28
0
                messagecountbyminute__date__gte=date_from)
    if date_to:
        if not date_from:
            event_list = event_list.filter(last_seen__lte=date_to)
        else:
            event_list = event_list.filter(
                messagecountbyminute__date__lte=date_to)

    sort = request.GET.get('sort')
    if sort not in SORT_OPTIONS:
        sort = settings.DEFAULT_SORT_OPTION

    if sort.startswith('accel_') and not has_trending():
        sort = settings.DEFAULT_SORT_OPTION

    engine = get_db_engine('default')
    if engine.startswith('sqlite'):
        sort_clause = SQLITE_SORT_CLAUSES.get(sort)
    elif engine.startswith('mysql'):
        sort_clause = MYSQL_SORT_CLAUSES.get(sort)
    else:
        sort_clause = SORT_CLAUSES.get(sort)

    # All filters must already be applied once we reach this point
    if sort == 'tottime':
        event_list = event_list.filter(time_spent_count__gt=0)
    elif sort == 'avgtime':
        event_list = event_list.filter(time_spent_count__gt=0)
    elif sort.startswith('accel_'):
        event_list = Group.objects.get_accelerated(event_list,
                                                   minutes=int(
Exemple #29
0
def _get_group_list(request, project):
    filters = []
    for cls in get_filters(Group, project):
        try:
            filters.append(cls(request, project))
        except Exception as e:
            logger = logging.getLogger('sentry.filters')
            logger.exception('Error initializing filter %r: %s', cls, e)

    event_list = Group.objects
    if request.user.is_authenticated() and request.GET.get('bookmarks'):
        event_list = event_list.filter(
            bookmark_set__project=project,
            bookmark_set__user=request.user,
        )
    else:
        event_list = event_list.filter(project=project)

    for filter_ in filters:
        try:
            if not filter_.is_set():
                continue
            event_list = filter_.get_query_set(event_list)
        except Exception as e:
            logger = logging.getLogger('sentry.filters')
            logger.exception('Error processing filter %r: %s', cls, e)

    date_from = request.GET.get('df')
    time_from = request.GET.get('tf')
    date_to = request.GET.get('dt')
    time_to = request.GET.get('tt')
    date_type = request.GET.get('date_type')

    today = timezone.now()

    # date format is Y-m-d
    if any(x is not None for x in [date_from, time_from, date_to, time_to]):
        date_from, date_to = parse_date(date_from, time_from), parse_date(date_to, time_to)
    else:
        date_from = today - datetime.timedelta(days=5)
        date_to = None

    if date_type == 'first_seen':
        if date_from:
            event_list = event_list.filter(first_seen__gte=date_from)
        elif date_to:
            event_list = event_list.filter(first_seen__lte=date_to)
    else:
        if date_from and date_to:
            event_list = event_list.filter(
                first_seen__gte=date_from,
                last_seen__lte=date_to,
            )
        elif date_from:
            event_list = event_list.filter(last_seen__gte=date_from)
        elif date_to:
            event_list = event_list.filter(last_seen__lte=date_to)

    sort = request.GET.get('sort') or request.session.get('streamsort')
    if sort not in SORT_OPTIONS:
        sort = DEFAULT_SORT_OPTION

    # Save last sort in session
    if sort != request.session.get('streamsort'):
        request.session['streamsort'] = sort

    engine = get_db_engine('default')
    if engine.startswith('sqlite'):
        score_clause = SQLITE_SORT_CLAUSES.get(sort)
        filter_clause = SQLITE_SCORE_CLAUSES.get(sort)
    elif engine.startswith('mysql'):
        score_clause = MYSQL_SORT_CLAUSES.get(sort)
        filter_clause = MYSQL_SCORE_CLAUSES.get(sort)
    elif engine.startswith('oracle'):
        score_clause = ORACLE_SORT_CLAUSES.get(sort)
        filter_clause = ORACLE_SCORE_CLAUSES.get(sort)
    elif engine in ('django_pytds', 'sqlserver_ado', 'sql_server.pyodbc'):
        score_clause = MSSQL_SORT_CLAUSES.get(sort)
        filter_clause = MSSQL_SCORE_CLAUSES.get(sort)
    else:
        score_clause = SORT_CLAUSES.get(sort)
        filter_clause = SCORE_CLAUSES.get(sort)

    # IMPORTANT: All filters must already be applied once we reach this point

    if sort == 'tottime':
        event_list = event_list.filter(time_spent_count__gt=0)
    elif sort == 'avgtime':
        event_list = event_list.filter(time_spent_count__gt=0)

    if score_clause:
        event_list = event_list.extra(
            select={'sort_value': score_clause},
        )
        # HACK: don't sort by the same column twice
        if sort == 'date':
            event_list = event_list.order_by('-last_seen')
        else:
            event_list = event_list.order_by('-sort_value', '-last_seen')
        cursor = request.GET.get('cursor', request.GET.get('c'))
        if cursor:
            event_list = event_list.extra(
                where=['%s > %%s' % filter_clause],
                params=[float(cursor)],
            )

    return {
        'filters': filters,
        'event_list': event_list,
        'date_from': date_from,
        'date_to': date_to,
        'today': today,
        'sort': sort,
        'date_type': date_type
    }
Exemple #30
0
    def _build_queryset(
        self,
        project,
        query=None,
        status=None,
        tags=None,
        bookmarked_by=None,
        assigned_to=None,
        first_release=None,
        sort_by="date",
        unassigned=None,
        age_from=None,
        age_from_inclusive=True,
        age_to=None,
        age_to_inclusive=True,
        date_from=None,
        date_from_inclusive=True,
        date_to=None,
        date_to_inclusive=True,
        cursor=None,
        limit=None,
    ):
        from sentry.models import Event, Group, GroupStatus

        engine = get_db_engine("default")

        queryset = Group.objects.filter(project=project)
        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(Q(message__icontains=query) | Q(culprit__icontains=query))

        if status is None:
            queryset = queryset.exclude(
                status__in=(GroupStatus.PENDING_DELETION, GroupStatus.DELETION_IN_PROGRESS, GroupStatus.PENDING_MERGE)
            )
        else:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(bookmark_set__project=project, bookmark_set__user=bookmarked_by)

        if assigned_to:
            queryset = queryset.filter(assignee_set__project=project, assignee_set__user=assigned_to)
        elif unassigned in (True, False):
            queryset = queryset.filter(assignee_set__isnull=unassigned)

        if first_release:
            if first_release is EMPTY:
                return queryset.none()
            queryset = queryset.filter(first_release__project=project, first_release__version=first_release)

        if tags:
            matches = self._tags_to_filter(project, tags)
            if not matches:
                return queryset.none()
            queryset = queryset.filter(id__in=matches)

        if age_from or age_to:
            params = {}
            if age_from:
                if age_from_inclusive:
                    params["first_seen__gte"] = age_from
                else:
                    params["first_seen__gt"] = age_from
            if age_to:
                if age_to_inclusive:
                    params["first_seen__lte"] = age_to
                else:
                    params["first_seen__lt"] = age_to
            queryset = queryset.filter(**params)

        if date_from or date_to:
            params = {"project_id": project.id}
            if date_from:
                if date_from_inclusive:
                    params["datetime__gte"] = date_from
                else:
                    params["datetime__gt"] = date_from
            if date_to:
                if date_to_inclusive:
                    params["datetime__lte"] = date_to
                else:
                    params["datetime__lt"] = date_to

            event_queryset = Event.objects.filter(**params)
            # limit to the first 1000 results
            group_ids = event_queryset.distinct().values_list("group_id", flat=True)[:1000]

            # if Event is not on the primary database remove Django's
            # implicit subquery by coercing to a list
            base = router.db_for_read(Group)
            using = router.db_for_read(Event)
            # MySQL also cannot do a LIMIT inside of a subquery
            if base != using or engine.startswith("mysql"):
                group_ids = list(group_ids)

            queryset = queryset.filter(id__in=group_ids)

        if engine.startswith("sqlite"):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
        elif engine.startswith("mysql"):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
        elif engine.startswith("oracle"):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]

        queryset = queryset.extra(select={"sort_value": score_clause})
        return queryset
Exemple #31
0
        try:
            if not filter_.is_set():
                continue
            event_list = filter_.get_query_set(event_list)
        except Exception, e:
            logger = logging.getLogger('sentry.filters')
            logger.exception('Error processing filter %r: %s', cls, e)

    sort = request.GET.get('sort')
    if sort not in SORT_OPTIONS:
        sort = settings.DEFAULT_SORT_OPTION

    if sort.startswith('accel_') and not has_trending():
        sort = settings.DEFAULT_SORT_OPTION

    engine = get_db_engine('default')
    if engine.startswith('sqlite'):
        sort_clause = SQLITE_SORT_CLAUSES.get(sort)
    elif engine.startswith('mysql'):
        sort_clause = MYSQL_SORT_CLAUSES.get(sort)
    else:
        sort_clause = SORT_CLAUSES.get(sort)

    if sort == 'tottime':
        event_list = event_list.filter(time_spent_count__gt=0)
    elif sort == 'avgtime':
        event_list = event_list.filter(time_spent_count__gt=0)
    elif sort.startswith('accel_'):
        event_list = Group.objects.get_accelerated(event_list, minutes=int(sort.split('_', 1)[1]))

    date_from = request.GET.get('df')
Exemple #32
0
    def get_accelerated(self, project_ids, queryset=None, minutes=15):
        if not project_ids:
            return self.none()

        if queryset is None:
            queryset = self.filter(
                project__in=project_ids,
                status=STATUS_UNRESOLVED,
            )
        else:
            queryset = queryset._clone()
            queryset.query.select_related = False

        normalization = float(MINUTE_NORMALIZATION)

        assert minutes >= normalization

        intervals = 8

        engine = get_db_engine(queryset.db)
        # We technically only support mysql and postgresql, since there seems to be no standard
        # way to get the epoch from a datetime/interval
        if engine.startswith('mysql'):
            minute_clause = "interval %s minute"
            epoch_clause = "unix_timestamp(utc_timestamp()) - unix_timestamp(mcbm.date)"
            now_clause = 'utc_timestamp()'
        else:
            minute_clause = "interval '%s minutes'"
            epoch_clause = "extract(epoch from now()) - extract(epoch from mcbm.date)"
            now_clause = 'now()'

        sql, params = queryset.query.get_compiler(queryset.db).as_sql()
        before_select, after_select = str(sql).split('SELECT ', 1)
        after_where = after_select.split(' WHERE ', 1)[1]

        # Ensure we remove any ordering clause
        after_where = after_where.split(' ORDER BY ')[0]

        query = """
        SELECT ((mcbm.times_seen + 1) / ((%(epoch_clause)s) / 60)) / (COALESCE(z.rate, 0) + 1) as sort_value,
               %(fields)s
        FROM sentry_groupedmessage
        INNER JOIN sentry_messagecountbyminute as mcbm
            ON (sentry_groupedmessage.id = mcbm.group_id)
        LEFT JOIN (SELECT a.group_id, (SUM(a.times_seen)) / COUNT(a.times_seen) / %(norm)f as rate
            FROM sentry_messagecountbyminute as a
            WHERE a.date >=  %(now)s - %(max_time)s
            AND a.date < %(now)s - %(min_time)s
            AND a.project_id IN (%(project_ids)s)
            GROUP BY a.group_id) as z
        ON z.group_id = mcbm.group_id
        WHERE mcbm.date >= %(now)s - %(min_time)s
        AND mcbm.date < %(now)s - %(offset_time)s
        AND mcbm.times_seen > 0
        AND ((mcbm.times_seen + 1) / ((%(epoch_clause)s) / 60)) > (COALESCE(z.rate, 0) + 1)
        AND %(after_where)s
        GROUP BY z.rate, mcbm.times_seen, mcbm.date, %(fields)s
        ORDER BY sort_value DESC
        """ % dict(
            fields=self.model_fields_clause,
            after_where=after_where,
            offset_time=minute_clause % (1, ),
            min_time=minute_clause % (minutes + 1, ),
            max_time=minute_clause % (minutes * intervals + 1, ),
            norm=normalization,
            epoch_clause=epoch_clause,
            now=now_clause,
            project_ids=', '.join((str(int(x)) for x in project_ids)),
        )
        return RawQuerySet(self, query, params)
    def get(self, request, project_id):
        project = Project.objects.get(
            id=project_id,
        )

        assert_perm(project, request.user, request.auth)

        group_list = Group.objects.all()

        if request.user.is_authenticated() and request.GET.get('bookmarks'):
            group_list = group_list.filter(
                bookmark_set__project=project,
                bookmark_set__user=request.user,
            )
        else:
            group_list = group_list.filter(project=project)

        status = request.GET.get('status')
        if status:
            group_list = group_list.filter(status=int(status))

        tag_keys = TagKey.objects.all_keys(project)
        for tag in tag_keys:
            value = request.GET.get(tag)
            if value:
                group_list = group_list.filter(
                    grouptag__project=project,
                    grouptag__key=tag,
                    grouptag__value=value,
                )

        # TODO: dates should include timestamps
        date_from = request.GET.get('since')
        time_from = request.GET.get('until')
        date_filter = request.GET.get('date_filter')

        date_to = request.GET.get('dt')
        time_to = request.GET.get('tt')

        today = timezone.now()

        # date format is Y-m-d
        if any(x is not None for x in [date_from, time_from, date_to, time_to]):
            date_from, date_to = parse_date(date_from, time_from), parse_date(date_to, time_to)
        else:
            date_from = today - timedelta(days=5)
            date_to = None

        if date_filter == 'first_seen':
            if date_from:
                group_list = group_list.filter(first_seen__gte=date_from)
            elif date_to:
                group_list = group_list.filter(first_seen__lte=date_to)
        else:
            # TODO(dcramer): a date_to no longer makes a lot of sense, and will
            # need corrected when search lands
            if date_from:
                group_list = group_list.filter(last_seen__gte=date_from)
            if date_to:
                group_list = group_list.filter(last_seen__lte=date_to)

        sort = request.GET.get('sort') or request.session.get('streamsort')
        if sort is None:
            sort = DEFAULT_SORT_OPTION
        elif sort not in SORT_OPTIONS or sort.startswith('accel_'):
            return HttpResponse(status=400)

        # Save last sort in session
        if sort != request.session.get('streamsort'):
            request.session['streamsort'] = sort

        engine = get_db_engine('default')
        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES.get(sort)
            filter_clause = SQLITE_SCORE_CLAUSES.get(sort)
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES.get(sort)
            filter_clause = MYSQL_SCORE_CLAUSES.get(sort)
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES.get(sort)
            filter_clause = ORACLE_SCORE_CLAUSES.get(sort)
        elif engine in ('django_pytds', 'sqlserver_ado', 'sql_server.pyodbc'):
            score_clause = MSSQL_SORT_CLAUSES.get(sort)
            filter_clause = MSSQL_SCORE_CLAUSES.get(sort)
        else:
            score_clause = SORT_CLAUSES.get(sort)
            filter_clause = SCORE_CLAUSES.get(sort)

        assert score_clause

        if sort == 'tottime':
            group_list = group_list.filter(time_spent_count__gt=0)
        elif sort == 'avgtime':
            group_list = group_list.filter(time_spent_count__gt=0)

        group_list = group_list.extra(
            select={'sort_value': score_clause},
        )

        return self.paginate(
            request=request,
            queryset=group_list,
            order_by='-sort_value',
            on_results=lambda x: serialize(x, request.user),
        )
Exemple #34
0
def get_group_tags(request, organization, project, group_id, tag_name):
    # XXX(dcramer): Consider this API deprecated as soon as it was implemented
    cutoff = timezone.now() - timedelta(days=7)

    engine = get_db_engine('default')
    if 'postgres' in engine:
        # This doesnt guarantee percentage is accurate, but it does ensure
        # that the query has a maximum cost
        cursor = connections['default'].cursor()
        cursor.execute("""
            SELECT SUM(t)
            FROM (
                SELECT times_seen as t
                FROM sentry_messagefiltervalue
                WHERE group_id = %s
                AND key = %s
                AND last_seen > NOW() - INTERVAL '7 days'
                LIMIT 10000
            ) as a
        """, [group_id, tag_name])
        total = cursor.fetchone()[0] or 0
    else:
        total = GroupTagValue.objects.filter(
            group=group_id,
            key=tag_name,
            last_seen__gte=cutoff,
        ).aggregate(t=Sum('times_seen'))['t'] or 0

    unique_tags = GroupTagValue.objects.filter(
        group=group_id,
        key=tag_name,
        last_seen__gte=cutoff,
    ).values_list('value', 'times_seen').order_by('-times_seen')[:10]

    # fetch TagValue instances so we can get proper labels
    tag_values = dict(
        (t.value, t)
        for t in TagValue.objects.filter(
            key=tag_name,
            project_id=project.id,
            value__in=[u[0] for u in unique_tags],
        )
    )

    values = []
    for tag, times_seen in unique_tags:
        try:
            tag_value = tag_values[tag]
        except KeyError:
            label = tag
        else:
            label = tag_value.get_label()

        values.append({
            'value': tag,
            'count': times_seen,
            'label': label,
        })

    return json.dumps({
        'name': tag_name,
        'values': values,
        'total': total,
    })
Exemple #35
0
    def get_accelerated(self, project_ids, queryset=None, minutes=15):
        # mintues should
        from sentry.models import MessageCountByMinute

        mcbm_tbl = MessageCountByMinute._meta.db_table
        if queryset is None:
            queryset = self

        normalization = float(settings.MINUTE_NORMALIZATION)
        assert minutes >= normalization

        engine = get_db_engine(queryset.db)
        # We technically only support mysql and postgresql, since there seems to be no standard
        # way to get the epoch from a datetime/interval
        if engine.startswith("mysql"):
            minute_clause = "interval %s minute"
            epoch_clause = "unix_timestamp(utc_timestamp()) - unix_timestamp(%(mcbm_tbl)s.date)"
            now_clause = "utc_timestamp()"
        else:
            minute_clause = "interval '%s minutes'"
            epoch_clause = "extract(epoch from now()) - extract(epoch from %(mcbm_tbl)s.date)"
            now_clause = "now()"

        epoch_clause = epoch_clause % dict(mcbm_tbl=mcbm_tbl)

        queryset = queryset.annotate(x=Sum("messagecountbyminute__times_seen")).order_by("id")

        sql, params = queryset.query.get_compiler(queryset.db).as_sql()
        before_select, after_select = str(sql).split("SELECT ", 1)
        before_where, after_where = after_select.split(" WHERE ", 1)
        before_group, after_group = after_where.split(" GROUP BY ", 1)

        # Ensure we remove any ordering clause
        after_group = after_group.split(" ORDER BY ")[0]

        # TODO: adding project_id to sort clause on left join helps query in many cases
        query = """
        SELECT (SUM(%(mcbm_tbl)s.times_seen) * (%(norm)f / (%(epoch_clause)s / 60)) + 1.0) / (COALESCE(z.rate, 0) + 1.0) as accel,
               (COALESCE(z.rate, 0) + 1.0) as prev_rate,
               %(before_where)s
        LEFT JOIN (SELECT a.group_id, SUM(a.times_seen) / COUNT(a.times_seen) / %(norm)f as rate
            FROM %(mcbm_tbl)s as a
            WHERE a.date >=  %(now)s - %(max_time)s
            AND a.date < %(now)s - %(min_time)s
            AND a.project_id IN (%(project_ids)s)
            GROUP BY a.group_id) as z
        ON z.group_id = %(mcbm_tbl)s.group_id
        WHERE %(mcbm_tbl)s.date >= %(now)s - %(min_time)s
        AND %(mcbm_tbl)s.date < %(now)s - %(offset_time)s
        AND %(before_group)s
        GROUP BY prev_rate, %(mcbm_tbl)s.date, %(after_group)s
        HAVING SUM(%(mcbm_tbl)s.times_seen) > 0
        ORDER BY accel DESC
        """ % dict(
            mcbm_tbl=mcbm_tbl,
            before_where=before_where,
            before_group=before_group,
            after_group=after_group,
            offset_time=minute_clause % (1,),
            min_time=minute_clause % (minutes + 1,),
            max_time=minute_clause % (minutes * (60 / normalization),),
            norm=normalization,
            epoch_clause=epoch_clause,
            now=now_clause,
            project_ids=", ".join((str(int(x)) for x in project_ids)),
        )
        return RawQuerySet(self, query, params)
Exemple #36
0
    def query(self,
              project,
              query=None,
              status=None,
              tags=None,
              bookmarked_by=None,
              assigned_to=None,
              first_release=None,
              sort_by='date',
              date_filter='last_seen',
              unassigned=None,
              date_from=None,
              date_to=None,
              cursor=None,
              limit=100):
        from sentry.models import Group, GroupStatus

        queryset = Group.objects.filter(project=project)
        if query:
            # TODO(dcramer): if we want to continue to support search on SQL
            # we should at least optimize this in Postgres so that it does
            # the query filter **after** the index filters, and restricts the
            # result set
            queryset = queryset.filter(
                Q(message__icontains=query) | Q(culprit__icontains=query))

        if status is None:
            queryset = queryset.exclude(status__in=(
                GroupStatus.PENDING_DELETION,
                GroupStatus.DELETION_IN_PROGRESS,
                GroupStatus.PENDING_MERGE,
            ))
        else:
            queryset = queryset.filter(status=status)

        if bookmarked_by:
            queryset = queryset.filter(
                bookmark_set__project=project,
                bookmark_set__user=bookmarked_by,
            )

        if assigned_to:
            queryset = queryset.filter(
                assignee_set__project=project,
                assignee_set__user=assigned_to,
            )
        elif unassigned in (True, False):
            queryset = queryset.filter(assignee_set__isnull=unassigned, )

        if first_release:
            queryset = queryset.filter(
                first_release__project=project,
                first_release__version=first_release,
            )

        if tags:
            for k, v in tags.iteritems():
                queryset = queryset.filter(**dict(
                    grouptag__key=k,
                    grouptag__value=v,
                ))

        if date_filter == 'first_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    first_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(first_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(first_seen__lte=date_to)
        elif date_filter == 'last_seen':
            if date_from and date_to:
                queryset = queryset.filter(
                    first_seen__gte=date_from,
                    last_seen__lte=date_to,
                )
            elif date_from:
                queryset = queryset.filter(last_seen__gte=date_from)
            elif date_to:
                queryset = queryset.filter(last_seen__lte=date_to)

        engine = get_db_engine('default')
        if engine.startswith('sqlite'):
            score_clause = SQLITE_SORT_CLAUSES[sort_by]
        elif engine.startswith('mysql'):
            score_clause = MYSQL_SORT_CLAUSES[sort_by]
        elif engine.startswith('oracle'):
            score_clause = ORACLE_SORT_CLAUSES[sort_by]
        elif engine in MSSQL_ENGINES:
            score_clause = MSSQL_SORT_CLAUSES[sort_by]
        else:
            score_clause = SORT_CLAUSES[sort_by]

        if sort_by == 'tottime':
            queryset = queryset.filter(time_spent_count__gt=0)
        elif sort_by == 'avgtime':
            queryset = queryset.filter(time_spent_count__gt=0)

        queryset = queryset.extra(select={'sort_value': score_clause}, )

        # HACK: don't sort by the same column twice
        if sort_by == 'date':
            paginator_cls = DateTimePaginator
            sort_clause = '-last_seen'
        elif sort_by == 'priority':
            paginator_cls = Paginator
            sort_clause = '-score'
        elif sort_by == 'new':
            paginator_cls = DateTimePaginator
            sort_clause = '-first_seen'
        elif sort_by == 'freq':
            paginator_cls = Paginator
            sort_clause = '-times_seen'
        else:
            paginator_cls = Paginator
            sort_clause = '-sort_value'

        queryset = queryset.order_by(sort_clause)

        paginator = paginator_cls(queryset, sort_clause)
        return paginator.get_result(limit, cursor)