settings_common/inspect/
config_logger.rs1use 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 config_load_values: ManagedInspectMap<ConfigInspectInfo>,
15}
16
17#[derive(Default, Inspect)]
22struct ConfigInspectInfo {
23 inspect_node: inspect::Node,
25
26 timestamp: inspect::StringProperty,
28
29 count: inspect::UintProperty,
31
32 value: inspect::StringProperty,
34
35 result_counts: ManagedInspectMap<inspect::UintProperty>,
37}
38
39impl InspectConfigLogger {
40 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(×tamp);
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 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 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}