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.
45use 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;
1112/// 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> {
20let (logger_proxy, server_end) = fidl::endpoints::create_proxy();
21let logger_factory = connect_to_protocol::<MetricEventLoggerFactoryMarker>()
22 .context("Failed to connect to the Cobalt MetricEventLoggerFactory")?;
2324 fasync::Task::spawn(async move {
25if 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{
32warn!(err:%; "Failed to create Cobalt logger");
33 }
34 })
35 .detach();
3637Ok(logger_proxy)
38}
3940/// 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> {
55let elapsed_time = (end_time - start_time).into_micros();
56if elapsed_time < 0 {
57return Err(format_err!("End time must be after start time."));
58 }
5960 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))?;
6970Ok(())
71}
7273#[cfg(test)]
74#[allow(clippy::unwrap_used)]
75mod tests {
76use super::*;
77use assert_matches::assert_matches;
78use fidl::endpoints::create_proxy_and_stream;
79use fidl_fuchsia_metrics::{MetricEventLoggerMarker, MetricEventLoggerRequest};
80use futures::TryStreamExt;
8182/// Tests that the right payload is sent to Cobalt when logging the session launch time.
83#[fuchsia::test(allow_stalls = false)]
84async fn test_log_session_launch_time() {
85let (logger_proxy, mut logger_server) =
86 create_proxy_and_stream::<MetricEventLoggerMarker>();
87let start_time = zx::MonotonicInstant::from_nanos(0);
88let end_time = zx::MonotonicInstant::from_nanos(5000);
8990 fasync::Task::spawn(async move {
91let _ = log_session_launch_time(logger_proxy, start_time, end_time).await;
92 })
93 .detach();
9495assert_matches!(
96 logger_server.try_next().await.unwrap(),
97Some(MetricEventLoggerRequest::LogInteger {
98 metric_id: metrics::SESSION_LAUNCH_TIME_MIGRATED_METRIC_ID,
99 value: 5,
100 event_codes,
101 responder: _,
102 }) => {
103assert_eq!(
104 event_codes,
105vec![metrics::SessionLaunchTimeMigratedMetricDimensionStatus::Success as u32]
106 );
107 }
108 )
109 }
110111/// Tests that an error is raised if end_time < start_time.
112#[fuchsia::test(allow_stalls = false)]
113async fn test_log_session_launch_time_swap_start_end_time() {
114let (logger_proxy, _logger_server) = create_proxy_and_stream::<MetricEventLoggerMarker>();
115let start_time = zx::MonotonicInstant::from_nanos(0);
116let end_time = zx::MonotonicInstant::from_nanos(5000);
117118assert!(log_session_launch_time(logger_proxy, end_time, start_time).await.is_err());
119 }
120}