Browse Source

feat(metrics): Rename all metrics extracted by Relay (#30472)

As in getsentry/relay#1147, prefix all metric names with either
"sentry.sessions" or "sentry.transactions".
Joris Bayer 3 years ago
parent
commit
63fa2a1693

+ 19 - 19
src/sentry/relay/config.py

@@ -353,24 +353,24 @@ def _filter_option_to_config_setting(flt, setting):
 
 ALL_MEASUREMENT_METRICS = frozenset(
     [
-        "measurements.fp",
-        "measurements.fcp",
-        "measurements.lcp",
-        "measurements.fid",
-        "measurements.cls",
-        "measurements.ttfb",
-        "measurements.ttfb.requesttime",
-        "measurements.app_start_cold",
-        "measurements.app_start_warm",
-        "measurements.frames_total",
-        "measurements.frames_slow",
-        "measurements.frames_frozen",
-        "measurements.frames_slow_rate",
-        "measurements.frames_frozen_rate",
-        "measurements.stall_count",
-        "measurements.stall_total_time",
-        "measurements.stall_longest_time",
-        "measurements.stall_percentage",
+        "sentry.transactions.measurements.fp",
+        "sentry.transactions.measurements.fcp",
+        "sentry.transactions.measurements.lcp",
+        "sentry.transactions.measurements.fid",
+        "sentry.transactions.measurements.cls",
+        "sentry.transactions.measurements.ttfb",
+        "sentry.transactions.measurements.ttfb.requesttime",
+        "sentry.transactions.measurements.app_start_cold",
+        "sentry.transactions.measurements.app_start_warm",
+        "sentry.transactions.measurements.frames_total",
+        "sentry.transactions.measurements.frames_slow",
+        "sentry.transactions.measurements.frames_frozen",
+        "sentry.transactions.measurements.frames_slow_rate",
+        "sentry.transactions.measurements.frames_frozen_rate",
+        "sentry.transactions.measurements.stall_count",
+        "sentry.transactions.measurements.stall_total_time",
+        "sentry.transactions.measurements.stall_longest_time",
+        "sentry.transactions.measurements.stall_percentage",
     ]
 )
 
@@ -397,7 +397,7 @@ def get_transaction_metrics_settings(
                     assert breakdown_config["type"] == "spanOperations"
 
                     for op_name in breakdown_config["matches"]:
-                        metrics.append(f"breakdown.{breakdown_name}.{op_name}")
+                        metrics.append(f"sentry.transactions.breakdowns.{breakdown_name}.{op_name}")
             except Exception:
                 capture_exception()
 

+ 60 - 32
src/sentry/release_health/metrics.py

@@ -52,6 +52,7 @@ from sentry.release_health.base import (
 )
 from sentry.release_health.metrics_sessions_v2 import run_sessions_query
 from sentry.sentry_metrics import indexer
+from sentry.sentry_metrics.sessions import SessionMetricKey as MetricKey
 from sentry.snuba.dataset import Dataset, EntityKey
 from sentry.snuba.sessions import _make_stats, get_rollup_starts_and_buckets, parse_snuba_datetime
 from sentry.snuba.sessions_v2 import QueryDefinition
@@ -77,10 +78,10 @@ def get_tag_values_list(org_id: int, values: Sequence[str]) -> Sequence[int]:
     return [x for x in [try_get_string_index(org_id, x) for x in values] if x is not None]
 
 
-def metric_id(org_id: int, name: str) -> int:
-    index = indexer.resolve(name)  # type: ignore
+def metric_id(org_id: int, metric_key: MetricKey) -> int:
+    index = indexer.resolve(metric_key.value)  # type: ignore
     if index is None:
-        raise MetricIndexNotFound(name)
+        raise MetricIndexNotFound(metric_key.value)
     return index  # type: ignore
 
 
@@ -220,7 +221,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
             where=[
                 Condition(Column("org_id"), Op.EQ, org_id),
                 Condition(Column("project_id"), Op.IN, project_ids),
-                Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+                Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
                 Condition(Column("timestamp"), Op.GTE, start),
                 Condition(Column("timestamp"), Op.LT, end),
             ],
@@ -327,7 +328,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                 select=[Function("sum", [Column("value")], "value")],
                 where=_get_common_where(total)
                 + [
-                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
                 ],
                 groupby=_get_common_groupby(total),
             )
@@ -348,7 +349,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                 select=[Function("uniq", [Column("value")], "value")],
                 where=_get_common_where(total)
                 + [
-                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "user")),
+                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.USER)),
                 ],
                 groupby=_get_common_groupby(total),
             )
