Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions tools/generate-rust-dashboards/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub enum Metric {
LabeledCounter(LabeledCounterMetric),
Distribution(DistributionMetric),
LabeledDistribution(LabeledDistributionMetric),
Events(EventsMetric),
}

/// Glean counter
Expand Down Expand Up @@ -154,6 +155,22 @@ pub enum DistributionMetricKind {
Custom,
}

/// Track multiple Glean events together
///
/// This will create time-series panels with event counts for each event
pub struct EventsMetric {
/// Name to display on the dashboard
pub display_name: &'static str,
/// Name of the ping ("metrics" by default)
pub ping: &'static str,
/// Category name (top-level key in metrics.yaml)
pub category: &'static str,
/// Metric name (key for the metric)
pub metrics: Vec<&'static str>,
// Which applications report this metric
pub applications: Vec<Application>,
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Application {
Android,
Expand Down Expand Up @@ -263,3 +280,9 @@ impl From<LabeledDistributionMetric> for Metric {
Self::LabeledDistribution(m)
}
}

impl From<EventsMetric> for Metric {
fn from(m: EventsMetric) -> Self {
Self::Events(m)
}
}
87 changes: 87 additions & 0 deletions tools/generate-rust-dashboards/src/metrics/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use crate::{
config::{Application, EventsMetric, ReleaseChannel, TeamConfig},
schema::{
DashboardBuilder, Datasource, FieldConfig, FieldConfigCustom, FieldConfigDefaults, GridPos,
Panel, Target, TimeSeriesPanel, Transformation,
},
sql::{Query, Union},
Result,
};

pub fn add_to_dashboard(
builder: &mut DashboardBuilder,
_config: &TeamConfig,
metric: &EventsMetric,
) -> Result<()> {
builder.add_panel_title(metric.display_name);
for app in metric.applications.iter().cloned() {
builder.add_panel_third(count_panel(app, ReleaseChannel::Nightly, metric));
builder.add_panel_third(count_panel(app, ReleaseChannel::Beta, metric));
builder.add_panel_third(count_panel(app, ReleaseChannel::Release, metric));
}
Ok(())
}

fn count_panel(application: Application, channel: ReleaseChannel, metric: &EventsMetric) -> Panel {
let EventsMetric {
ping,
category,
metrics,
..
} = metric;

let mut query = Union::default();
for metric in metrics {
query.queries.push(Query {
select: vec![
"TIMESTAMP(submission_date) as time".into(),
format!("'{metric}' as label"),
"SUM(count) as count".into(),
],
from: format!("`mozdata.rust_components.{ping}_{category}_{metric}`"),
where_: vec![
"$__timeFilter(TIMESTAMP(submission_date))".into(),
format!("application = '{}'", application.slug()),
format!("channel = '{channel}'"),
],
group_by: Some("1, 2".into()),
..Query::default()
});
}
query.order_by = Some("submission_date asc".into());

TimeSeriesPanel {
title: application.display_name(channel),
grid_pos: GridPos::height(8),
datasource: Datasource::bigquery(),
interval: "1d".into(),
targets: vec![Target::table(query.sql())],
field_config: FieldConfig {
defaults: FieldConfigDefaults {
links: vec![],
custom: FieldConfigCustom {
axis_label: "count / day".into(),
..FieldConfigCustom::default()
},
unit: None,
},
},
transformations: vec![
Transformation::PartitionByValues {
fields: vec!["label".into()],
keep_fields: true,
},
// Fixup the field names for better legend labels
Transformation::RenameByRegex {
regex: "count (.*)".into(),
rename_pattern: "$1".into(),
},
],
..TimeSeriesPanel::default()
}
.into()
}
2 changes: 2 additions & 0 deletions tools/generate-rust-dashboards/src/metrics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

pub mod counter;
pub mod distribution;
pub mod event;
pub mod labeled_counter;
pub mod labeled_distribution;
pub mod rust_component_errors;
Expand All @@ -30,6 +31,7 @@ impl Metric {
Self::LabeledDistribution(metric) => {
labeled_distribution::add_to_dashboard(builder, config, metric)
}
Self::Events(metric) => event::add_to_dashboard(builder, config, metric),
}
}
}
23 changes: 23 additions & 0 deletions tools/generate-rust-dashboards/src/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,26 @@ impl Query {
);
}
}

/// Union query
///
/// Like `Query`, use this if it helps or use raw SQL if it's easier.
#[derive(Debug, Default)]
pub struct Union {
pub queries: Vec<Query>,
pub order_by: Option<String>,
}

impl Union {
pub fn sql(&self) -> String {
let mut sql = String::default();

for (i, q) in self.queries.iter().enumerate() {
if i != 0 {
sql.push_str("UNION ALL\n");
}
sql.push_str(&format!("{}\n", q.sql()));
}
sql
}
}
40 changes: 27 additions & 13 deletions tools/generate-rust-dashboards/src/team_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,33 @@ pub fn all_dashboards() -> Vec<TeamConfig> {
],
component_errors: true,
sync_metrics: true,
main_dashboard_metrics: vec![DistributionMetric {
kind: DistributionMetricKind::Timing,
display_name: "Places run_maintenance() time",
ping: "metrics",
category: "places_manager",
metric: "run_maintenance_time",
axis_label: "time",
unit: Some(Unit::Milliseconds),
value_divisor: Some(1_000_000),
applications: vec![Android],
link_to: Some("Sync Maintenance Times"),
}
.into()],
main_dashboard_metrics: vec![
DistributionMetric {
kind: DistributionMetricKind::Timing,
display_name: "Places run_maintenance() time",
ping: "metrics",
category: "places_manager",
metric: "run_maintenance_time",
axis_label: "time",
unit: Some(Unit::Milliseconds),
value_divisor: Some(1_000_000),
applications: vec![Android],
link_to: Some("Sync Maintenance Times"),
}
.into(),
EventsMetric {
display_name: "Logins key regeneration",
ping: "metrics",
category: "logins_store",
metrics: vec![
"key_regenerated_lost",
"key_regenerated_corrupt",
"key_regenerated_other",
],
applications: vec![Android],
}
.into(),
],
extra_dashboards: vec![ExtraDashboard {
name: "Sync Maintenance Times",
metrics: vec![
Expand Down