コード例 #1
0
ファイル: metrics.py プロジェクト: wangjianweiwei/sentry
    def get_single_metric(self, metric_name: str) -> MetricMetaWithTagKeys:
        """Get metadata for a single metric, without tag values"""
        metric_id = indexer.resolve(metric_name)
        if metric_id is None:
            raise InvalidParams

        for metric_type in ("counter", "set", "distribution"):
            # TODO: What if metric_id exists for multiple types / units?
            entity_key = METRIC_TYPE_TO_ENTITY[metric_type]
            data = self._get_data(
                entity_key=entity_key,
                select=[Column("metric_id"), Column("tags.key")],
                where=[Condition(Column("metric_id"), Op.EQ, metric_id)],
                groupby=[Column("metric_id"), Column("tags.key")],
                referrer="snuba.metrics.meta.get_single_metric",
            )
            if data:
                tag_ids = {tag_id for row in data for tag_id in row["tags.key"]}
                return {
                    "name": metric_name,
                    "type": metric_type,
                    "operations": _AVAILABLE_OPERATIONS[entity_key.value],
                    "tags": sorted(
                        ({"key": reverse_resolve(tag_id)} for tag_id in tag_ids),
                        key=itemgetter("key"),
                    ),
                    "unit": None,
                }

        raise InvalidParams
コード例 #2
0
    def resolve_metric(self, value: str) -> int:
        metric_id = indexer.resolve(constants.METRICS_MAP.get(value, value))
        if metric_id is None:
            raise IncompatibleMetricsQuery(f"Metric: {value} could not be resolved")

        self.builder.metric_ids.append(metric_id)
        return metric_id
コード例 #3
0
def _translate_conditions(org_id: int, input_: Any) -> Any:
    if isinstance(input_, Column):
        # The only filterable tag keys are release and environment.
        assert input_.name in ("release", "environment")
        # It greatly simplifies code if we just assume that they exist.
        # Alternative would be:
        #   * if tag key or value does not exist in AND-clause, return no data
        #   * if tag key or value does not exist in OR-clause, remove condition
        return Column(resolve_tag_key(input_.name))

    if isinstance(input_, str):
        # Assuming this is the right-hand side, we need to fetch a tag value.
        # It's OK if the tag value resolves to None, the snuba query will then
        # return no results, as is intended behavior

        return indexer.resolve(input_)

    if isinstance(input_, Function):
        return Function(function=input_.function,
                        parameters=_translate_conditions(
                            org_id, input_.parameters))

    if isinstance(input_, Condition):
        return Condition(
            lhs=_translate_conditions(org_id, input_.lhs),
            op=input_.op,
            rhs=_translate_conditions(org_id, input_.rhs),
        )

    if isinstance(input_, (int, float)):
        return input_

    assert isinstance(input_, (tuple, list)), input_
    return [_translate_conditions(org_id, item) for item in input_]
コード例 #4
0
ファイル: metrics.py プロジェクト: littlekign/sentry
 def _resolve_failure_count(
     self,
     _: Mapping[str, Union[str, Column, SelectType, int, float]],
     alias: Optional[str] = None,
 ) -> SelectType:
     statuses = [
         indexer.resolve(status) for status in constants.NON_FAILURE_STATUS
     ]
     return self._resolve_count_if(
         Function(
             "equals",
             [
                 Column("metric_id"),
                 self.resolve_metric("transaction.duration"),
             ],
         ),
         Function(
             "notIn",
             [
                 self.builder.column("transaction.status"),
                 list(status for status in statuses if status is not None),
             ],
         ),
         alias,
     )
コード例 #5
0
ファイル: metrics.py プロジェクト: wangjianweiwei/sentry
def resolve_tag_value(string: str) -> int:
    resolved = indexer.resolve(string)
    if resolved is None:
        # This delegates the problem of dealing with missing tag values to
        # snuba
        return 0

    return resolved
コード例 #6
0
ファイル: metrics.py プロジェクト: littlekign/sentry
    def resolve_metric(self, value: str) -> int:
        metric_id = indexer.resolve(constants.METRICS_MAP.get(value, value))
        if metric_id is None:
            # TODO: unsure if this should be incompatible or invalid
            raise InvalidSearchQuery(f"Metric: {value} could not be resolved")

        self.builder.metric_ids.append(metric_id)
        return metric_id
