Source code

Revision control

Copy as Markdown

Other Tools

// -*- mode: Rust -*-
// AUTOGENERATED BY glean_parser. DO NOT EDIT.
{# The rendered source is autogenerated, but this
Jinja2 template is not. Please file bugs! #}
/* 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/. */
/// This file contains factory implementation information for the
/// JOG Runtime Registration module.
/// It is responsible for being able to build metrics and pings described at runtime.
/// It is generated to keep it in sync with how the runtime definitions are defined.
use std::borrow::Cow;
use std::sync::atomic::{AtomicU32, Ordering};
use crate::private::{
CommonMetricData,
Lifetime,
MemoryUnit,
TimeUnit,
Ping,
LabeledMetric,
{% for metric_type_name in metric_types.keys() if not metric_type_name.startswith('labeled_') %}
{% if metric_type_name != "object" %}{# TODO(bug 1883857): Add JOG support #}
{{ metric_type_name|Camelize }}Metric,
{% endif %}
{% endfor %}};
use crate::private::traits::HistogramType;
pub(crate) static DYNAMIC_METRIC_BIT: u32 = {{runtime_metric_bit}};
// 2**DYNAMIC_METRIC_BIT + 1 (+1 because we reserve the 0 metric id)
static NEXT_METRIC_ID: AtomicU32 = AtomicU32::new({{2**runtime_metric_bit + 1}});
#[cfg(feature = "with_gecko")] // only used in submit_ping_by_id, which is gecko-only.
pub(crate) static DYNAMIC_PING_BIT: u32 = {{runtime_ping_bit}};
// 2**DYNAMIC_PING_BIT + 1 (+1 because we reserve the 0 ping id)
static NEXT_PING_ID: AtomicU32 = AtomicU32::new({{2**runtime_ping_bit + 1}});
pub(crate) mod __jog_metric_maps {
use crate::metrics::DynamicLabel;
use crate::private::MetricId;
use crate::private::{
Ping,
LabeledMetric,
NoExtraKeys,
{% for metric_type_name in metric_types.keys() %}
{{ metric_type_name|Camelize }}Metric,
{% endfor %}
};
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
{% for metric_type_name in metric_types.keys() if metric_type_name != "event" and not metric_type_name.startswith('labeled_') and metric_type_name != "object" %}
pub static {{ metric_type_name.upper() }}_MAP: Lazy<Arc<RwLock<HashMap<MetricId, {{ metric_type_name|Camelize }}Metric>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
{% endfor %}
{# Labeled metrics are special because they're LabeledMetric<Labeled{Counter|Boolean|...}Metric> #}
{% for metric_type_name in metric_types.keys() if metric_type_name.startswith('labeled_') %}
pub static {{ metric_type_name.upper() }}_MAP: Lazy<Arc<RwLock<HashMap<MetricId, LabeledMetric<{{ metric_type_name|Camelize }}Metric, DynamicLabel>>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
{% endfor %}
pub static PING_MAP: Lazy<Arc<RwLock<HashMap<u32, Ping>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
{# Event metrics are special because they're EventMetric<K> #}
pub static EVENT_MAP: Lazy<Arc<RwLock<HashMap<MetricId, EventMetric<NoExtraKeys>>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
{# Object metrics are special because they're ObjectMetric<K> #}
#[allow(dead_code)]
pub static OBJECT_MAP: Lazy<Arc<RwLock<HashMap<MetricId, ObjectMetric<()>>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
}
#[derive(Debug)]
struct MetricTypeNotFoundError(String);
impl std::error::Error for MetricTypeNotFoundError {}
impl std::fmt::Display for MetricTypeNotFoundError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Metric type {} not found", self.0)
}
}
/// Creates and registers a metric, returning its type+id.
pub fn create_and_register_metric(
metric_type: &str,
{# The rest of these are handrolled because it proved easier than maintaining a
map of argument name to argument type. I may regret this if I need it again. #}
{# In order of util.common_metric_args and util.extra_metric_args, because why not. #}
category: String,
name: String,
send_in_pings: Vec<String>,
lifetime: Lifetime,
disabled: bool,
time_unit: Option<TimeUnit>,
memory_unit: Option<MemoryUnit>,
allowed_extra_keys: Option<Vec<String>>,
{# Skipping reason_codes since that's a ping thing. #}
range_min: Option<u64>,
range_max: Option<u64>,
bucket_count: Option<u64>,
histogram_type: Option<HistogramType>,
numerators: Option<Vec<CommonMetricData>>,
{# And, don't forget the list of acceptable labels for a labeled metric. #}
labels: Option<Vec<Cow<'static, str>>>,
) -> Result<(u32, u32), Box<dyn std::error::Error>> {
let metric_id = NEXT_METRIC_ID.fetch_add(1, Ordering::SeqCst);
let metric32 = match metric_type {
{% for metric_type_name, metric_type in metric_types.items() %}
"{{ metric_type_name }}" => {
{% if metric_type_name == "object" %}{# TODO(bug 1883857): Add JOG support #}
return Err(Box::new(MetricTypeNotFoundError(metric_type.to_string())));
{% else %}
let metric = {{ metric_type_name|Camelize if not metric_type_name.startswith('labeled_') else "Labeled"}}Metric::{% if metric_type_name == 'event' %}with_runtime_extra_keys{% else %}new{% endif %}(metric_id.into(), CommonMetricData {
{% for arg_name in common_metric_data_args if arg_name in metric_type.args %}
{{ arg_name }},
{% endfor %}
..Default::default()
}
{%- for arg_name in metric_type.args if arg_name not in common_metric_data_args -%}
, {{ arg_name }}.unwrap()
{%- endfor -%}
{%- if metric_type_name.startswith('labeled_') -%}
, labels
{%- endif -%}
);
let metric32: u32 = ({{metric_type.id}} << {{ID_BITS}}) | metric_id;
assert!(
__jog_metric_maps::{{metric_type_name.upper()}}_MAP.write()?.insert(metric_id.into(), metric).is_none(),
"We should never insert a runtime metric with an already-used id."
);
metric32
{% endif %}
}
{% endfor %}
_ => return Err(Box::new(MetricTypeNotFoundError(metric_type.to_string())))
};
Ok((metric32, metric_id))
}
/// Creates and registers a ping, returning its id.
pub fn create_and_register_ping(
ping_name: String,
include_client_id: bool,
send_if_empty: bool,
precise_timestamps: bool,
include_info_sections: bool,
enabled: bool,
schedules_pings: Vec<String>,
reason_codes: Vec<String>,
) -> Result<u32, Box<dyn std::error::Error>> {
let ping_id = NEXT_PING_ID.fetch_add(1, Ordering::SeqCst);
let ping = Ping::new(ping_name, include_client_id, send_if_empty, precise_timestamps, include_info_sections, enabled, schedules_pings, reason_codes);
assert!(
__jog_metric_maps::PING_MAP.write()?.insert(ping_id.into(), ping).is_none(),
"We should never insert a runtime ping with an already-used id."
);
Ok(ping_id)
}