Skip to main content

input_pipeline/metrics/
mod.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{Dispatcher, Incoming, Transport};
6use anyhow::{Context as _, Error};
7use cobalt_client::traits::AsEventCode;
8use derivative::Derivative;
9use fidl_next_fuchsia_metrics as metrics;
10use log::warn;
11use metrics_registry::*;
12
13/// Connects to the MetricEventLoggerFactory service to create a
14/// MetricEventLoggerProxy for the caller.
15fn create_metrics_logger(
16    incoming: &Incoming,
17) -> Result<fidl_next::Client<metrics::MetricEventLogger, Transport>, Error> {
18    let factory_proxy = incoming
19        .connect_protocol_next::<metrics::MetricEventLoggerFactory>()
20        .context("connecting to metrics")?;
21    let factory_proxy = factory_proxy.spawn();
22
23    let (cobalt_proxy, cobalt_server) =
24        fidl_next::fuchsia::create_channel::<metrics::MetricEventLogger>();
25    let cobalt_proxy = Dispatcher::client_from_zx_channel(cobalt_proxy).spawn();
26
27    let project_spec = metrics::ProjectSpec {
28        customer_id: None, // defaults to fuchsia
29        project_id: Some(PROJECT_ID),
30        ..Default::default()
31    };
32
33    Dispatcher::spawn_local(async move {
34        match factory_proxy.create_metric_event_logger(&project_spec, cobalt_server).await {
35            Err(e) => warn!("FIDL failure setting up event logger: {e:?}"),
36            Ok(Err(e)) => warn!("CreateMetricEventLogger failure: {e:?}"),
37            Ok(Ok(_)) => {}
38        }
39    })
40    .detach();
41
42    Ok(cobalt_proxy)
43}
44
45fn log_on_failure<T: std::fmt::Debug>(result: Result<Result<T, metrics::Error>, fidl_next::Error>) {
46    match result {
47        Ok(Ok(_)) => (),
48        e => warn!("failed to log metrics: {:?}", e),
49    };
50}
51
52/// A client connection to the Cobalt logging service.
53#[derive(Clone, Derivative, Default)]
54#[derivative(Debug)]
55pub struct MetricsLogger(
56    #[derivative(Debug = "ignore")]
57    Option<fidl_next::Client<metrics::MetricEventLogger, Transport>>,
58);
59
60impl MetricsLogger {
61    pub fn new(incoming: &Incoming) -> Self {
62        let logger = create_metrics_logger(incoming)
63            .map_err(|e| warn!("Failed to create metrics logger: {e}"))
64            .ok();
65        Self(logger)
66    }
67
68    /// Logs an warning occurrence metric using the Cobalt logger. Does not block execution.
69    pub fn log_warn<E: AsEventCode, S: Into<String>>(&self, event_code: E, message: S) {
70        log::warn!("{}", message.into());
71        self.send_metric(event_code);
72    }
73
74    /// Logs an error occurrence metric using the Cobalt logger. Does not block execution.
75    pub fn log_error<E: AsEventCode, S: Into<String>>(&self, event_code: E, message: S) {
76        log::error!("{}", message.into());
77        self.send_metric(event_code);
78    }
79
80    // send metric, does not block the execution.
81    fn send_metric<E: AsEventCode>(&self, event_code: E) {
82        let Some(c) = self.0.clone() else { return };
83        let code = event_code.as_event_code();
84        Dispatcher::spawn_local(async move {
85            log_on_failure(c.log_occurrence(INPUT_PIPELINE_ERROR_METRIC_ID, 1, &[code]).await);
86        })
87        .detach();
88    }
89}