コード例 #7
0
 def get_column_for_status(function_name: str, prefix: str, status: str) -> Function:
     return Function(
         f"{function_name}If",
         [
             Column("value"),
             Function(
                 "equals",
                 [Column(tag_key_session_status), indexer.resolve(status)],
             ),
         ],
         alias=f"{prefix}_{status}",
     )
コード例 #8
0
ファイル: utils.py プロジェクト: littlekign/sentry
def resolve_weak(string: str) -> int:
    """
    A version of `resolve` that returns 0 for missing values.

    When using `resolve_weak` to produce a WHERE-clause, it is quite
    useful to make the WHERE-clause "impossible" with `WHERE x = 0` instead of
    explicitly handling that exception.
    """
    resolved = indexer.resolve(string)
    if resolved is None:
        return 0

    return resolved  # type: ignore
コード例 #9
0
ファイル: metrics.py プロジェクト: KingDEV95/sentry
        def _get_common_where(
                total: bool) -> List[Union[BooleanCondition, Condition]]:
            where_common: List[Union[BooleanCondition, Condition]] = [
                Condition(Column("org_id"), Op.EQ, org_id),
                Condition(Column("project_id"), Op.IN, project_ids),
                Condition(Column("timestamp"), Op.GTE, start),
                Condition(Column("timestamp"), Op.LT, now),
                Condition(Column(tag_key(org_id, "session.status")), Op.EQ,
                          tag_value(org_id, "init")),
            ]

            if environments is not None:
                environment_tag_values = []

                for environment in environments:
                    value = indexer.resolve(org_id,
                                            environment)  # type: ignore
                    if value is not None:
                        environment_tag_values.append(value)

                where_common.append(
                    Condition(Column(tag_key(org_id, "environment")), Op.IN,
                              environment_tag_values))

            if not total:
                release_tag_values = []

                for _, release in project_releases:
                    value = indexer.resolve(org_id, release)  # type: ignore
                    if value is not None:
                        # We should not append the value if it hasn't been
                        # observed before.
                        release_tag_values.append(value)

                where_common.append(
                    Condition(Column(tag_key(org_id, "release")), Op.IN,
                              release_tag_values))

            return where_common
コード例 #10
0
def resolve_team_key_transaction_alias(
    builder: QueryBuilder, resolve_metric_index: bool = False
) -> SelectType:
    org_id = builder.params.get("organization_id")
    project_ids = builder.params.get("project_id")
    team_ids = builder.params.get("team_id")

    if org_id is None or team_ids is None or project_ids is None:
        raise TypeError("Team key transactions parameters cannot be None")

    team_key_transactions = list(
        TeamKeyTransaction.objects.filter(
            organization_id=org_id,
            project_team__in=ProjectTeam.objects.filter(
                project_id__in=project_ids, team_id__in=team_ids
            ),
        )
        .order_by("transaction", "project_team__project_id")
        .values_list("project_team__project_id", "transaction")
        .distinct("transaction", "project_team__project_id")[
            : fields.MAX_QUERYABLE_TEAM_KEY_TRANSACTIONS
        ]
    )

    count = len(team_key_transactions)
    if resolve_metric_index:
        team_key_transactions = [
            (project, indexer.resolve(transaction))
            for project, transaction in team_key_transactions
        ]

    # NOTE: this raw count is not 100% accurate because if it exceeds
    # `MAX_QUERYABLE_TEAM_KEY_TRANSACTIONS`, it will not be reflected
    sentry_sdk.set_tag("team_key_txns.count", count)
    sentry_sdk.set_tag(
        "team_key_txns.count.grouped", format_grouped_length(count, [10, 100, 250, 500])
    )

    if count == 0:
        return Function("toInt8", [0], constants.TEAM_KEY_TRANSACTION_ALIAS)

    return Function(
        "in",
        [
            (builder.column("project_id"), builder.column("transaction")),
            team_key_transactions,
        ],
        constants.TEAM_KEY_TRANSACTION_ALIAS,
    )
