1use std::convert::TryFrom;
6
7use glean_core::{metrics::*, CommonMetricData, Lifetime};
8
9use crate::boolean::BOOLEAN_METRICS;
10use crate::counter::COUNTER_METRICS;
11use crate::string::STRING_METRICS;
12use crate::*;
13
14macro_rules! impl_labeled_metric {
31 ($metric:ty, $global:ident, $metric_global:ident, $new_name:ident, $destroy_name:ident, $get_name:ident, $test_get_num_recorded_errors:ident) => {
32 static $global: once_cell::sync::Lazy<ConcurrentHandleMap<LabeledMetric<$metric>>> =
33 once_cell::sync::Lazy::new(ConcurrentHandleMap::new);
34 $crate::define_infallible_handle_map_deleter!($global, $destroy_name);
35
36 #[no_mangle]
38 pub extern "C" fn $new_name(
39 category: FfiStr,
40 name: FfiStr,
41 send_in_pings: RawStringArray,
42 send_in_pings_len: i32,
43 lifetime: i32,
44 disabled: u8,
45 labels: RawStringArray,
46 label_count: i32,
47 ) -> u64 {
48 $global.insert_with_log(|| {
49 let name = name.to_string_fallible()?;
50 let category = category.to_string_fallible()?;
51 let send_in_pings = from_raw_string_array(send_in_pings, send_in_pings_len)?;
52 let labels = from_raw_string_array(labels, label_count)?;
53 let labels = if labels.is_empty() {
54 None
55 } else {
56 Some(labels)
57 };
58 let lifetime = Lifetime::try_from(lifetime)?;
59
60 Ok(LabeledMetric::new(
61 <$metric>::new(CommonMetricData {
62 name,
63 category,
64 send_in_pings,
65 lifetime,
66 disabled: disabled != 0,
67 ..Default::default()
68 }),
69 labels,
70 ))
71 })
72 }
73
74 #[no_mangle]
76 pub extern "C" fn $get_name(handle: u64, label: FfiStr) -> u64 {
77 static LABEL_MAP: once_cell::sync::Lazy<
80 std::sync::Mutex<std::collections::HashMap<String, u64>>,
81 > = once_cell::sync::Lazy::new(|| {
82 std::sync::Mutex::new(std::collections::HashMap::new())
83 });
84
85 let id = format!("{}/{}", handle, label.as_str());
88
89 let mut map = LABEL_MAP.lock().unwrap();
90
91 use std::collections::hash_map::Entry;
92 match map.entry(id) {
93 Entry::Occupied(entry) => {
94 *entry.get()
99 }
100 Entry::Vacant(entry) => {
101 let label_handle = $global.call_infallible_mut(handle, |labeled| {
102 let metric = labeled.get(label.as_str());
103 $metric_global.insert_with_log(|| Ok(metric))
104 });
105 entry.insert(label_handle);
106 label_handle
107 }
108 }
109 }
110
111 #[no_mangle]
112 pub extern "C" fn $test_get_num_recorded_errors(
113 metric_id: u64,
114 error_type: i32,
115 storage_name: FfiStr,
116 ) -> i32 {
117 crate::with_glean_value(|glean| {
118 crate::HandleMapExtension::call_infallible(&*$global, metric_id, |metric| {
119 let error_type = std::convert::TryFrom::try_from(error_type).unwrap();
120 let storage_name =
121 crate::FallibleToString::to_string_fallible(&storage_name).unwrap();
122 glean_core::test_get_num_recorded_errors(
123 glean,
124 &metric.get_submetric().meta(),
125 error_type,
126 Some(&storage_name),
127 )
128 .unwrap_or(0)
129 })
130 })
131 }
132 };
133}
134
135impl_labeled_metric!(
137 CounterMetric,
138 LABELED_COUNTER,
139 COUNTER_METRICS,
140 glean_new_labeled_counter_metric,
141 glean_destroy_labeled_counter_metric,
142 glean_labeled_counter_metric_get,
143 glean_labeled_counter_test_get_num_recorded_errors
144);
145
146impl_labeled_metric!(
148 BooleanMetric,
149 LABELED_BOOLEAN,
150 BOOLEAN_METRICS,
151 glean_new_labeled_boolean_metric,
152 glean_destroy_labeled_boolean_metric,
153 glean_labeled_boolean_metric_get,
154 glean_labeled_boolean_test_get_num_recorded_errors
155);
156
157impl_labeled_metric!(
159 StringMetric,
160 LABELED_STRING,
161 STRING_METRICS,
162 glean_new_labeled_string_metric,
163 glean_destroy_labeled_string_metric,
164 glean_labeled_string_metric_get,
165 glean_labeled_string_test_get_num_recorded_errors
166);