blob: ff54161101e757950f0ada37c1d1efabcc1fb293 [file] [log] [blame]
// Copyright 2020 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 crate::metrics_service::*;
use crate::INIT_ERROR;
use anyhow::{bail, Result};
use std::collections::BTreeMap;
const MAX_ENTRIES_EXCEEDED: &str = "There is a maximum of 20 events allowed in a batch.";
pub struct MetricsEventBatch {
events: Vec<String>,
}
impl MetricsEventBatch {
pub fn new() -> MetricsEventBatch {
MetricsEventBatch { events: vec![] }
}
pub async fn add_launch_event(&mut self, args: Option<&str>) -> Result<()> {
if self.full_batch() {
bail!(MAX_ENTRIES_EXCEEDED);
}
let svc = METRICS_SERVICE.lock().await;
svc.inner_add_custom_event(None, args, args, BTreeMap::new(), Some(self)).await
}
pub async fn add_custom_event(
&mut self,
category: Option<&str>,
action: Option<&str>,
label: Option<&str>,
custom_dimensions: BTreeMap<&str, String>,
) -> Result<()> {
if self.full_batch() {
bail!(MAX_ENTRIES_EXCEEDED);
}
let svc = METRICS_SERVICE.lock().await;
svc.inner_add_custom_event(category, action, label, custom_dimensions, Some(self)).await
}
pub async fn add_timing_event(
&mut self,
category: Option<&str>,
time: String,
variable: Option<&str>,
label: Option<&str>,
custom_dimensions: BTreeMap<&str, String>,
) -> Result<()> {
if self.full_batch() {
bail!(MAX_ENTRIES_EXCEEDED);
}
let svc = METRICS_SERVICE.lock().await;
svc.inner_add_timing_event(category, time, variable, label, custom_dimensions, Some(self))
.await
}
pub async fn add_crash_event(&mut self, description: &str, fatal: Option<&bool>) -> Result<()> {
if self.full_batch() {
bail!(MAX_ENTRIES_EXCEEDED);
}
let svc = METRICS_SERVICE.lock().await;
svc.inner_add_crash_event(description, fatal, Some(self)).await
}
pub async fn send_events(&self) -> Result<()> {
// TODO this guard is not necessary because the way it is constructed prevents the erroneous path
let svc = METRICS_SERVICE.lock().await;
match svc.init_state {
MetricsServiceInitStatus::INITIALIZED => {
svc.inner_send_events(self.event_strings_one_per_line(), true).await
}
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("send_events called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
pub(crate) fn add_event_string(&mut self, post_string: String) {
self.events.push(post_string);
}
fn full_batch(&self) -> bool {
self.events.len() == 20
}
fn event_strings_one_per_line(&self) -> String {
self.events.join("\n")
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_too_many_events(_r: Result<()>) -> Result<()> {
match _r {
Err(_e) => {
assert_eq!(MAX_ENTRIES_EXCEEDED, _e.to_string());
return Ok(());
}
Ok(()) => bail!("Should have bailed with MAX_ENTRIES_EXCEEDED error"),
}
}
#[fuchsia_async::run_singlethreaded(test)]
async fn add_timing_event_count_over_limit_bails() -> Result<()> {
let mut batch = MetricsEventBatch { events: vec!["_".to_string(); 20] };
let _r =
batch.add_timing_event(None, "1000".to_string(), None, None, BTreeMap::new()).await;
assert_too_many_events(_r)
}
#[fuchsia_async::run_singlethreaded(test)]
async fn add_crash_event_count_over_limit_bails() -> Result<()> {
let mut batch = MetricsEventBatch { events: vec!["_".to_string(); 20] };
let _r = batch.add_crash_event("Oops", None).await;
assert_too_many_events(_r)
}
#[fuchsia_async::run_singlethreaded(test)]
async fn add_launch_event_count_over_limit_bails() -> Result<()> {
let mut batch = MetricsEventBatch { events: vec!["_".to_string(); 20] };
let _r = batch.add_launch_event(Some("foo")).await;
assert_too_many_events(_r)
}
#[fuchsia_async::run_singlethreaded(test)]
async fn add_custom_event_count_over_limit_bails() -> Result<()> {
let mut batch = MetricsEventBatch { events: vec!["_".to_string(); 20] };
let _r = batch.add_custom_event(None, None, None, BTreeMap::new()).await;
assert_too_many_events(_r)
}
#[test]
fn add_event_string_adds_string() {
let mut batch = MetricsEventBatch { events: vec![] };
batch.add_event_string("string 1".to_string());
assert_eq!("string 1".to_string(), batch.event_strings_one_per_line());
}
#[test]
fn add_event_string_adds_both_strings() {
let mut batch = MetricsEventBatch { events: vec![] };
batch.add_event_string("string 1".to_string());
batch.add_event_string("string 2".to_string());
assert_eq!("string 1\nstring 2".to_string(), batch.event_strings_one_per_line());
}
}