コード例 #11
0
ファイル: metrics.py プロジェクト: littlekign/sentry
    def _resolve_apdex_function(
        self,
        _: Mapping[str, Union[str, Column, SelectType, int, float]],
        alias: Optional[str] = None,
    ) -> SelectType:
        metric_true = indexer.resolve(constants.METRIC_TRUE_TAG_VALUE)

        # Nothing is satisfied or tolerated, the score must be 0
        if metric_true is None:
            return Function(
                "toUInt64",
                [0],
                alias,
            )

        satisfied = Function("equals", [
            self.builder.column(constants.METRIC_SATISFIED_TAG_KEY),
            metric_true
        ])
        tolerable = Function("equals", [
            self.builder.column(constants.METRIC_TOLERATED_TAG_KEY),
            metric_true
        ])
        metric_condition = Function(
            "equals",
            [Column("metric_id"),
             self.resolve_metric("transaction.duration")])

        return Function(
            "divide",
            [
                Function(
                    "plus",
                    [
                        self._resolve_count_if(metric_condition, satisfied),
                        Function(
                            "divide",
                            [
                                self._resolve_count_if(metric_condition,
                                                       tolerable), 2
                            ],
                        ),
                    ],
                ),
                Function("countIf", [metric_condition]),
            ],
            alias,
        )
コード例 #12
0
ファイル: metrics.py プロジェクト: wangjianweiwei/sentry
    def _get_metrics_filter(
        self, metric_names: Optional[Sequence[str]]
    ) -> Optional[List[Condition]]:
        """Add a condition to filter by metrics. Return None if a name cannot be resolved."""
        where = []
        if metric_names is not None:
            metric_ids = []
            for name in metric_names:
                resolved = indexer.resolve(name)
                if resolved is None:
                    # We are looking for tags that appear in all given metrics.
                    # A tag cannot appear in a metric if the metric is not even indexed.
                    return None
                metric_ids.append(resolved)
            where.append(Condition(Column("metric_id"), Op.IN, metric_ids))

        return where
コード例 #13
0
ファイル: datasource.py プロジェクト: billyvg/sentry
def _get_metrics_filter_ids(metric_names: Sequence[str]) -> Set[int]:
    """
    Returns a set of metric_ids that map to input metric names and raises an exception if
    metric cannot be resolved in the indexer
    """
    if not metric_names:
        return set()
    metric_ids = set()
    for name in metric_names:
        if name not in DERIVED_METRICS:
            metric_ids.add(indexer.resolve(name))
        else:
            metric_ids |= DERIVED_METRICS[name].generate_metric_ids()
    if None in metric_ids:
        # We are looking for tags that appear in all given metrics.
        # A tag cannot appear in a metric if the metric is not even indexed.
        raise MetricDoesNotExistInIndexer()
    return metric_ids
コード例 #14
0
ファイル: metrics.py プロジェクト: littlekign/sentry
    def _resolve_web_vital_function(
        self,
        args: Mapping[str, Union[str, Column, SelectType, int, float]],
        alias: str,
    ) -> SelectType:
        column = args["column"]
        metric_id = args["metric_id"]
        quality = args["quality"].lower()

        if column not in [
                "measurements.lcp",
                "measurements.fcp",
                "measurements.fp",
                "measurements.fid",
                "measurements.cls",
        ]:
            raise InvalidSearchQuery(
                "count_web_vitals only supports measurements")

        measurement_rating = self.builder.resolve_column("measurement_rating")

        quality_id = indexer.resolve(quality)
        if quality_id is None:
            return Function(
                # This matches the type from doing `select toTypeName(count()) ...` from clickhouse
                "toUInt64",
                [0],
                alias,
            )

        return Function(
            "countIf",
            [
                Column("value"),
                Function(
                    "and",
                    [
                        Function("equals", [measurement_rating, quality_id]),
                        Function("equals", [Column("metric_id"), metric_id]),
                    ],
                ),
            ],
            alias,
        )