@@ -487,7 +488,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                 select=select,
                 where=where
                 + [
-                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
                     Condition(
                         Column(tag_key(org_id, "session.status")), Op.EQ, tag_value(org_id, "init")
                     ),
@@ -515,7 +516,9 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                 select=select,
                 where=where
                 + [
-                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session.duration")),
+                    Condition(
+                        Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION_DURATION)
+                    ),
                 ],
             )
             rows.extend(
@@ -581,7 +584,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         where_clause = [
             Condition(Column("org_id"), Op.EQ, org_id),
             Condition(Column("project_id"), Op.IN, project_ids),
-            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
             Condition(Column("timestamp"), Op.GTE, start),
             Condition(Column("timestamp"), Op.LT, now),
         ]
@@ -636,7 +639,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
     ) -> Set[ReleaseName]:
 
         try:
-            metric_id_session = metric_id(organization_id, "session")
+            metric_id_session = metric_id(organization_id, MetricKey.SESSION)
             release_column_name = tag_key(organization_id, "release")
         except MetricIndexNotFound:
             return set()
@@ -699,7 +702,9 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                 ],
                 where=where
                 + [
-                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session.duration")),
+                    Condition(
+                        Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION_DURATION)
+                    ),
                     Condition(
                         Column(tag_key(org_id, "session.status")),
                         Op.EQ,
@@ -745,7 +750,9 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                 select=aggregates + [Function("uniq", [Column("value")], "value")],
                 where=where
                 + [
-                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session.error")),
+                    Condition(
+                        Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION_ERROR)
+                    ),
                 ],
                 groupby=aggregates,
                 granularity=Granularity(rollup),
@@ -782,7 +789,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                 select=aggregates + [Function("sum", [Column("value")], "value")],
                 where=where
                 + [
-                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+                    Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
                     Condition(
                         Column(session_status_column_name),
                         Op.IN,
@@ -824,7 +831,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         # Avoid mutating input parameters here
         select = aggregates + [Function("uniq", [Column("value")], "value")]
         where = where + [
-            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "user")),
+            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.USER)),
             Condition(
                 Column(session_status_column_name),
                 Op.IN,
@@ -886,7 +893,9 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
             "sessions": Function("sum", [Column("value")], "value"),
         }[stat]
 
