session_manager_lib/
cobalt.rs

1// Copyright 2019 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 anyhow::{format_err, Context, Error};
6use fidl_fuchsia_metrics::{MetricEventLoggerFactoryMarker, MetricEventLoggerProxy, ProjectSpec};
7use fuchsia_async as fasync;
8use fuchsia_component::client::connect_to_protocol;
9use log::warn;
10use session_framework_metrics_registry::cobalt_registry as metrics;
11
12/// Creates a `LoggerProxy` connected to Cobalt.
13///
14/// The connection is performed in a Future run on the global executor, but the `LoggerProxy`
15/// can be used immediately.
16///
17/// # Returns
18/// `LoggerProxy` for log messages to be sent to.
19pub fn get_logger() -> Result<MetricEventLoggerProxy, Error> {
20    let (logger_proxy, server_end) = fidl::endpoints::create_proxy();
21    let logger_factory = connect_to_protocol::<MetricEventLoggerFactoryMarker>()
22        .context("Failed to connect to the Cobalt MetricEventLoggerFactory")?;
23
24    fasync::Task::spawn(async move {
25        if let Err(err) = logger_factory
26            .create_metric_event_logger(
27                &ProjectSpec { project_id: Some(metrics::PROJECT_ID), ..Default::default() },
28                server_end,
29            )
30            .await
31        {
32            warn!(err:%; "Failed to create Cobalt logger");
33        }
34    })
35    .detach();
36
37    Ok(logger_proxy)
38}
39
40/// Reports the time elapsed while launching a session.
41///
42/// # Parameters
43/// - `logger_proxy`: The cobalt logger.
44/// - `start_time`: The time when `session_manager` starts launching a session.
45/// - `end_time`: The time when `session_manager` has bound to a session. This must be strictly after
46///   `start_time`.
47///
48/// # Returns
49/// `Ok` if the time elapsed was logged successfully.
50pub async fn log_session_launch_time(
51    logger_proxy: MetricEventLoggerProxy,
52    start_time: zx::MonotonicInstant,
53    end_time: zx::MonotonicInstant,
54) -> Result<(), Error> {
55    let elapsed_time = (end_time - start_time).into_micros();
56    if elapsed_time < 0 {
57        return Err(format_err!("End time must be after start time."));
58    }
59
60    logger_proxy
61        .log_integer(
62            metrics::SESSION_LAUNCH_TIME_MIGRATED_METRIC_ID,
63            elapsed_time,
64            &[metrics::SessionLaunchTimeMigratedMetricDimensionStatus::Success as u32],
65        )
66        .await
67        .context("Could not log session launch time.")?
68        .map_err(|e| format_err!("Logging session launch time returned an error: {:?}", e))?;
69
70    Ok(())
71}
72
73#[cfg(test)]
74#[allow(clippy::unwrap_used)]
75mod tests {
76    use super::*;
77    use assert_matches::assert_matches;
78    use fidl::endpoints::create_proxy_and_stream;
79    use fidl_fuchsia_metrics::{MetricEventLoggerMarker, MetricEventLoggerRequest};
80    use futures::TryStreamExt;
81
82    /// Tests that the right payload is sent to Cobalt when logging the session launch time.
83    #[fuchsia::test(allow_stalls = false)]
84    async fn test_log_session_launch_time() {
85        let (logger_proxy, mut logger_server) =
86            create_proxy_and_stream::<MetricEventLoggerMarker>();
87        let start_time = zx::MonotonicInstant::from_nanos(0);
88        let end_time = zx::MonotonicInstant::from_nanos(5000);
89
90        fasync::Task::spawn(async move {
91            let _ = log_session_launch_time(logger_proxy, start_time, end_time).await;
92        })
93        .detach();
94
95        assert_matches!(
96            logger_server.try_next().await.unwrap(),
97            Some(MetricEventLoggerRequest::LogInteger {
98                metric_id: metrics::SESSION_LAUNCH_TIME_MIGRATED_METRIC_ID,
99                value: 5,
100                event_codes,
101                responder: _,
102            }) => {
103                assert_eq!(
104                    event_codes,
105                    vec![metrics::SessionLaunchTimeMigratedMetricDimensionStatus::Success as u32]
106                );
107            }
108        )
109    }
110
111    /// Tests that an error is raised if end_time < start_time.
112    #[fuchsia::test(allow_stalls = false)]
113    async fn test_log_session_launch_time_swap_start_end_time() {
114        let (logger_proxy, _logger_server) = create_proxy_and_stream::<MetricEventLoggerMarker>();
115        let start_time = zx::MonotonicInstant::from_nanos(0);
116        let end_time = zx::MonotonicInstant::from_nanos(5000);
117
118        assert!(log_session_launch_time(logger_proxy, end_time, start_time).await.is_err());
119    }
120}