コード例 #15
0
ファイル: base.py プロジェクト: littlekign/sentry
def get_single_metric_info(projects: Sequence[Project],
                           metric_name: str) -> MetricMetaWithTagKeys:
    assert projects

    metric_id = indexer.resolve(metric_name)

    if metric_id is None:
        raise InvalidParams

    for metric_type in ("counter", "set", "distribution"):
        # TODO: What if metric_id exists for multiple types / units?
        entity_key = METRIC_TYPE_TO_ENTITY[metric_type]
        data = run_metrics_query(
            entity_key=entity_key,
            select=[Column("metric_id"),
                    Column("tags.key")],
            where=[Condition(Column("metric_id"), Op.EQ, metric_id)],
            groupby=[Column("metric_id"),
                     Column("tags.key")],
            referrer="snuba.metrics.meta.get_single_metric",
            projects=projects,
            org_id=projects[0].organization_id,
        )
        if data:
            tag_ids = {tag_id for row in data for tag_id in row["tags.key"]}
            return {
                "name":
                metric_name,
                "type":
                metric_type,
                "operations":
                AVAILABLE_OPERATIONS[entity_key.value],
                "tags":
                sorted(
                    ({
                        "key": reverse_resolve(tag_id)
                    } for tag_id in tag_ids),
                    key=itemgetter("key"),
                ),
                "unit":
                None,
            }

    raise InvalidParams(f"Raw metric {metric_name} does not exit")
コード例 #16
0
ファイル: metrics.py プロジェクト: saujanyanagpal104/sentry
    def _build_where(
        self, query_definition: QueryDefinition
    ) -> List[Union[BooleanCondition, Condition]]:
        where: List[Union[BooleanCondition, Condition]] = [
            Condition(Column("org_id"), Op.EQ, self._project.organization_id),
            Condition(Column("project_id"), Op.EQ, self._project.id),
            Condition(
                Column("metric_id"),
                Op.IN,
                [indexer.resolve(name) for _, name in query_definition.fields.values()],
            ),
            Condition(Column(TS_COL_QUERY), Op.GTE, query_definition.start),
            Condition(Column(TS_COL_QUERY), Op.LT, query_definition.end),
        ]
        filter_ = self._build_filter(query_definition)
        if filter_:
            where.append(filter_)

        return where
コード例 #17
0
ファイル: metrics.py プロジェクト: wangjianweiwei/sentry
    def get_tag_values(
        self, tag_name: str, metric_names: Optional[Sequence[str]]
    ) -> Sequence[TagValue]:
        """Get all known values for a specific tag"""
        tag_id = indexer.resolve(tag_name)
        if tag_id is None:
            raise InvalidParams

        where = self._get_metrics_filter(metric_names)
        if where is None:
            return []

        tags = defaultdict(list)

        column_name = f"tags[{tag_id}]"
        for metric_type in ("counter", "set", "distribution"):
            # TODO: What if metric_id exists for multiple types / units?
            entity_key = METRIC_TYPE_TO_ENTITY[metric_type]
            rows = self._get_data(
                entity_key=entity_key,
                select=[Column("metric_id"), Column(column_name)],
                where=where,
                groupby=[Column("metric_id"), Column(column_name)],
                referrer="snuba.metrics.meta.get_tag_values",
            )
            for row in rows:
                value_id = row[column_name]
                if value_id > 0:
                    metric_id = row["metric_id"]
                    tags[metric_id].append(value_id)

        value_id_lists = tags.values()
        if metric_names is not None:
            # Only return tags that occur in all metrics
            value_ids = set.intersection(*[set(ids) for ids in value_id_lists])
        else:
            value_ids = {value_id for ids in value_id_lists for value_id in ids}

        tags = [{"key": tag_name, "value": reverse_resolve(value_id)} for value_id in value_ids]
        tags.sort(key=itemgetter("key"))

        return tags
コード例 #18
0
ファイル: metrics.py プロジェクト: littlekign/sentry
    def _resolve_count_miserable_function(
        self,
        args: Mapping[str, Union[str, Column, SelectType, int, float]],
        alias: Optional[str] = None,
    ) -> SelectType:
        metric_true = indexer.resolve(constants.METRIC_TRUE_TAG_VALUE)

        # Nobody is miserable, we can return 0
        if metric_true is None:
            return Function(
                "toUInt64",
                [0],
                alias,
            )

        return Function(
            "uniqIf",
            [
                Column("value"),
                Function(
                    "and",
                    [
                        Function(
                            "equals",
                            [
                                Column("metric_id"),
                                args["metric_id"],
                            ],
                        ),
                        Function(
                            "equals",
                            [
                                self.builder.column(
                                    constants.METRIC_MISERABLE_TAG_KEY),
                                metric_true
                            ],
                        ),
                    ],
                ),
            ],
            alias,
        )
