Skip to content

Commit 6f3e926

Browse files
Yashika KhuranaYashika Khurana
authored andcommitted
feat(nimbus): Nimbus feature monitoring configs in metric-hub
- Add FeatmonSpec, SourceTableSpec, FeatureSpec classes to parse TOML configs - Add SourceType enum (metrics, events_stream, clients_daily) - Add ratios field to FeatureSpec - Integrate featmon_configs into ConfigCollection.from_github_repo() - Add firefox_desktop.toml with data sources and features - Add featmon/ README and example config - Bump version to 2026.4.4
1 parent 566b2ed commit 6f3e926

2 files changed

Lines changed: 19 additions & 8 deletions

File tree

featmon/firefox_desktop.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Each data source specifies:
33
# - analysis_unit_id: field used to identify analysis units (client/profile IDs)
44
# - table_name: the BigQuery table name within the application dataset
5-
# - type: one of "metrics", "event_stream", or "clients_daily"
5+
# - type: one of "metrics", "events_stream", or "clients_daily"
66
# - dimensions: optional fields to group metrics by
77

88
[data_sources.metrics]
@@ -24,7 +24,7 @@ normalized_country_code = { value_in = ["CA", "DE", "FR", "GB", "US"], default_v
2424
[data_sources.events_stream]
2525
analysis_unit_id = "profile_group_id"
2626
table_name = "events_stream"
27-
type = "event_stream"
27+
type = "events_stream"
2828

2929
[data_sources.newtab]
3030
analysis_unit_id = "metrics.uuid.legacy_telemetry_profile_group_id"

lib/metric-config-parser/metric_config_parser/featmon.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
Each file defines:
77
- ``data_sources``: BigQuery tables to query, each with a ``type`` of
8-
``"metrics"``, ``"event_stream"``, or ``"clients_daily"``
8+
``"metrics"``, ``"events_stream"``, or ``"clients_daily"``
99
- ``features``: Nimbus features and the metrics to collect per source table
1010
1111
The ``dataset`` is derived from the filename stem (e.g. ``firefox_desktop.toml``
@@ -16,24 +16,32 @@
1616
"""
1717

1818
from collections.abc import Mapping
19+
from enum import StrEnum
1920
from pathlib import Path
2021
from typing import Any
2122

2223
import attr
2324
import toml
2425

25-
VALID_SOURCE_TYPES = frozenset({"metrics", "event_stream", "clients_daily"})
26-
2726
FEATMON_DIR = "featmon"
2827

2928

29+
class DataSourceType(StrEnum):
30+
"""Valid BigQuery source table types for featmon configs."""
31+
32+
METRICS = "metrics"
33+
EVENTS_STREAM = "events_stream"
34+
DEPRECATED_EVENT_STREAM = "event_stream" # deprecated alias, use events_stream
35+
CLIENTS_DAILY = "clients_daily"
36+
37+
3038
@attr.s(auto_attribs=True)
3139
class SourceTableSpec:
3240
"""Represents a single BigQuery data source in a featmon config."""
3341

3442
name: str
3543
table_name: str
36-
type: str = "metrics"
44+
type: str = DataSourceType.METRICS.value
3745
analysis_unit_id: str = "client_info.client_id"
3846
dimensions: dict[str, Any] = attr.Factory(dict)
3947

@@ -45,6 +53,7 @@ class FeatureSpec:
4553
name: str
4654
slug: str | None = None
4755
metrics_by_source: dict[str, Any] = attr.Factory(dict)
56+
ratios: list[list[str]] = attr.Factory(list)
4857

4958
def nimbus_slug(self) -> str:
5059
"""Return the Nimbus slug for this feature.
@@ -79,11 +88,12 @@ def __attrs_post_init__(self) -> None:
7988

8089
def _validate(self) -> None:
8190
"""Validate data source types."""
91+
valid = {t.value for t in DataSourceType}
8292
for name, source in self.data_sources.items():
83-
if source.type not in VALID_SOURCE_TYPES:
93+
if source.type not in valid:
8494
raise ValueError(
8595
f"data_source '{name}' has invalid type '{source.type}'. "
86-
f"Must be one of: {sorted(VALID_SOURCE_TYPES)}"
96+
f"Must be one of: {sorted(valid)}"
8797
)
8898

8999
@classmethod
@@ -98,6 +108,7 @@ def from_dict(cls, d: Mapping[str, Any], dataset: str) -> "FeatmonSpec":
98108
name=name,
99109
slug=cfg.get("slug"),
100110
metrics_by_source=cfg.get("metrics_by_source", {}),
111+
ratios=cfg.get("ratios", []),
101112
)
102113
for name, cfg in d.get("features", {}).items()
103114
}

0 commit comments

Comments
 (0)