1use anyhow::{Context as _, Error};
6use log::warn;
7use {fidl_fuchsia_metrics as metrics, fuchsia_async as fasync};
8
9pub use bt_metrics_registry::*;
10
11pub fn create_metrics_logger() -> Result<metrics::MetricEventLoggerProxy, Error> {
14 let factory_proxy =
15 fuchsia_component::client::connect_to_protocol::<metrics::MetricEventLoggerFactoryMarker>()
16 .context("connecting to metrics")?;
17
18 let (cobalt_proxy, cobalt_server) =
19 fidl::endpoints::create_proxy::<metrics::MetricEventLoggerMarker>();
20
21 let project_spec = metrics::ProjectSpec {
22 customer_id: None, project_id: Some(PROJECT_ID),
24 ..Default::default()
25 };
26
27 fasync::Task::spawn(async move {
28 match factory_proxy.create_metric_event_logger(&project_spec, cobalt_server).await {
29 Err(e) => warn!("FIDL failure setting up event logger: {e:?}"),
30 Ok(Err(e)) => warn!("CreateMetricEventLogger failure: {e:?}"),
31 Ok(Ok(())) => {}
32 }
33 })
34 .detach();
35
36 Ok(cobalt_proxy)
37}
38
39pub fn log_on_failure(result: Result<Result<(), metrics::Error>, fidl::Error>) {
40 match result {
41 Ok(Ok(())) => (),
42 e => warn!("failed to log metrics: {:?}", e),
43 };
44}
45
46#[derive(Clone, Default)]
48pub struct MetricsLogger(Option<metrics::MetricEventLoggerProxy>);
49
50impl MetricsLogger {
51 pub fn new() -> Self {
52 let logger =
53 create_metrics_logger().map_err(|e| warn!("Failed to create metrics logger: {e}")).ok();
54 Self(logger)
55 }
56
57 pub fn from_proxy(proxy: metrics::MetricEventLoggerProxy) -> Self {
59 Self(Some(proxy))
60 }
61
62 pub fn log_occurrence(&self, id: u32, event_codes: Vec<u32>) {
64 let Some(c) = self.0.clone() else { return };
65 fuchsia_async::Task::spawn(async move {
66 log_on_failure(c.log_occurrence(id, 1, &event_codes).await);
67 })
68 .detach();
69 }
70
71 pub fn log_integer(&self, id: u32, value: i64, event_codes: Vec<u32>) {
73 let Some(c) = self.0.clone() else { return };
74 fuchsia_async::Task::spawn(async move {
75 log_on_failure(c.log_integer(id, value, &event_codes).await);
76 })
77 .detach();
78 }
79
80 pub fn log_occurrences<I: 'static + IntoIterator<Item = u32> + std::marker::Send>(
81 &self,
82 id: u32,
83 event_codes: I,
84 ) where
85 <I as IntoIterator>::IntoIter: std::marker::Send,
86 {
87 let Some(c) = self.0.clone() else { return };
88 fasync::Task::spawn(async move {
89 for code in event_codes {
90 log_on_failure(c.log_occurrence(id, 1, &[code]).await);
91 }
92 })
93 .detach();
94 }
95}
96
97pub fn respond_to_metrics_req_for_test(
99 request: metrics::MetricEventLoggerRequest,
100) -> metrics::MetricEvent {
101 match request {
102 metrics::MetricEventLoggerRequest::LogOccurrence {
103 metric_id,
104 count,
105 event_codes,
106 responder,
107 } => {
108 let _ = responder.send(Ok(())).unwrap();
109 metrics::MetricEvent {
110 metric_id,
111 event_codes,
112 payload: metrics::MetricEventPayload::Count(count),
113 }
114 }
115 metrics::MetricEventLoggerRequest::LogInteger {
116 metric_id,
117 value,
118 event_codes,
119 responder,
120 } => {
121 let _ = responder.send(Ok(())).unwrap();
122 metrics::MetricEvent {
123 metric_id,
124 event_codes,
125 payload: metrics::MetricEventPayload::IntegerValue(value),
126 }
127 }
128 _ => panic!("unexpected logging to Cobalt"),
129 }
130}