-        metric_name = metric_id(org_id, {"sessions": "session", "users": "user"}[stat])
+        metric_name = metric_id(
+            org_id, {"sessions": MetricKey.SESSION, "users": MetricKey.USER}[stat]
+        )
 
         for row in raw_snql_query(
             Query(
@@ -1097,10 +1106,10 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
             conditions.append(Condition(Column(environment_key), Op.IN, environment_values))
 
         def query_stats(end: datetime) -> CrashFreeBreakdown:
-            def _get_data(entity_key: EntityKey, metric_name: str) -> Tuple[int, int]:
+            def _get_data(entity_key: EntityKey, metric_key: MetricKey) -> Tuple[int, int]:
                 total = 0
                 crashed = 0
-                metric_id = try_get_string_index(org_id, metric_name)
+                metric_id = try_get_string_index(org_id, metric_key.value)
                 if metric_id is not None:
                     where = conditions + [
                         Condition(Column("metric_id"), Op.EQ, metric_id),
@@ -1133,8 +1142,10 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
 
                 return total, crashed
 
-            sessions_total, sessions_crashed = _get_data(EntityKey.MetricsCounters, "session")
-            users_total, users_crashed = _get_data(EntityKey.MetricsSets, "user")
+            sessions_total, sessions_crashed = _get_data(
+                EntityKey.MetricsCounters, MetricKey.SESSION
+            )
+            users_total, users_crashed = _get_data(EntityKey.MetricsSets, MetricKey.USER)
 
             return {
                 "date": end,
@@ -1209,7 +1220,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         where_clause = [
             Condition(Column("org_id"), Op.EQ, org_id),
             Condition(Column("project_id"), Op.IN, project_ids),
-            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
             Condition(Column("timestamp"), Op.GTE, start),
             Condition(Column("timestamp"), Op.LT, now),
         ]
@@ -1265,7 +1276,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         where_clause = [
             Condition(Column("org_id"), Op.EQ, org_id),
             Condition(Column("project_id"), Op.IN, project_ids),
-            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
             Condition(Column("timestamp"), Op.GTE, start),
             Condition(Column("timestamp"), Op.LT, now),
             Condition(Column(release_column_name), Op.IN, releases_ids),
@@ -1388,7 +1399,9 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                     where=where
                     + [
                         Condition(
-                            Column("metric_id"), Op.EQ, metric_id(org_id, "session.duration")
+                            Column("metric_id"),
+                            Op.EQ,
+                            metric_id(org_id, MetricKey.SESSION_DURATION),
                         ),
                         Condition(Column(session_status_key), Op.EQ, session_status_healthy),
                     ],
@@ -1428,7 +1441,8 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         session_series_data = raw_snql_query(
             Query(
                 dataset=Dataset.Metrics.value,
-                where=where + [Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session"))],
+                where=where
+                + [Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION))],
                 granularity=Granularity(rollup),
                 match=Entity(EntityKey.MetricsCounters.value),
                 select=[
@@ -1467,7 +1481,11 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
             Query(
                 dataset=Dataset.Metrics.value,
                 where=where
-                + [Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session.error"))],
+                + [
+                    Condition(
+                        Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION_ERROR)
+                    )
+                ],
                 granularity=Granularity(rollup),
                 match=Entity(EntityKey.MetricsSets.value),
                 select=[
@@ -1518,7 +1536,8 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         user_series_data = raw_snql_query(
             Query(
                 dataset=Dataset.Metrics.value,
-                where=where + [Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "user"))],
+                where=where
+                + [Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.USER))],
                 granularity=Granularity(rollup),
                 match=Entity(EntityKey.MetricsSets.value),
                 select=[
@@ -1531,7 +1550,8 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         user_totals_data = raw_snql_query(
             Query(
                 dataset=Dataset.Metrics.value,
-                where=where + [Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "user"))],
+                where=where
+                + [Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.USER))],
                 granularity=Granularity(rollup),
                 match=Entity(EntityKey.MetricsSets.value),
                 select=[
@@ -1711,7 +1731,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
         where_clause = [
             Condition(Column("org_id"), Op.EQ, org_id),
             Condition(Column("project_id"), Op.EQ, project_id),
-            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
             Condition(Column("timestamp"), Op.GTE, start),
             Condition(Column("timestamp"), Op.LT, end),
             Condition(Column(status_key), Op.EQ, status_init),
@@ -1768,7 +1788,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
 
         where_clause = [
             Condition(Column("org_id"), Op.EQ, org_id),
-            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")),
+            Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION)),
             Condition(Column("timestamp"), Op.GTE, start),
             Condition(Column("timestamp"), Op.LT, end),
             Condition(Column(status_key), Op.EQ, status_init),
@@ -1893,13 +1913,17 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                     direction=Direction.DESC,
                 )
             ]
-            where_clause.append(Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")))
+            where_clause.append(
+                Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION))
+            )
             entity = Entity(EntityKey.MetricsCounters.value)
         elif scope == "sessions":
             order_by_clause = [
                 OrderBy(exp=Function("sum", [Column("value")], "value"), direction=Direction.DESC)
             ]
-            where_clause.append(Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "session")))
+            where_clause.append(
+                Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.SESSION))
+            )
             entity = Entity(EntityKey.MetricsCounters.value)
         elif scope == "crash_free_users":
             order_by_clause = [
@@ -1931,13 +1955,17 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
                     direction=Direction.DESC,
                 )
             ]
-            where_clause.append(Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "user")))
+            where_clause.append(
+                Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.USER))
+            )
             entity = Entity(EntityKey.MetricsSets.value)
             having_clause = [Condition(Function("uniq", [Column("value")], "users"), Op.GT, 0)]
         else:  # users
             users_column = Function("uniq", [Column("value")], "users")
             order_by_clause = [OrderBy(exp=users_column, direction=Direction.DESC)]
-            where_clause.append(Condition(Column("metric_id"), Op.EQ, metric_id(org_id, "user")))
+            where_clause.append(
+                Condition(Column("metric_id"), Op.EQ, metric_id(org_id, MetricKey.USER))
+            )
             entity = Entity(EntityKey.MetricsSets.value)
             having_clause = [Condition(users_column, Op.GT, 0)]
 

+ 36 - 39
src/sentry/release_health/metrics_sessions_v2.py

@@ -36,6 +36,7 @@ from sentry.release_health.base import (
     SessionsQueryValue,
 )
 from sentry.sentry_metrics import indexer
+from sentry.sentry_metrics.sessions import SessionMetricKey as MetricKey
 from sentry.snuba.dataset import Dataset, EntityKey
 from sentry.snuba.metrics import TS_COL_GROUP, TS_COL_QUERY, get_intervals
 from sentry.snuba.sessions_v2 import QueryDefinition, finite_or_none