コード例 #19
0
ファイル: datasource.py プロジェクト: billyvg/sentry
def get_tag_values(
    projects: Sequence[Project], tag_name: str, metric_names: Optional[Sequence[str]]
) -> Sequence[TagValue]:
    """Get all known values for a specific tag"""
    assert projects

    tag_id = indexer.resolve(tag_name)
    if tag_id is None:
        raise InvalidParams(f"Tag {tag_name} is not available in the indexer")

    try:
        tags, _ = _fetch_tags_or_values_per_ids(
            projects=projects,
            column=f"tags[{tag_id}]",
            metric_names=metric_names,
            referrer="snuba.metrics.meta.get_tag_values",
        )
    except InvalidParams:
        return []
    return tags
コード例 #20
0
def _get_entity_of_metric_name(projects: Sequence[Project],
                               metric_name: str) -> EntityKey:
    assert projects

    metric_id = indexer.resolve(metric_name)

    if metric_id is None:
        raise InvalidParams

    for metric_type in ("counter", "set", "distribution"):
        entity_key = METRIC_TYPE_TO_ENTITY[metric_type]
        data = run_metrics_query(
            entity_key=entity_key,
            select=[Column("metric_id")],
            where=[Condition(Column("metric_id"), Op.EQ, metric_id)],
            groupby=[Column("metric_id")],
            referrer="snuba.metrics.meta.get_entity_of_metric",
            projects=projects,
            org_id=projects[0].organization_id,
        )
        if data:
            return entity_key

    raise InvalidParams(f"Raw metric {metric_name} does not exit")
コード例 #21
0
ファイル: metrics.py プロジェクト: KingDEV95/sentry
def tag_key(org_id: int, name: str) -> str:
    index = indexer.resolve(org_id, name)  # type: ignore
    if index is None:
        raise MetricIndexNotFound(name)
    return f"tags[{index}]"
