summaryrefslogtreecommitdiffstats
path: root/toolkit/components/glean/build_scripts/glean_parser_ext/templates/jog_factory.jinja2
blob: ef2088bec4aed86b3da1ce00297e66e437084f4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// -*- 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)
}