blob: f1309d30cffab5dcbd78a9fea55236be04108dbb [file] [log] [blame]
// Copyright 2021 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::inspect::utils::inspect_map::InspectMap;
use std::sync::Arc;
use fuchsia_inspect::{self as inspect, component, NumericProperty, Property};
use fuchsia_inspect_derive::{Inspect, WithInspect};
use futures::lock::Mutex;
use lazy_static::lazy_static;
const STASH_INSPECT_NODE_NAME: &str = "stash_failures";
pub struct StashInspectLogger {
/// The inspector, stored for access in tests.
pub inspector: &'static inspect::Inspector,
/// The saved inspect node under which failure counts are written.
inspect_node: inspect::Node,
/// Map from a setting's device storage key to its inspect data.
flush_failure_counts: InspectMap<StashInspectInfo>,
}
/// Contains the node and property used to record the number of stash failures for a given
/// setting.
///
/// Inspect nodes are not used, but need to be held as they're deleted from inspect once they go
/// out of scope.
#[derive(Default, Inspect)]
struct StashInspectInfo {
/// Node of this info.
inspect_node: inspect::Node,
/// Number of write failures.
count: inspect::UintProperty,
}
impl StashInspectInfo {
fn new(node: &inspect::Node, key: &str) -> Self {
let info = Self::default()
.with_inspect(node, key)
.expect("Failed to create StashInspectInfo node");
info.count.set(1);
info
}
}
lazy_static! {
// TODO(fxb/93842): replace with a dependency injected value instead of a static.
pub(crate) static ref STASH_LOGGER: Arc<Mutex<StashInspectLogger>> =
Arc::new(Mutex::new(StashInspectLogger::new()));
}
impl StashInspectLogger {
fn new() -> Self {
let inspector = component::inspector();
let inspect_node = inspector.root().create_child(STASH_INSPECT_NODE_NAME);
Self { inspector, inspect_node, flush_failure_counts: InspectMap::new() }
}
/// Records a write failure for the given setting.
// TODO(fxb/97284): Change to take String.
pub fn record_flush_failure(&mut self, key: String) {
match self.flush_failure_counts.get_mut(&key) {
Some(stash_inspect_info) => {
stash_inspect_info.count.add(1u64);
}
None => {
let _ = self
.flush_failure_counts
.set(key.clone(), StashInspectInfo::new(&self.inspect_node, &key));
}
}
}
}
// Handle used to access the singleton logger.
pub struct StashInspectLoggerHandle {
pub logger: Arc<Mutex<StashInspectLogger>>,
}
impl StashInspectLoggerHandle {
pub fn new() -> Self {
Self { logger: Arc::clone(&STASH_LOGGER) }
}
}
impl Default for StashInspectLoggerHandle {
fn default() -> Self {
StashInspectLoggerHandle::new()
}
}