Skip to content

Commit 50de83f

Browse files
authored
Update opmon generation to use statistic tables (#523)
1 parent defbe0c commit 50de83f

8 files changed

+172
-198
lines changed

generator/dashboards/operational_monitoring_dashboard.py

+7-12
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ class OperationalMonitoringDashboard(Dashboard):
1212

1313
type: str = "operational_monitoring_dashboard"
1414

15-
OPMON_DASH_EXCLUDED_FIELDS: List[str] = [
16-
"branch",
17-
"probe",
18-
"histogram__VALUES__key",
19-
"histogram__VALUES__value",
20-
]
21-
2215
def __init__(
2316
self,
2417
title: str,
@@ -101,16 +94,17 @@ def to_lookml(self, bq_client):
10194
series_colors = self._map_series_to_colours(
10295
table_defn["branches"], explore
10396
)
104-
for metric in table_defn.get("probes", []):
97+
for summary in table_defn.get("summaries", []):
10598
if self.compact_visualization:
106-
title = "Probe"
99+
title = "Metric"
107100
else:
108-
title = lookml_utils.slug_to_title(metric)
101+
title = lookml_utils.slug_to_title(summary["metric"])
109102

110103
kwargs["elements"].append(
111104
{
112105
"title": title,
113-
"metric": metric,
106+
"metric": summary["metric"],
107+
"statistic": summary["statistic"],
114108
"explore": explore,
115109
"series_colors": series_colors,
116110
"xaxis": self.xaxis,
@@ -124,7 +118,8 @@ def to_lookml(self, bq_client):
124118
kwargs["elements"].append(
125119
{
126120
"title": f"{title} - By {self.group_by_dimension}",
127-
"metric": metric,
121+
"metric": summary["metric"],
122+
"statistic": summary["statistic"],
128123
"explore": explore,
129124
"series_colors": series_colors,
130125
"xaxis": self.xaxis,

generator/dashboards/templates/dashboard.lkml

+48-30
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,53 @@
66
elements:
77
{% for element in elements -%}
88
- title: {{element.title}}
9-
name: {{element.title}}
9+
name: {{element.title}}_{{element.statistic}}
10+
note_state: expanded
11+
note_display: above
12+
note_text: {{element.statistic.title()}}
1013
explore: {{element.explore}}
14+
{% if element.statistic == "percentile" -%}
1115
type: "ci-line-chart"
16+
{% else -%}
17+
type: looker_line
18+
{% endif -%}
1219
fields: [
1320
{{element.explore}}.{{element.xaxis}},
1421
{{element.explore}}.branch,
15-
{{element.explore}}.high,
16-
{{element.explore}}.low,
17-
{{element.explore}}.percentile
22+
{% if element.statistic == "percentile" -%}
23+
{{element.explore}}.upper,
24+
{{element.explore}}.lower,
25+
{% endif -%}
26+
{{element.explore}}.point
1827
]
1928
pivots: [
2029
{{element.explore}}.branch
2130
{%- if group_by_dimension and element.title.endswith(group_by_dimension) %}, {{element.explore}}.{{group_by_dimension}} {% endif %}
2231
]
2332
{% if not compact_visualization -%}
2433
filters:
25-
{{element.explore}}.probe: {{element.metric}}
34+
{{element.explore}}.metric: {{element.metric}}
35+
{{element.explore}}.statistic: {{element.statistic}}
2636
{% endif -%}
2737
row: {{element.row}}
2838
col: {{element.col}}
2939
width: 12
3040
height: 8
3141
field_x: {{element.explore}}.{{element.xaxis}}
32-
field_y: {{element.explore}}.percentile
42+
field_y: {{element.explore}}.point
3343
log_scale: false
34-
ci_lower: {{element.explore}}.low
35-
ci_upper: {{element.explore}}.high
44+
ci_lower: {{element.explore}}.lower
45+
ci_upper: {{element.explore}}.upper
3646
show_grid: true
3747
listen:
38-
Percentile: {{element.explore}}.percentile_conf
48+
{%- if element.statistic == "percentile" %}
49+
Percentile: {{element.explore}}.parameter
50+
{%- endif %}
3951
{%- for dimension in dimensions %}
4052
{{dimension.title}}: {{element.explore}}.{{dimension.name}}
4153
{%- endfor %}
4254
{% if compact_visualization -%}
43-
Probe: {{element.explore}}.probe
55+
Metric: {{element.explore}}.metric
4456
{% endif -%}
4557
{%- for branch, color in element.series_colors.items() %}
4658
{{ branch }}: "{{ color }}"
@@ -54,7 +66,7 @@
5466
explore: {{alerts.explore}}
5567
type: looker_grid
5668
fields: [{{alerts.explore}}.submission_date,
57-
{{alerts.explore}}.probe, {{alerts.explore}}.percentile,
69+
{{alerts.explore}}.metric, {{alerts.explore}}.statistic, {{alerts.explore}}.percentile,
5870
{{alerts.explore}}.message, {{alerts.explore}}.branch, {{alerts.explore}}.errors]
5971
sorts: [{{alerts.explore}}.submission_date
6072
desc]
@@ -107,39 +119,45 @@
107119
filters:
108120
- name: Percentile
109121
title: Percentile
110-
type: number_filter
122+
type: field_filter
111123
default_value: '50'
112124
allow_multiple_values: false
113125
required: true
114126
ui_config:
115-
type: dropdown_menu
127+
type: slider
116128
display: inline
117-
options:
118-
- '10'
119-
- '20'
120-
- '30'
121-
- '40'
122-
- '50'
123-
- '60'
124-
- '70'
125-
- '80'
126-
- '90'
127-
- '95'
128-
- '99'
129+
options: []
130+
model: operational_monitoring
131+
explore: {{ elements[0].explore }}
132+
listens_to_filters: []
133+
field: {{ elements[0].explore }}.parameter
129134
{% if compact_visualization -%}
130-
- name: Probe
131-
title: Probe
135+
- name: Metric
136+
title: Metric
132137
type: field_filter
133138
default_value: '{{ elements[0].metric }}'
134-
allow_multiple_values: true
139+
allow_multiple_values: false
135140
required: true
136141
ui_config:
137142
type: dropdown_menu
138143
display: popover
139144
model: operational_monitoring
140145
explore: {{ elements[0].explore }}
141146
listens_to_filters: []
142-
field: {{ elements[0].explore }}.probe
147+
field: {{ elements[0].explore }}.metric
148+
- name: Statistic
149+
title: Statistic
150+
type: field_filter
151+
default_value: '{{ elements[0].statistic }}'
152+
allow_multiple_values: false
153+
required: true
154+
ui_config:
155+
type: dropdown_menu
156+
display: popover
157+
model: operational_monitoring
158+
explore: {{ elements[0].explore }}
159+
listens_to_filters: []
160+
field: {{ elements[0].explore }}.statistic
143161
{% endif -%}
144162

145163
{% for dimension in dimensions -%}
@@ -171,5 +189,5 @@
171189
{% for option in dimension.options | sort -%}
172190
- '{{option}}'
173191
{% endfor %}
174-
{% endif %}
192+
{% endif %}
175193
{% endfor -%}

generator/explores/operational_monitoring_explore.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def __init__(
2828
self.branches = ", ".join(defn["branches"])
2929
self.xaxis = defn.get("xaxis")
3030
self.dimensions = defn.get("dimensions", {})
31-
self.probes = defn.get("probes", [])
31+
self.summaries = defn.get("summaries", [])
3232

3333
@staticmethod
3434
def from_views(views: List[View]) -> Iterator[Explore]:
@@ -56,7 +56,6 @@ def _to_lookml(
5656

5757
filters = [
5858
{f"{base_view_name}.branch": self.branches},
59-
{f"{base_view_name}.percentile_conf": "50"},
6059
]
6160
for dimension, info in self.dimensions.items():
6261
if "default" in info:

generator/namespaces.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,11 @@ def _get_opmon(bq_client: bigquery.Client, namespaces: Dict[str, Any]):
100100
branches = project.get("branches", ["enabled", "disabled"])
101101

102102
# append view and explore for data type
103-
project_data_type_id = f"{table_prefix}"
104-
table = f"{PROD_PROJECT}.{OPMON_DATASET}.{table_prefix}"
103+
table = f"{PROD_PROJECT}.{OPMON_DATASET}.{table_prefix}_statistics"
105104
dimensions = operational_monitoring_utils.get_dimension_defaults(
106105
bq_client, table, project["dimensions"]
107106
)
108-
om_content["views"][project_data_type_id] = {
107+
om_content["views"][table_prefix] = {
109108
"type": "operational_monitoring_view",
110109
"tables": [
111110
{
@@ -115,13 +114,13 @@ def _get_opmon(bq_client: bigquery.Client, namespaces: Dict[str, Any]):
115114
}
116115
],
117116
}
118-
om_content["explores"][project_data_type_id] = {
117+
om_content["explores"][table_prefix] = {
119118
"type": "operational_monitoring_explore",
120119
"views": {"base_view": f"{table_prefix}"},
121120
"branches": branches,
122121
"xaxis": project["xaxis"],
123122
"dimensions": dimensions,
124-
"probes": [p["name"] for p in project["probes"]],
123+
"summaries": project["summaries"],
125124
}
126125

127126
if "alerting" in project and project["alerting"]:
@@ -145,15 +144,15 @@ def _get_opmon(bq_client: bigquery.Client, namespaces: Dict[str, Any]):
145144
"tables": [
146145
{
147146
"explore": f"{table_prefix}",
148-
"table": f"{PROD_PROJECT}.{OPMON_DATASET}.{table_prefix}",
147+
"table": f"{PROD_PROJECT}.{OPMON_DATASET}.{table_prefix}_statistics",
149148
"branches": branches,
150149
"xaxis": project["xaxis"],
151150
"compact_visualization": project.get(
152151
"compact_visualization", False
153152
),
154153
"dimensions": dimensions,
155154
"group_by_dimension": project.get("group_by_dimension", None),
156-
"probes": [p["name"] for p in project["probes"]],
155+
"summaries": project["summaries"],
157156
}
158157
],
159158
}

generator/views/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
ClientCountsView.type: ClientCountsView,
1515
EventsView.type: EventsView,
1616
FunnelAnalysisView.type: FunnelAnalysisView,
17+
OperationalMonitoringView.type: OperationalMonitoringView,
18+
OperationalMonitoringAlertingView.type: OperationalMonitoringAlertingView,
1719
GleanPingView.type: GleanPingView,
1820
PingView.type: PingView,
1921
GrowthAccountingView.type: GrowthAccountingView,
20-
OperationalMonitoringView.type: OperationalMonitoringView,
21-
OperationalMonitoringAlertingView.type: OperationalMonitoringAlertingView,
2222
TableView.type: TableView,
2323
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Class to describe an Operational Monitoring View."""
22
from __future__ import annotations
33

4-
from textwrap import dedent
54
from typing import Any, Dict, List, Optional
65

76
from . import lookml_utils
@@ -10,17 +9,19 @@
109

1110
ALLOWED_DIMENSIONS = {
1211
"branch",
13-
"probe",
14-
"value__VALUES__key",
15-
"value__VALUES__value",
12+
"metric",
13+
"statistic",
14+
"point",
15+
"parameter",
16+
"upper",
17+
"lower",
1618
}
1719

1820

1921
class OperationalMonitoringView(PingView):
2022
"""A view on a operational monitoring table."""
2123

2224
type: str = "operational_monitoring_view"
23-
percentile_ci_labels = ["percentile", "low", "high"]
2425

2526
def __init__(self, namespace: str, name: str, tables: List[Dict[str, Any]]):
2627
"""Create instance of a OperationalMonitoringView."""
@@ -40,34 +41,6 @@ def __init__(self, namespace: str, name: str, tables: List[Dict[str, Any]]):
4041
"sql": xaxis_to_sql_mapping[xaxis],
4142
}
4243
]
43-
self.parameters: List[Dict[str, str]] = [
44-
{
45-
"name": "percentile_conf",
46-
"type": "number",
47-
"label": "Percentile",
48-
"default_value": "50.0",
49-
}
50-
]
51-
52-
def _percentile_measure(self, percentile_ci_label) -> Dict[str, str]:
53-
return {
54-
"name": percentile_ci_label,
55-
"type": "number",
56-
"sql": dedent(
57-
f"""
58-
`moz-fx-data-shared-prod`.udf_js.jackknife_percentile_ci(
59-
{{% parameter percentile_conf %}},
60-
STRUCT(
61-
mozfun.hist.merge(
62-
ARRAY_AGG(
63-
${{TABLE}}.value IGNORE NULLS
64-
)
65-
).values AS values
66-
)
67-
).{percentile_ci_label}
68-
"""
69-
),
70-
}
7144

7245
@classmethod
7346
def from_dict(
@@ -98,11 +71,6 @@ def to_lookml(self, bq_client, v1_name: Optional[str]) -> Dict[str, Any]:
9871
"name": self.name,
9972
"sql_table_name": reference_table,
10073
"dimensions": self.dimensions,
101-
"parameters": self.parameters,
102-
"measures": [
103-
self._percentile_measure(label)
104-
for label in self.percentile_ci_labels
105-
],
10674
}
10775
]
10876
}

tests/test_namespaces.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ def result(self):
166166
"name": "OpMon",
167167
"branches": ["enabled", "disabled"],
168168
"xaxis": "submission_date",
169-
"probes": [
170-
{"name": "GC_MS", "agg_type": "histogram"},
171-
{"name": "GC_MS_CONTENT", "agg_type": "histogram"},
169+
"summaries": [
170+
{"metric": "GC_MS", "statistic": "mean"},
171+
{"metric": "GC_MS_CONTENT", "statistic": "percentile"},
172172
],
173173
"dimensions": {
174174
"cores_count": {"default": "4", "options": ["4", "1"]}
@@ -422,8 +422,14 @@ def test_namespaces_full(
422422
},
423423
"explore": "op_mon",
424424
"group_by_dimension": None,
425-
"probes": ["GC_MS", "GC_MS_CONTENT"],
426-
"table": "moz-fx-data-shared-prod.operational_monitoring.op_mon",
425+
"summaries": [
426+
{"metric": "GC_MS", "statistic": "mean"},
427+
{
428+
"metric": "GC_MS_CONTENT",
429+
"statistic": "percentile",
430+
},
431+
],
432+
"table": "moz-fx-data-shared-prod.operational_monitoring.op_mon_statistics",
427433
"xaxis": "submission_date",
428434
}
429435
],
@@ -437,7 +443,10 @@ def test_namespaces_full(
437443
"dimensions": {
438444
"cores_count": {"default": "4", "options": ["4", "1"]}
439445
},
440-
"probes": ["GC_MS", "GC_MS_CONTENT"],
446+
"summaries": [
447+
{"metric": "GC_MS", "statistic": "mean"},
448+
{"metric": "GC_MS_CONTENT", "statistic": "percentile"},
449+
],
441450
"type": "operational_monitoring_explore",
442451
"views": {"base_view": "op_mon"},
443452
"xaxis": "submission_date",
@@ -457,7 +466,7 @@ def test_namespaces_full(
457466
"options": ["4", "1"],
458467
}
459468
},
460-
"table": "moz-fx-data-shared-prod.operational_monitoring.op_mon",
469+
"table": "moz-fx-data-shared-prod.operational_monitoring.op_mon_statistics",
461470
"xaxis": "submission_date",
462471
}
463472
],

0 commit comments

Comments
 (0)