blob: f5f1c1c3ccfbd5d8a4b8ebb73ee271587ca25d3d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::Error;
#[cfg(test)]
use fidl_fuchsia_cobalt::CobaltEvent;
use fuchsia_cobalt::{CobaltConnector, CobaltSender, ConnectionType};
use futures::prelude::*;
use log::info;
use omaha_client::metrics::{Metrics, MetricsReporter};
/// A MetricsReporter trait implementation that send metrics to Cobalt.
pub struct CobaltMetricsReporter {
cobalt_sender: CobaltSender,
}
impl CobaltMetricsReporter {
pub fn new() -> (Self, impl Future<Output = ()>) {
let (cobalt_sender, fut) = CobaltConnector::default()
.serve(ConnectionType::project_id(mos_metrics_registry::PROJECT_ID));
(CobaltMetricsReporter { cobalt_sender }, fut)
}
#[cfg(test)]
fn new_mock() -> (Self, futures::channel::mpsc::Receiver<CobaltEvent>) {
let (sender, receiver) = futures::channel::mpsc::channel(1);
let cobalt_sender = CobaltSender::new(sender);
(CobaltMetricsReporter { cobalt_sender }, receiver)
}
}
impl MetricsReporter for CobaltMetricsReporter {
fn report_metrics(&mut self, metrics: Metrics) -> Result<(), Error> {
info!("Reporting metrics to Cobalt: {:?}", metrics);
match metrics {
Metrics::UpdateCheckResponseTime(duration) => {
self.cobalt_sender.log_elapsed_time(
mos_metrics_registry::UPDATE_CHECK_RESPONSE_TIME_METRIC_ID,
mos_metrics_registry::UpdateCheckResponseTimeMetricDimensionResult::Success
as u32,
duration.as_micros() as i64,
);
}
Metrics::UpdateCheckInterval(duration) => {
self.cobalt_sender.log_elapsed_time(
mos_metrics_registry::UPDATE_CHECK_INTERVAL_METRIC_ID,
mos_metrics_registry::UpdateCheckIntervalMetricDimensionResult::Success as u32,
duration.as_micros() as i64,
);
}
Metrics::SuccessfulUpdateDuration(duration) => {
self.cobalt_sender.log_elapsed_time(
mos_metrics_registry::UPDATE_DURATION_METRIC_ID,
mos_metrics_registry::UpdateDurationMetricDimensionResult::Success as u32,
duration.as_micros() as i64,
);
}
Metrics::FailedUpdateDuration(duration) => {
self.cobalt_sender.log_elapsed_time(
mos_metrics_registry::UPDATE_DURATION_METRIC_ID,
mos_metrics_registry::UpdateDurationMetricDimensionResult::Failed as u32,
duration.as_micros() as i64,
);
}
Metrics::SuccessfulUpdateFromFirstSeen(duration) => {
self.cobalt_sender.log_elapsed_time(
mos_metrics_registry::UPDATE_DURATION_FROM_FIRST_SEEN_METRIC_ID,
mos_metrics_registry::UpdateDurationFromFirstSeenMetricDimensionResult::Success
as u32,
duration.as_micros() as i64,
);
}
Metrics::UpdateCheckFailureReason(reason) => {
self.cobalt_sender
.log_event(mos_metrics_registry::UPDATE_CHECK_FAILURE_METRIC_ID, reason as u32);
}
Metrics::UpdateCheckRetries(count) => {
self.cobalt_sender.log_event_count(
mos_metrics_registry::UPDATE_CHECK_RETRIES_METRIC_ID,
mos_metrics_registry::UpdateCheckRetriesMetricDimensionResult::Success as u32,
0,
count as i64,
);
}
Metrics::AttemptsToSucceed(count) => {
self.cobalt_sender.log_event_count(
mos_metrics_registry::ATTEMPTS_TO_SUCCEED_METRIC_ID,
mos_metrics_registry::AttemptsToSucceedMetricDimensionResult::Success as u32,
0,
count as i64,
);
}
Metrics::WaitedForRebootDuration(duration) => {
self.cobalt_sender.log_elapsed_time(
mos_metrics_registry::WAITED_FOR_REBOOT_DURATION_METRIC_ID,
mos_metrics_registry::WaitedForRebootDurationMetricDimensionResult::Success
as u32,
duration.as_micros() as i64,
);
}
Metrics::FailedBootAttempts(count) => {
self.cobalt_sender.log_event_count(
mos_metrics_registry::FAILED_BOOT_ATTEMPTS_METRIC_ID,
mos_metrics_registry::FailedBootAttemptsMetricDimensionResult::Success as u32,
0,
count as i64,
);
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use fidl_fuchsia_cobalt::{CountEvent, EventPayload};
use omaha_client::metrics::UpdateCheckFailureReason;
use std::time::Duration;
#[test]
fn test_report_update_check_response_time() {
let (mut reporter, mut receiver) = CobaltMetricsReporter::new_mock();
reporter
.report_metrics(Metrics::UpdateCheckResponseTime(Duration::from_millis(10)))
.unwrap();
assert_eq!(
receiver.try_next().unwrap().unwrap(),
CobaltEvent {
metric_id: mos_metrics_registry::UPDATE_CHECK_RESPONSE_TIME_METRIC_ID,
event_codes: vec![
mos_metrics_registry::UpdateCheckResponseTimeMetricDimensionResult::Success
as u32
],
component: None,
payload: EventPayload::ElapsedMicros(10 * 1000),
}
);
}
#[test]
fn test_report_update_check_failure_reason() {
let (mut reporter, mut receiver) = CobaltMetricsReporter::new_mock();
reporter
.report_metrics(Metrics::UpdateCheckFailureReason(
UpdateCheckFailureReason::Configuration,
))
.unwrap();
assert_eq!(
receiver.try_next().unwrap().unwrap(),
CobaltEvent {
metric_id: mos_metrics_registry::UPDATE_CHECK_FAILURE_METRIC_ID,
event_codes: vec![
mos_metrics_registry::UpdateCheckFailureMetricDimensionReason::Configuration
as u32
],
component: None,
payload: EventPayload::Event(fidl_fuchsia_cobalt::Event),
}
);
}
#[test]
fn test_report_update_check_retries() {
let (mut reporter, mut receiver) = CobaltMetricsReporter::new_mock();
reporter.report_metrics(Metrics::UpdateCheckRetries(3)).unwrap();
assert_eq!(
receiver.try_next().unwrap().unwrap(),
CobaltEvent {
metric_id: mos_metrics_registry::UPDATE_CHECK_RETRIES_METRIC_ID,
event_codes: vec![
mos_metrics_registry::UpdateCheckRetriesMetricDimensionResult::Success as u32
],
component: None,
payload: EventPayload::EventCount(CountEvent {
period_duration_micros: 0,
count: 3
}),
}
);
}
}