@@ -44,19 +45,19 @@ from sentry.utils.snuba import raw_snql_query
 #: Referrers for snuba queries
 #: Referrers must be searchable, so no string interpolation here
 REFERRERS = {
-    "user": {
+    MetricKey.USER: {
         "series": "release_health.metrics.sessions_v2.user.series",
         "totals": "release_health.metrics.sessions_v2.user.totals",
     },
-    "session.duration": {
+    MetricKey.SESSION_DURATION: {
         "series": "release_health.metrics.sessions_v2.session.duration.series",
         "totals": "release_health.metrics.sessions_v2.session.duration.totals",
     },
-    "session": {
+    MetricKey.SESSION: {
         "series": "release_health.metrics.sessions_v2.session.series",
         "totals": "release_health.metrics.sessions_v2.session.totals",
     },
-    "session.error": {
+    MetricKey.SESSION_ERROR: {
         "series": "release_health.metrics.sessions_v2.session.error.series",
         "totals": "release_health.metrics.sessions_v2.session.error.totals",
     },
@@ -103,8 +104,6 @@ class _SessionStatusValue:
     value: Union[None, float, int]
 
 
-_MetricName = Literal["session", "session.duration", "session.error", "user"]
-
 #: Actual column name in snuba
 _SnubaColumnName = Literal["value", "avg", "max", "percentiles"]
 
@@ -175,15 +174,15 @@ class _DataPointKey:
 
     would result in data keys
 
-        metric_name=session.duration, column=avg, bucketed_time=<datetime1>
-        metric_name=session.duration, column=max, bucketed_time=<datetime1>
-        metric_name=session.duration, column=avg, bucketed_time=<datetime2>
-        metric_name=session.duration, column=max, bucketed_time=<datetime2>
+        metric_key=MetricKey.SESSION_DURATION, column=avg, bucketed_time=<datetime1>
+        metric_key=MetricKey.SESSION_DURATION, column=max, bucketed_time=<datetime1>
+        metric_key=MetricKey.SESSION_DURATION, column=avg, bucketed_time=<datetime2>
+        metric_key=MetricKey.SESSION_DURATION, column=max, bucketed_time=<datetime2>
         ...
 
     """
 
-    metric_name: _MetricName
+    metric_key: MetricKey
     raw_session_status: Optional[str] = None
     release: Optional[int] = None
     environment: Optional[int] = None
@@ -194,7 +193,7 @@ class _DataPointKey:
 
 _DataPoints = MutableMapping[_DataPointKey, float]
 _SnubaData = Sequence[MutableMapping[str, Any]]
-_SnubaDataByMetric = Sequence[Tuple[_MetricName, _SnubaData]]
+_SnubaDataByMetric = Sequence[Tuple[MetricKey, _SnubaData]]
 
 
 class _OutputField(abc.ABC):
@@ -258,7 +257,7 @@ class _SumSessionField(_OutputField):
             started = int(data_points[key])
             abnormal = int(data_points.get(replace(key, raw_session_status="abnormal"), 0))
             crashed = int(data_points.get(replace(key, raw_session_status="crashed"), 0))
-            errored_key = replace(key, metric_name="session.error", raw_session_status=None)
+            errored_key = replace(key, metric_key=MetricKey.SESSION_ERROR, raw_session_status=None)
             individual_errors = int(data_points.get(errored_key, 0))
             aggregated_errors = int(
                 data_points.get(replace(key, raw_session_status="errored_preaggr"), 0)
@@ -362,12 +361,12 @@ def _get_snuba_query_data(
     org_id: int,
     query: QueryDefinition,
     entity_key: EntityKey,
-    metric_name: _MetricName,
+    metric_key: MetricKey,
     metric_id: int,
     columns: Sequence[SelectableExpression],
     extra_conditions: Optional[List[Condition]] = None,
     remove_groupby: Optional[Set[Column]] = None,
-) -> Generator[Tuple[_MetricName, _SnubaData], None, None]:
+) -> Generator[Tuple[MetricKey, _SnubaData], None, None]:
     """Get data from snuba"""
     if extra_conditions is None:
         extra_conditions = []
@@ -386,47 +385,45 @@ def _get_snuba_query_data(
             extra_conditions=extra_conditions,
             remove_groupby=remove_groupby,
         )
-        referrer = REFERRERS[metric_name][query_type]
+        referrer = REFERRERS[metric_key][query_type]
         query_data = raw_snql_query(snuba_query, referrer=referrer)["data"]
 
-        yield (metric_name, query_data)
+        yield (metric_key, query_data)
 
 
 def _fetch_data(
     org_id: int,
     query: QueryDefinition,
-) -> Tuple[_SnubaDataByMetric, Mapping[Tuple[_MetricName, _VirtualColumnName], _OutputField]]:
+) -> Tuple[_SnubaDataByMetric, Mapping[Tuple[MetricKey, _VirtualColumnName], _OutputField]]:
     """Build & run necessary snuba queries"""
 
     # It greatly simplifies code if we just assume that these two tags exist:
     # TODO: Can we get away with that assumption?
     tag_key_session_status = _resolve_ensured("session.status")
 
-    data: List[Tuple[_MetricName, _SnubaData]] = []
+    data: List[Tuple[MetricKey, _SnubaData]] = []
 
     #: Find the field that needs a specific column in a specific metric
-    metric_to_output_field: MutableMapping[
-        Tuple[_MetricName, _VirtualColumnName], _OutputField
-    ] = {}
+    metric_to_output_field: MutableMapping[Tuple[MetricKey, _VirtualColumnName], _OutputField] = {}
 
     if "count_unique(user)" in query.raw_fields:
-        metric_id = _resolve("user")
+        metric_id = _resolve(MetricKey.USER.value)
         if metric_id is not None:
             data.extend(
                 _get_snuba_query_data(
                     org_id,
                     query,
                     EntityKey.MetricsSets,
-                    "user",
+                    MetricKey.USER,
                     metric_id,
                     [Function("uniq", [Column("value")], "value")],
                 )
             )
-            metric_to_output_field[("user", "value")] = _UserField()
+            metric_to_output_field[(MetricKey.USER, "value")] = _UserField()
 
     duration_fields = [field for field in query.raw_fields if "session.duration" in field]
     if duration_fields:
-        metric_id = _resolve("session.duration")
+        metric_id = _resolve(MetricKey.SESSION_DURATION.value)
         if metric_id is not None:
 
             def get_virtual_column(field: SessionsQueryFunction) -> _VirtualColumnName:
@@ -455,7 +452,7 @@ def _fetch_data(
                         org_id,
                         query,
                         EntityKey.MetricsDistributions,
-                        "session.duration",
+                        MetricKey.SESSION_DURATION,
                         metric_id,
                         snuba_columns,
                         extra_conditions=extra_conditions,
@@ -465,12 +462,12 @@ def _fetch_data(
                 group_by_status = "session.status" in query.raw_groupby
                 for field in duration_fields:
                     col = get_virtual_column(field)
-                    metric_to_output_field[("session.duration", col)] = _SessionDurationField(
-                        field, col, group_by_status
-                    )
+                    metric_to_output_field[
+                        (MetricKey.SESSION_DURATION, col)
+                    ] = _SessionDurationField(field, col, group_by_status)
 
     if "sum(session)" in query.raw_fields:
-        metric_id = _resolve("session")
+        metric_id = _resolve(MetricKey.SESSION.value)
         if metric_id is not None:
             if "session.status" in query.raw_groupby:
                 # We need session counters grouped by status, as well as the number of errored sessions
@@ -481,14 +478,14 @@ def _fetch_data(
                         org_id,
                         query,
                         EntityKey.MetricsCounters,
-                        "session",
+                        MetricKey.SESSION,
                         metric_id,
                         [Function("sum", [Column("value")], "value")],
                     )
                 )
 
                 # 2: session.error
-                error_metric_id = _resolve("session.error")
+                error_metric_id = _resolve(MetricKey.SESSION_ERROR.value)
                 if error_metric_id is not None:
                     remove_groupby = {Column(f"tags[{tag_key_session_status}]")}
                     data.extend(
@@ -496,7 +493,7 @@ def _fetch_data(
                             org_id,
                             query,
                             EntityKey.MetricsSets,
-                            "session.error",
+                            MetricKey.SESSION_ERROR,
                             error_metric_id,
                             [Function("uniq", [Column("value")], "value")],
                             remove_groupby=remove_groupby,
@@ -514,14 +511,14 @@ def _fetch_data(
                             org_id,
                             query,
                             EntityKey.MetricsCounters,
-                            "session",
+                            MetricKey.SESSION,
                             metric_id,
                             [Function("sum", [Column("value")], "value")],
                             extra_conditions,
                         )
                     )
 
-            metric_to_output_field[("session", "value")] = _SumSessionField()
+            metric_to_output_field[(MetricKey.SESSION, "value")] = _SumSessionField()
 
     return data, metric_to_output_field
 
@@ -536,13 +533,13 @@ def _flatten_data(org_id: int, data: _SnubaDataByMetric) -> _DataPoints:
     tag_key_environment = _resolve_ensured("environment")
     tag_key_session_status = _resolve_ensured("session.status")
 
-    for metric_name, metric_data in data:
+    for metric_key, metric_data in data:
         for row in metric_data:
             raw_session_status = row.pop(f"tags[{tag_key_session_status}]", None)
             if raw_session_status is not None:
                 raw_session_status = _reverse_resolve_ensured(raw_session_status)
             flat_key = _DataPointKey(
-                metric_name=metric_name,
+                metric_key=metric_key,
                 raw_session_status=raw_session_status,
                 release=row.pop(f"tags[{tag_key_release}]", None),
                 environment=row.pop(f"tags[{tag_key_environment}]", None),
@@ -598,7 +595,7 @@ def run_sessions_query(
 
     for key in data_points.keys():
         try:
-            output_field = metric_to_output_field[key.metric_name, key.column]
+            output_field = metric_to_output_field[key.metric_key, key.column]
         except KeyError:
             continue  # secondary metric, like session.error
 

+ 6 - 4
src/sentry/sentry_metrics/indexer/mock.py

@@ -2,6 +2,8 @@ import itertools
 from collections import defaultdict
 from typing import DefaultDict, Dict, Optional
 
+from sentry.sentry_metrics.sessions import SessionMetricKey
+
 from .base import StringIndexer
 
 _STRINGS = (
@@ -11,13 +13,13 @@ _STRINGS = (
     "healthy",
     "production",
     "release",
-    "session.duration",
+    SessionMetricKey.SESSION_DURATION.value,
     "session.status",
-    "session",
+    SessionMetricKey.SESSION.value,
     "staging",
-    "user",
+    SessionMetricKey.USER.value,
     "init",
-    "session.error",
+    SessionMetricKey.SESSION_ERROR.value,
     "abnormal",
 )
 

+ 14 - 0
src/sentry/sentry_metrics/sessions.py

@@ -0,0 +1,14 @@
+""" Base module for sessions-related metrics """
+from enum import Enum
+
+
+class SessionMetricKey(Enum):
+    """Identifier for a session-related metric
+
+    Values are metric names as submitted by Relay.
+    """
+
+    SESSION = "sentry.sessions.session"
+    SESSION_DURATION = "sentry.sessions.session.duration"
+    SESSION_ERROR = "sentry.sessions.session.error"
+    USER = "sentry.sessions.user"

+ 6 - 5
src/sentry/snuba/metrics.py

@@ -32,6 +32,7 @@ from sentry.models import Project
 from sentry.relay.config import ALL_MEASUREMENT_METRICS
 from sentry.search.events.filter import QueryFilter
 from sentry.sentry_metrics import indexer
+from sentry.sentry_metrics.sessions import SessionMetricKey
 from sentry.snuba.dataset import Dataset, EntityKey
 from sentry.snuba.sessions_v2 import (  # TODO: unite metrics and sessions_v2
     ONE_DAY,
@@ -470,28 +471,28 @@ _MEASUREMENT_TAGS = dict(
 )
 
 _METRICS = {
-    "session": {
+    SessionMetricKey.SESSION.value: {
         "type": "counter",
         "operations": _AVAILABLE_OPERATIONS["metrics_counters"],
         "tags": _SESSION_TAGS,
     },
-    "user": {
+    SessionMetricKey.USER.value: {
         "type": "set",
         "operations": _AVAILABLE_OPERATIONS["metrics_sets"],
         "tags": _SESSION_TAGS,
     },
-    "session.duration": {
+    SessionMetricKey.SESSION_DURATION.value: {
         "type": "distribution",
         "operations": _AVAILABLE_OPERATIONS["metrics_distributions"],
         "tags": _SESSION_TAGS,
         "unit": "seconds",
     },
-    "session.error": {
+    SessionMetricKey.SESSION_ERROR.value: {
         "type": "set",
         "operations": _AVAILABLE_OPERATIONS["metrics_sets"],
         "tags": _SESSION_TAGS,
     },
-    "transaction.duration": {
+    "sentry.transactions.transaction.duration": {
         "type": "distribution",
         "operations": _AVAILABLE_OPERATIONS["metrics_distributions"],
         "tags": {

+ 25 - 12
src/sentry/testutils/cases.py

@@ -97,6 +97,7 @@ from sentry.notifications.types import NotificationSettingOptionValues, Notifica
 from sentry.plugins.base import plugins
 from sentry.rules import EventState
 from sentry.sentry_metrics import indexer
+from sentry.sentry_metrics.sessions import SessionMetricKey
 from sentry.tagstore.snuba import SnubaTagStorage
 from sentry.testutils.helpers.datetime import iso_format
 from sentry.testutils.helpers.slack import install_slack
@@ -985,29 +986,41 @@ class SessionMetricsTestCase(SnubaTestCase):
         # seq=0 is equivalent to relay's session.init, init=True is transformed
         # to seq=0 in Relay.
         if session["seq"] == 0:  # init
-            self._push_metric(session, "counter", "session", {"session.status": "init"}, +1)
+            self._push_metric(
+                session, "counter", SessionMetricKey.SESSION, {"session.status": "init"}, +1
+            )
             if not user_is_nil:
-                self._push_metric(session, "set", "user", {"session.status": "init"}, user)
+                self._push_metric(
+                    session, "set", SessionMetricKey.USER, {"session.status": "init"}, user
+                )
 
         status = session["status"]
 
         # Mark the session as errored, which includes fatal sessions.
         if session.get("errors", 0) > 0 or status not in ("ok", "exited"):
-            self._push_metric(session, "set", "session.error", {}, session["session_id"])
+            self._push_metric(
+                session, "set", SessionMetricKey.SESSION_ERROR, {}, session["session_id"]
+            )
             if not user_is_nil:
-                self._push_metric(session, "set", "user", {"session.status": "errored"}, user)
+                self._push_metric(
+                    session, "set", SessionMetricKey.USER, {"session.status": "errored"}, user
+                )
 
         if status in ("abnormal", "crashed"):  # fatal
-            self._push_metric(session, "counter", "session", {"session.status": status}, +1)
+            self._push_metric(
+                session, "counter", SessionMetricKey.SESSION, {"session.status": status}, +1
+            )
             if not user_is_nil:
-                self._push_metric(session, "set", "user", {"session.status": status}, user)
+                self._push_metric(
+                    session, "set", SessionMetricKey.USER, {"session.status": status}, user
+                )
 
         if status != "ok":  # terminal
             if session["duration"] is not None:
                 self._push_metric(
                     session,
                     "distribution",
-                    "session.duration",
+                    SessionMetricKey.SESSION_DURATION,
                     {"session.status": status},
                     session["duration"],
                 )
@@ -1017,10 +1030,10 @@ class SessionMetricsTestCase(SnubaTestCase):
             self.store_session(session)
 
     @classmethod
-    def _push_metric(cls, session, type, name, tags, value):
-        def metric_id(name):
-            res = indexer.record(name)
-            assert res is not None, name
+    def _push_metric(cls, session, type, key: SessionMetricKey, tags, value):
+        def metric_id(key: SessionMetricKey):
+            res = indexer.record(key.value)
+            assert res is not None, key
             return res
 
         def tag_key(name):
@@ -1052,7 +1065,7 @@ class SessionMetricsTestCase(SnubaTestCase):
         msg = {
             "org_id": session["org_id"],
             "project_id": session["project_id"],
-            "metric_id": metric_id(name),
+            "metric_id": metric_id(key),
             "timestamp": session["started"],
             "tags": {**base_tags, **extra_tags},
             "type": {"counter": "c", "set": "s", "distribution": "d"}[type],

+ 8 - 0
static/app/utils/discover/fields.tsx

@@ -4,6 +4,8 @@ import {RELEASE_ADOPTION_STAGES} from 'sentry/constants';
 import {Organization, SelectValue} from 'sentry/types';
 import {assert} from 'sentry/types/utils';
 
+import {METRIC_TO_COLUMN_TYPE} from '../metrics/fields';
+
 export type Sort = {
   kind: 'asc' | 'desc';
   field: string;
@@ -1051,14 +1053,20 @@ export function aggregateFunctionOutputType(
     }
   }
 
+  if (firstArg && METRIC_TO_COLUMN_TYPE.hasOwnProperty(firstArg)) {
+    return METRIC_TO_COLUMN_TYPE[firstArg];
+  }
+
   // If the function is an inherit type it will have a field as
   // the first parameter and we can use that to get the type.
   if (firstArg && FIELDS.hasOwnProperty(firstArg)) {
     return FIELDS[firstArg];
   }
+
   if (firstArg && isMeasurement(firstArg)) {
     return measurementType(firstArg);
   }
+
   if (firstArg && isSpanOperationBreakdownField(firstArg)) {
     return 'duration';
   }

+ 61 - 0
static/app/utils/metrics/fields.tsx

@@ -0,0 +1,61 @@
+import {ColumnType} from '../discover/fields';
+
+export enum SessionMetric {
+  SENTRY_SESSIONS_SESSION = 'sentry.sessions.session',
+  SENTRY_SESSIONS_SESSION_DURATION = 'sentry.sessions.session.duration',
+  SENTRY_SESSIONS_SESSION_ERROR = 'sentry.sessions.session.error',
+  SENTRY_SESSIONS_USER = 'sentry.sessions.user',
+}
+
+export enum TransactionMetric {
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FP = 'sentry.transactions.measurements.fp',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FCP = 'sentry.transactions.measurements.fcp',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_LCP = 'sentry.transactions.measurements.lcp',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FID = 'sentry.transactions.measurements.fid',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_CLS = 'sentry.transactions.measurements.cls',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_TTFB = 'sentry.transactions.measurements.ttfb',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_TTFB_REQUESTTIME = 'sentry.transactions.measurements.ttfb.requesttime',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_APP_START_COLD = 'sentry.transactions.measurements.app_start_cold',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_APP_START_WARM = 'sentry.transactions.measurements.app_start_warm',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_TOTAL = 'sentry.transactions.measurements.frames_total',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_SLOW = 'sentry.transactions.measurements.frames_slow',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_FROZEN = 'sentry.transactions.measurements.frames_frozen',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_SLOW_RATE = 'sentry.transactions.measurements.frames_slow_rate',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_FROZEN_RATE = 'sentry.transactions.measurements.frames_frozen_rate',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_COUNT = 'sentry.transactions.measurements.stall_count',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_TOTAL_TIME = 'sentry.transactions.measurements.stall_total_time',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_LONGEST_TIME = 'sentry.transactions.measurements.stall_longest_time',
+  SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_PERCENTAGE = 'sentry.transactions.measurements.stall_percentage',
+  SENTRY_TRANSACTIONS_TRANSACTION_DURATION = 'sentry.transactions.transaction.duration',
+}
+
+export const METRIC_TO_COLUMN_TYPE: Readonly<
+  Record<SessionMetric | TransactionMetric, ColumnType>
+> = {
+  // Session metrics
+  [SessionMetric.SENTRY_SESSIONS_USER]: 'integer',
+  [SessionMetric.SENTRY_SESSIONS_SESSION_ERROR]: 'integer',
+  [SessionMetric.SENTRY_SESSIONS_SESSION_DURATION]: 'duration',
+  [SessionMetric.SENTRY_SESSIONS_SESSION]: 'duration',
+
+  // Measurement metrics
+  [TransactionMetric.SENTRY_TRANSACTIONS_TRANSACTION_DURATION]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FP]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FCP]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_LCP]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FID]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_CLS]: 'number',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_TTFB]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_TTFB_REQUESTTIME]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_APP_START_COLD]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_APP_START_WARM]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_TOTAL]: 'integer',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_SLOW]: 'integer',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_FROZEN]: 'integer',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_SLOW_RATE]: 'percentage',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_FRAMES_FROZEN_RATE]: 'percentage',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_COUNT]: 'integer',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_TOTAL_TIME]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_LONGEST_TIME]: 'duration',
+  [TransactionMetric.SENTRY_TRANSACTIONS_MEASUREMENTS_STALL_PERCENTAGE]: 'percentage',
+};

+ 2 - 1
static/app/views/dashboardsV2/widget/metricWidget/statsRequest.tsx

@@ -16,6 +16,7 @@ import {
   SessionApiResponse,
 } from 'sentry/types';
 import {Series} from 'sentry/types/echarts';
+import {SessionMetric} from 'sentry/utils/metrics/fields';
 import {getSessionsInterval} from 'sentry/utils/sessions';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import {roundDuration} from 'sentry/views/releases/utils';
@@ -163,7 +164,7 @@ function StatsRequest({
         field,
         chartData: breakDownChartData,
         valueFormatter:
-          metricMeta.name === 'session.duration'
+          metricMeta.name === SessionMetric.SENTRY_SESSIONS_SESSION_DURATION
             ? duration => roundDuration(duration ? duration / 1000 : 0)
             : undefined,
       });

Some files were not shown because too many files changed in this diff