settings_common/inspect/
config_logger.rs

1// Copyright 2021 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.
4
5use crate::{clock, config};
6use fuchsia_inspect::{self as inspect, Node, NumericProperty, Property};
7use fuchsia_inspect_derive::Inspect;
8use settings_inspect_utils::managed_inspect_map::ManagedInspectMap;
9
10const CONFIG_INSPECT_NODE_NAME: &str = "config_loads";
11
12pub struct InspectConfigLogger {
13    /// The saved information about each load.
14    config_load_values: ManagedInspectMap<ConfigInspectInfo>,
15}
16
17/// Information about a config file load to be written to inspect.
18///
19/// Inspect nodes are not used, but need to be held as they're deleted from inspect once they go
20/// out of scope.
21#[derive(Default, Inspect)]
22struct ConfigInspectInfo {
23    /// Node of this info.
24    inspect_node: inspect::Node,
25
26    /// Nanoseconds since boot that this config was loaded.
27    timestamp: inspect::StringProperty,
28
29    /// Number of times the config was loaded.
30    count: inspect::UintProperty,
31
32    /// Debug string representation of the value of this config load info.
33    value: inspect::StringProperty,
34
35    /// Counts of different results for this config's load attempts.
36    result_counts: ManagedInspectMap<inspect::UintProperty>,
37}
38
39impl InspectConfigLogger {
40    /// Creates a new [InspectConfigLogger] that writes to the default
41    /// [fuchsia_inspect::component::inspector()].
42    pub fn new(node: &Node) -> Self {
43        let config_inspect_node = node.create_child(CONFIG_INSPECT_NODE_NAME);
44        Self {
45            config_load_values: ManagedInspectMap::<ConfigInspectInfo>::with_node(
46                config_inspect_node,
47            ),
48        }
49    }
50
51    pub fn write_config_load_to_inspect(
52        &mut self,
53        path: String,
54        config_load_info: config::ConfigLoadInfo,
55    ) {
56        let timestamp = clock::inspect_format_now();
57        let config::ConfigLoadInfo { status, contents } = config_load_info;
58        let status_clone = status.clone();
59
60        let config_inspect_info =
61            self.config_load_values.get_or_insert_with(path, ConfigInspectInfo::default);
62
63        config_inspect_info.timestamp.set(&timestamp);
64        config_inspect_info
65            .value
66            .set(&format!("{:#?}", config::ConfigLoadInfo { status, contents }));
67        let _ = config_inspect_info.count.add(1u64);
68        let _ = config_inspect_info
69            .result_counts
70            .get_or_insert_with(status_clone.into(), inspect::UintProperty::default)
71            .add(1u64);
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::config::ConfigLoadStatus;
79    use diagnostics_assertions::assert_data_tree;
80    use fuchsia_inspect::component;
81
82    #[fuchsia::test]
83    async fn test_listener_logger() {
84        // Set clock for consistent timestamps.
85        clock::mock::set(zx::MonotonicInstant::from_nanos(0));
86
87        let inspector = component::inspector();
88        let mut logger = InspectConfigLogger::new(inspector.root());
89
90        logger.write_config_load_to_inspect(
91            "test_path".to_string(),
92            config::ConfigLoadInfo {
93                status: ConfigLoadStatus::Success,
94                contents: Some("test".to_string()),
95            },
96        );
97
98        assert_data_tree!(inspector, root: {
99            config_loads: {
100                "test_path": {
101                    "count": 1u64,
102                    "result_counts": {
103                        "Success": 1u64,
104                    },
105                    "timestamp": "0.000000000",
106                    "value": "ConfigLoadInfo {\n    status: Success,\n    contents: Some(\n        \"test\",\n    ),\n}"
107                }
108            }
109        });
110    }
111
112    #[fuchsia::test]
113    async fn test_response_counts() {
114        // Set clock for consistent timestamps.
115        clock::mock::set(zx::MonotonicInstant::from_nanos(0));
116
117        let inspector = component::inspector();
118        let mut logger = InspectConfigLogger::new(inspector.root());
119
120        logger.write_config_load_to_inspect(
121            "test_path".to_string(),
122            config::ConfigLoadInfo {
123                status: ConfigLoadStatus::Success,
124                contents: Some("test".to_string()),
125            },
126        );
127        logger.write_config_load_to_inspect(
128            "test_path".to_string(),
129            config::ConfigLoadInfo {
130                status: ConfigLoadStatus::ParseFailure("Fake parse failure".to_string()),
131                contents: Some("test".to_string()),
132            },
133        );
134        logger.write_config_load_to_inspect(
135            "test_path".to_string(),
136            config::ConfigLoadInfo {
137                status: ConfigLoadStatus::ParseFailure("Fake parse failure".to_string()),
138                contents: Some("test".to_string()),
139            },
140        );
141        logger.write_config_load_to_inspect(
142            "test_path".to_string(),
143            config::ConfigLoadInfo {
144                status: ConfigLoadStatus::UsingDefaults("default".to_string()),
145                contents: Some("test".to_string()),
146            },
147        );
148
149        assert_data_tree!(inspector, root: {
150            config_loads: {
151                "test_path": {
152                    "count": 4u64,
153                    "result_counts": {
154                        "Success": 1u64,
155                        "ParseFailure": 2u64,
156                        "UsingDefaults": 1u64,
157                    },
158                    "timestamp": "0.000000000",
159                    "value": "ConfigLoadInfo {\n    status: UsingDefaults(\n        \"default\",\n    ),\n    contents: Some(\n        \"test\",\n    ),\n}"
160                }
161            }
162        });
163    }
164}