コード例 #22
0
ファイル: metrics.py プロジェクト: KingDEV95/sentry
    def _get_release_adoption_impl(
        now: datetime,
        org_id: int,
        project_releases: Sequence[Tuple[ProjectId, ReleaseName]],
        project_ids: Sequence[ProjectId],
        environments: Optional[Sequence[EnvironmentName]] = None,
    ) -> ReleasesAdoption:
        start = now - timedelta(days=1)

        def _get_common_where(
                total: bool) -> List[Union[BooleanCondition, Condition]]:
            where_common: List[Union[BooleanCondition, Condition]] = [
                Condition(Column("org_id"), Op.EQ, org_id),
                Condition(Column("project_id"), Op.IN, project_ids),
                Condition(Column("timestamp"), Op.GTE, start),
                Condition(Column("timestamp"), Op.LT, now),
                Condition(Column(tag_key(org_id, "session.status")), Op.EQ,
                          tag_value(org_id, "init")),
            ]

            if environments is not None:
                environment_tag_values = []

                for environment in environments:
                    value = indexer.resolve(org_id,
                                            environment)  # type: ignore
                    if value is not None:
                        environment_tag_values.append(value)

                where_common.append(
                    Condition(Column(tag_key(org_id, "environment")), Op.IN,
                              environment_tag_values))

            if not total:
                release_tag_values = []

                for _, release in project_releases:
                    value = indexer.resolve(org_id, release)  # type: ignore
                    if value is not None:
                        # We should not append the value if it hasn't been
                        # observed before.
                        release_tag_values.append(value)

                where_common.append(
                    Condition(Column(tag_key(org_id, "release")), Op.IN,
                              release_tag_values))

            return where_common

        def _get_common_groupby(total: bool) -> List[SelectableExpression]:
            if total:
                return [Column("project_id")]
            else:
                return [
                    Column("project_id"),
                    Column(tag_key(org_id, "release"))
                ]

        def _convert_results(data: Any, total: bool) -> Dict[Any, int]:
            if total:
                return {x["project_id"]: x["value"] for x in data}
            else:
                release_tag = tag_key(org_id, "release")
                return {(x["project_id"], x[release_tag]): x["value"]
                        for x in data}

        def _count_sessions(total: bool, referrer: str) -> Dict[Any, int]:
            query = Query(
                dataset=Dataset.Metrics.value,
                match=Entity(EntityKey.MetricsCounters.value),
                select=[Column("value")],
                where=_get_common_where(total) + [
                    Condition(Column("metric_id"), Op.EQ,
                              metric_id(org_id, "session")),
                ],
                groupby=_get_common_groupby(total),
            )

            return _convert_results(
                raw_snql_query(
                    query,
                    referrer=referrer,
                    use_cache=False,
                )["data"],
                total=total,
            )

        def _count_users(total: bool, referrer: str) -> Dict[Any, int]:
            query = Query(
                dataset=Dataset.Metrics.value,
                match=Entity(EntityKey.MetricsSets.value),
                select=[Column("value")],
                where=_get_common_where(total) + [
                    Condition(Column("metric_id"), Op.EQ,
                              metric_id(org_id, "user")),
                ],
                groupby=_get_common_groupby(total),
            )

            return _convert_results(
                raw_snql_query(
                    query,
                    referrer=referrer,
                    use_cache=False,
                )["data"],
                total=total,
            )

        # XXX(markus): Four queries are quite horrible for this... the old code
        # sufficed with two. From what I understand, ClickHouse would have to
        # gain a function uniqCombined64MergeIf, i.e. a conditional variant of
        # what we already use.
        #
        # Alternatively we may want to use a threadpool here to send the
        # queries in parallel.

        # NOTE: referrers are spelled out as single static string literal so
        # S&S folks can search for it more easily. No string formatting
        # business please!

        # Count of sessions/users for given list of environments and timerange, per-project
        sessions_per_project: Dict[int, int] = _count_sessions(
            total=True,
            referrer=
            "release_health.metrics.get_release_adoption.total_sessions")
        users_per_project: Dict[int, int] = _count_users(
            total=True,
            referrer="release_health.metrics.get_release_adoption.total_users")

        # Count of sessions/users for given list of environments and timerange AND GIVEN RELEASES, per-project
        sessions_per_release: Dict[Tuple[int, int], int] = _count_sessions(
            total=False,
            referrer=
            "release_health.metrics.get_release_adoption.releases_sessions")
        users_per_release: Dict[Tuple[int, int], int] = _count_users(
            total=False,
            referrer=
            "release_health.metrics.get_release_adoption.releases_users")

        rv = {}

        for project_id, release in project_releases:
            release_tag_value = indexer.resolve(org_id,
                                                release)  # type: ignore
            if release_tag_value is None:
                # Don't emit empty releases -- for exact compatibility with
                # sessions table backend.
                continue

            release_sessions = sessions_per_release.get(
                (project_id, release_tag_value))
            release_users = users_per_release.get(
                (project_id, release_tag_value))

            total_sessions = sessions_per_project.get(project_id)
            total_users = users_per_project.get(project_id)

            adoption: ReleaseAdoption = {
                "adoption":
                float(release_users) / total_users *
                100 if release_users and total_users else None,
                "sessions_adoption":
                float(release_sessions) / total_sessions *
                100 if release_sessions and total_sessions else None,
                "users_24h":
                release_users,
                "sessions_24h":
                release_sessions,
                "project_users_24h":
                total_users,
                "project_sessions_24h":
                total_sessions,
            }

            rv[project_id, release] = adoption

        return rv
コード例 #23
0
ファイル: metrics.py プロジェクト: KingDEV95/sentry
 def to_int(string):
     try:
         return indexer.resolve(self._project.organization_id, string)
     except KeyError:
         return None
