blob: f08bad4dcdec72f2babd0f9af9f98204c494941d [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.
mod env_info;
mod ga_event;
pub mod metrics_event_batch;
mod metrics_service;
mod metrics_state;
mod notice;
use tracing;
use {
anyhow::{bail, Result},
std::collections::BTreeMap,
std::path::PathBuf,
};
use crate::env_info::{analytics_folder, is_analytics_disabled_by_env};
use crate::metrics_event_batch::MetricsEventBatch;
use crate::metrics_service::*;
use crate::metrics_state::{MetricsState, UNKNOWN_VERSION};
const INIT_ERROR: &str = "Please call analytics::init prior to any other analytics api calls.";
/// This function initializes the metrics service so that an app
/// can make posts to the analytics service and read the current opt in status of the user
pub async fn init_with_invoker(
app_name: String,
build_version: Option<String>,
ga_product_code: String,
invoker: Option<String>,
) {
METRICS_SERVICE.lock().await.inner_init(MetricsState::from_config(
&PathBuf::from(&analytics_folder()),
app_name,
build_version.unwrap_or(UNKNOWN_VERSION.into()),
ga_product_code,
is_analytics_disabled_by_env(),
invoker,
));
}
/// This function initializes the metrics service with a default of NONE for the invoker
pub async fn init(app_name: String, build_version: Option<String>, ga_product_code: String) {
init_with_invoker(app_name, build_version, ga_product_code, None).await;
}
/// Returns a legal notice of metrics data collection if user
/// is new to all tools (full notice) or new to this tool (brief notice).
/// Returns an error if init has not been called.
pub async fn get_notice() -> Option<String> {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => svc.inner_get_notice(),
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("get_notice called on uninitialized METRICS_SERVICE");
None
}
}
}
/// Records intended opt in status.
/// Returns an error if init has not been called.
pub async fn set_opt_in_status(enabled: bool) -> Result<()> {
let mut svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => svc.inner_set_opt_in_status(enabled),
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("set_optin_status called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
/// Returns current opt in status.
/// Returns an error if init has not been called.
pub async fn is_opted_in() -> bool {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => svc.inner_is_opted_in(),
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("is_opted_in called on uninitialized METRICS_SERVICE");
false
}
}
}
// disable analytics for this invocation only
// this does not affect the global analytics state
pub async fn opt_out_for_this_invocation() -> Result<()> {
let mut svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => svc.inner_opt_out_for_this_invocation(),
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("opt_out_for_this_incocation called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
/// Records a launch event with the command line args used to launch app.
/// Returns an error if init has not been called.
pub async fn add_launch_event(args: Option<&str>) -> Result<()> {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => svc.inner_add_launch_event(args, None).await,
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("add_launch_event called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
/// Records an error event in the app.
/// Returns an error if init has not been called.
pub async fn add_crash_event(description: &str, fatal: Option<&bool>) -> Result<()> {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => {
svc.inner_add_crash_event(description, fatal, None).await
}
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("add_crash_event called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
/// Records a timing event from the app.
/// Returns an error if init has not been called.
pub async fn add_timing_event(
category: Option<&str>,
time: String,
variable: Option<&str>,
label: Option<&str>,
custom_dimensions: BTreeMap<&str, String>,
) -> Result<()> {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => {
svc.inner_add_timing_event(category, time, variable, label, custom_dimensions, None)
.await
}
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("add_timing_event called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
/// Records an event with an option to specify every parameter.
/// Returns an error if init has not been called.
pub async fn add_custom_event(
category: Option<&str>,
action: Option<&str>,
label: Option<&str>,
custom_dimensions: BTreeMap<&str, String>,
) -> Result<()> {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => {
svc.inner_add_custom_event(category, action, label, custom_dimensions, None).await
}
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("add_custom_event called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
pub async fn make_batch() -> Result<MetricsEventBatch> {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => Ok(MetricsEventBatch::new()),
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("make_batch called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}
/// This is exposed for clients who want to use the uuid as a custom dimension
/// to do more accurate user counts in DataStudio analyses.
pub async fn uuid_as_str() -> Result<String> {
let svc = METRICS_SERVICE.lock().await;
match &svc.init_state {
MetricsServiceInitStatus::INITIALIZED => Ok(svc.uuid_as_str()),
MetricsServiceInitStatus::UNINITIALIZED => {
tracing::error!("uuid_as_str called on uninitialized METRICS_SERVICE");
bail!(INIT_ERROR)
}
}
}