1use crate::config::CobaltAllowlist;
6use fidl_fuchsia_metrics::{HistogramBucket, MetricEvent, MetricEventLoggerProxy};
7
8#[allow(unused)]
12macro_rules! log_cobalt {
13 ($cobalt_proxy:expr, $method_name:ident, $metric_id:expr, $value:expr, $event_codes:expr $(,)?) => {{
14 let status = $cobalt_proxy.$method_name($metric_id, $value, $event_codes).await;
15 match status {
16 Ok(Ok(())) => (),
17 Ok(Err(e)) => log::info!("Failed logging metric: {}, error: {:?}", $metric_id, e),
18 Err(e) => log::info!("Failed logging metric: {}, error: {}", $metric_id, e),
19 }
20 }};
21}
22
23macro_rules! log_cobalt_batch {
24 ($cobalt_proxy:expr, $events:expr, $context:expr $(,)?) => {{
25 if !$events.is_empty() {
26 let status = $cobalt_proxy.log_metric_events($events).await;
27 match status {
28 Ok(Ok(())) => (),
29 Ok(Err(e)) => {
30 log::info!(
31 "Failed logging batch metrics, context: {}, error: {:?}",
32 $context,
33 e
34 );
35 }
36 Err(e) => {
37 log::info!("Failed logging batch metrics, context: {}, error: {}", $context, e)
38 }
39 }
40 }
41 }};
42}
43
44#[allow(unused)]
46pub(crate) use {log_cobalt, log_cobalt_batch};
47pub struct FilteredCobaltLogger {
48 proxy: MetricEventLoggerProxy,
49 allowlist: CobaltAllowlist,
50}
51
52impl FilteredCobaltLogger {
53 pub fn new(proxy: MetricEventLoggerProxy, allowlist: CobaltAllowlist) -> Self {
54 Self { proxy, allowlist }
55 }
56
57 pub async fn log_occurrence(
58 &self,
59 metric_id: u32,
60 count: u64,
61 event_codes: &[u32],
62 ) -> Result<Result<(), fidl_fuchsia_metrics::Error>, fidl::Error> {
63 if !self.allowlist.contains(metric_id) {
64 return Ok(Ok(()));
65 }
66 self.proxy.log_occurrence(metric_id, count, event_codes).await
67 }
68
69 #[cfg_attr(not(test), expect(dead_code))]
70 pub async fn log_integer(
71 &self,
72 metric_id: u32,
73 value: i64,
74 event_codes: &[u32],
75 ) -> Result<Result<(), fidl_fuchsia_metrics::Error>, fidl::Error> {
76 if !self.allowlist.contains(metric_id) {
77 return Ok(Ok(()));
78 }
79 self.proxy.log_integer(metric_id, value, event_codes).await
80 }
81
82 #[expect(dead_code)]
83 pub async fn log_string(
84 &self,
85 metric_id: u32,
86 string_value: &str,
87 event_codes: &[u32],
88 ) -> Result<Result<(), fidl_fuchsia_metrics::Error>, fidl::Error> {
89 if !self.allowlist.contains(metric_id) {
90 return Ok(Ok(()));
91 }
92 self.proxy.log_string(metric_id, string_value, event_codes).await
93 }
94
95 #[expect(dead_code)]
96 pub async fn log_integer_histogram(
97 &self,
98 metric_id: u32,
99 histogram: &[HistogramBucket],
100 event_codes: &[u32],
101 ) -> Result<Result<(), fidl_fuchsia_metrics::Error>, fidl::Error> {
102 if !self.allowlist.contains(metric_id) {
103 return Ok(Ok(()));
104 }
105 self.proxy.log_integer_histogram(metric_id, histogram, event_codes).await
106 }
107
108 pub async fn log_metric_events(
109 &self,
110 events: &[MetricEvent],
111 ) -> Result<Result<(), fidl_fuchsia_metrics::Error>, fidl::Error> {
112 let filtered_events: Vec<MetricEvent> =
113 events.iter().filter(|e| self.allowlist.contains(e.metric_id)).cloned().collect();
114 if filtered_events.is_empty() {
115 return Ok(Ok(()));
116 }
117 self.proxy.log_metric_events(&filtered_events).await
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use crate::config::CobaltAllowlist;
124 use crate::testing::setup_test;
125 use fidl_fuchsia_metrics::{MetricEvent, MetricEventPayload};
126 use std::collections::HashSet;
127 use std::pin::pin;
128 use std::task::Poll;
129
130 #[fuchsia::test]
131 fn test_filtered_cobalt_logger_allow_all() {
132 let mut test_helper = setup_test();
133 let logger = test_helper.filtered_cobalt_logger();
134
135 let mut test_fut = pin!(async move {
136 logger.log_occurrence(100, 1, &[]).await.unwrap().unwrap();
137 logger.log_integer(101, 42, &[]).await.unwrap().unwrap();
138 });
139
140 assert_eq!(
141 test_helper.run_until_stalled_drain_cobalt_events(&mut test_fut),
142 Poll::Ready(())
143 );
144 assert_eq!(test_helper.cobalt_events.len(), 2);
145 }
146
147 #[fuchsia::test]
148 fn test_filtered_cobalt_logger_allowlist_only() {
149 let mut test_helper = setup_test();
150 let allowlist = CobaltAllowlist::Only(HashSet::from([1, 2]));
151 let logger = test_helper.filtered_cobalt_logger_with_allowlist(allowlist);
152
153 let mut test_fut = pin!(async move {
154 logger.log_occurrence(1, 1, &[]).await.unwrap().unwrap();
155 logger.log_occurrence(3, 1, &[]).await.unwrap().unwrap();
156 let events = vec![
157 MetricEvent {
158 metric_id: 2,
159 event_codes: vec![],
160 payload: MetricEventPayload::Count(1),
161 },
162 MetricEvent {
163 metric_id: 4,
164 event_codes: vec![],
165 payload: MetricEventPayload::Count(1),
166 },
167 ];
168 logger.log_metric_events(&events).await.unwrap().unwrap();
169 });
170
171 assert_eq!(
172 test_helper.run_until_stalled_drain_cobalt_events(&mut test_fut),
173 Poll::Ready(())
174 );
175 assert_eq!(test_helper.cobalt_events.len(), 2);
176 assert_eq!(test_helper.cobalt_events[0].metric_id, 1);
177 assert_eq!(test_helper.cobalt_events[1].metric_id, 2);
178 }
179}