コード例 #24
0
def _fetch_data_for_field(
    org_id: int,
    query: QueryDefinition,
    raw_field: SessionsQueryFunction,
    limit_state: _LimitState,
    columns_fetched: Set[SelectableExpression],  # output param
) -> Tuple[_SnubaDataByMetric, MutableMapping[Tuple[
        MetricKey, _VirtualColumnName], _OutputField]]:
    tag_key_session_status = resolve_tag_key("session.status")

    data: _SnubaDataByMetric = []

    # Find the field that needs a specific column in a specific metric
    metric_to_output_field: MutableMapping[Tuple[MetricKey,
                                                 _VirtualColumnName],
                                           _OutputField] = {}

    group_by_status = "session.status" in query.raw_groupby

    # We limit the number of groups returned, but because session status
    # groups in the response are actually composed of multiple groups in storage,
    # we need to make sure we get them all. For this, use conditional aggregates:
    def get_column_for_status(function_name: str, prefix: str,
                              status: str) -> Function:
        return Function(
            f"{function_name}If",
            [
                Column("value"),
                Function(
                    "equals",
                    [Column(tag_key_session_status),
                     indexer.resolve(status)],
                ),
            ],
            alias=f"{prefix}_{status}",
        )

    if "count_unique(user)" == raw_field:
        metric_id = indexer.resolve(MetricKey.USER.value)
        if metric_id is not None:
            if group_by_status:
                data.extend(
                    _get_snuba_query_data(
                        org_id,
                        query,
                        EntityKey.MetricsSets,
                        MetricKey.USER,
                        metric_id,
                        [
                            # The order of these columns is important, because
                            # the first column might get used in order by
                            get_column_for_status("uniq", "users", "init"),
                            get_column_for_status("uniq", "users", "abnormal"),
                            get_column_for_status("uniq", "users", "crashed"),
                            get_column_for_status("uniq", "users", "errored"),
                        ],
                        limit_state,
                    ))
            else:
                data.extend(
                    _get_snuba_query_data(
                        org_id,
                        query,
                        EntityKey.MetricsSets,
                        MetricKey.USER,
                        metric_id,
                        [Function("uniq", [Column("value")], "value")],
                        limit_state,
                    ))
            metric_to_output_field[(MetricKey.USER, "value")] = _UserField()

    if raw_field in _DURATION_FIELDS:
        metric_id = indexer.resolve(MetricKey.SESSION_DURATION.value)
        if metric_id is not None:

            def get_virtual_column(
                    field: SessionsQueryFunction) -> _VirtualColumnName:
                return cast(_VirtualColumnName, field[:3])

            # Filter down
            # to healthy sessions, because that's what sessions_v2 exposes:
            healthy = indexer.resolve("exited")
            if healthy is None:
                # There are no healthy sessions, return
                return [], {}
            column_condition = Function(
                "equals", (Column(tag_key_session_status), healthy))

            snuba_column = _to_column(raw_field, column_condition)

            if snuba_column not in columns_fetched:
                data.extend(
                    _get_snuba_query_data(
                        org_id,
                        query,
                        EntityKey.MetricsDistributions,
                        MetricKey.SESSION_DURATION,
                        metric_id,
                        [snuba_column],
                        limit_state,
                    ))
                columns_fetched.add(snuba_column)

            col = get_virtual_column(raw_field)
            metric_to_output_field[(MetricKey.SESSION_DURATION,
                                    col)] = _SessionDurationField(
                                        raw_field, col, group_by_status)

    if "sum(session)" == raw_field:
        metric_id = indexer.resolve(MetricKey.SESSION.value)
        if metric_id is not None:
            if group_by_status:
                # We need session counters grouped by status, as well as the number of errored sessions

                # 1 session counters
                data.extend(
                    _get_snuba_query_data(
                        org_id,
                        query,
                        EntityKey.MetricsCounters,
                        MetricKey.SESSION,
                        metric_id,
                        [
                            # The order of these columns is important, because
                            # the first column might get used in order by
                            get_column_for_status("sum", "sessions", "init"),
                            get_column_for_status("sum", "sessions",
                                                  "abnormal"),
                            get_column_for_status("sum", "sessions",
                                                  "crashed"),
                            get_column_for_status("sum", "sessions",
                                                  "errored_preaggr"),
                        ],
                        limit_state,
                    ))

                # 2: session.error
                error_metric_id = indexer.resolve(
                    MetricKey.SESSION_ERROR.value)
                if error_metric_id is not None:
                    # Should not limit session.error to session.status=X,
                    # because that tag does not exist for this metric
                    limit_state.skip_columns.add(
                        Column(tag_key_session_status))
                    data.extend(
                        _get_snuba_query_data(
                            org_id,
                            query,
                            EntityKey.MetricsSets,
                            MetricKey.SESSION_ERROR,
                            error_metric_id,
                            [Function("uniq", [Column("value")], "value")],
                            limit_state,
                        ))
                    # Remove skip_column again:
                    limit_state.skip_columns.remove(
                        Column(tag_key_session_status))
            else:
                # Simply count the number of started sessions:
                init = indexer.resolve("init")
                if tag_key_session_status is not None and init is not None:
                    extra_conditions = [
                        Condition(Column(tag_key_session_status), Op.EQ, init)
                    ]
                    data.extend(
                        _get_snuba_query_data(
                            org_id,
                            query,
                            EntityKey.MetricsCounters,
                            MetricKey.SESSION,
                            metric_id,
                            [Function("sum", [Column("value")], "value")],
                            limit_state,
                            extra_conditions,
                        ))

            metric_to_output_field[(MetricKey.SESSION,
                                    "value")] = _SumSessionField()

    return data, metric_to_output_field
コード例 #25
0
ファイル: metrics.py プロジェクト: saujanyanagpal104/sentry
 def to_int(string):
     try:
         return indexer.resolve(string)
     except KeyError:
         return None
コード例 #26
0
ファイル: metrics.py プロジェクト: KingDEV95/sentry
def tag_value(org_id: int, name: str) -> int:
    index = indexer.resolve(org_id, name)  # type: ignore
    if index is None:
        raise MetricIndexNotFound(name)
    return index  # type: ignore
コード例 #27
0
 def to_int(string_type, string):
     try:
         return indexer.resolve(self._project.id, string_type, string)
     except KeyError:
         return None
コード例 #28
0
ファイル: datasource.py プロジェクト: littlekign/sentry
def get_tag_values(
        projects: Sequence[Project], tag_name: str,
        metric_names: Optional[Sequence[str]]) -> Sequence[TagValue]:
    """Get all known values for a specific tag"""
    assert projects

    tag_id = indexer.resolve(tag_name)
    if tag_id is None:
        raise InvalidParams

    try:
        metric_ids = _get_metrics_filter_ids(metric_names)
    except MetricDoesNotExistInIndexer:
        return []
    else:
        where = [Condition(Column("metric_id"), Op.IN, list(metric_ids))
                 ] if metric_ids else []

    tag_values = defaultdict(list)
    # This dictionary is required as a mapping from an entity to the ids available in it to
    # validate that constituent metrics of a SingleEntityDerivedMetric actually span a single
    # entity by validating that the ids of the constituent metrics all lie in the same entity
    supported_metric_ids_in_entities = {}

    column_name = f"tags[{tag_id}]"
    for metric_type in ("counter", "set", "distribution"):
        supported_metric_ids_in_entities.setdefault(metric_type, [])

        entity_key = METRIC_TYPE_TO_ENTITY[metric_type]
        rows = run_metrics_query(
            entity_key=entity_key,
            select=[Column("metric_id"),
                    Column(column_name)],
            where=where,
            groupby=[Column("metric_id"),
                     Column(column_name)],
            referrer="snuba.metrics.meta.get_tag_values",
            projects=projects,
            org_id=projects[0].organization_id,
        )
        for row in rows:
            value_id = row[column_name]
            supported_metric_ids_in_entities[metric_type].append(
                row["metric_id"])
            if value_id > 0:
                metric_id = row["metric_id"]
                tag_values[metric_id].append(value_id)

        # If we are trying to find the tag values for only one metric name, then no need to query
        # other entities once we find data for that metric_name in one of the entities
        if metric_names and len(metric_names) == 1 and rows:
            break

    value_id_lists = tag_values.values()
    if metric_names is not None:
        if metric_ids != set(tag_values.keys()):
            return []
        # At this point, we are sure that every metric_name/metric_id that was requested is
        # present in the dataset, and now we need to check that all derived metrics requested are
        # setup correctly
        _validate_requested_derived_metrics(
            metric_names=metric_names,
            supported_metric_ids_in_entities=supported_metric_ids_in_entities,
        )
        # Only return tags that occur in all metrics
        value_ids = set.intersection(*[set(ids) for ids in value_id_lists])
    else:
        value_ids = {value_id for ids in value_id_lists for value_id in ids}

    tags = [{
        "key": tag_name,
        "value": reverse_resolve(value_id)
    } for value_id in value_ids]
    tags.sort(key=lambda tag: (tag["key"], tag["value"]))

    return tags
コード例 #29
0
ファイル: metrics.py プロジェクト: KingDEV95/sentry
def try_get_string_index(org_id: int, name: str) -> Optional[int]:
    return indexer.resolve(org_id, name)  # type: ignore
コード例 #30
0
def _resolve(name: str) -> Optional[int]:
    """Wrapper for typing"""
    return indexer.resolve(name)  # type: ignore