1pub mod components;
2
3pub mod filesystem;
4
5use crate::components::{cpu, kernel, memory, mount, network, os, uptime};
6use anyhow::Result;
7use rayon::prelude::*;
8use serde_json::{Map, Value};
9
10pub trait Collector: Send + Sync {
11 fn name(&self) -> &'static str;
12 fn collect(&self) -> Result<serde_json::Value>;
13}
14
15pub fn build() -> Result<Map<String, Value>> {
16 let components: Vec<Box<dyn Collector>> = vec![
19 Box::new(kernel::KernelComponent::new()),
20 Box::new(cpu::CPUComponent::new()),
21 Box::new(memory::MemoryComponent::new()),
22 Box::new(os::OSComponent::new()),
23 Box::new(uptime::UptimeComponent::new()),
24 Box::new(network::NetworkComponent::new()),
25 Box::new(mount::MountComponent::new()),
26 ];
27
28 let pairs: Vec<(String, Value)> = components
30 .par_iter()
31 .filter_map(|c| {
32 let name = c.name().to_string();
33 match c.collect() {
34 Ok(v) => Some((name, v)),
35 Err(e) => {
36 tracing::warn!(component = %name, error = ?e, "collector failed");
37 None
38 }
39 }
40 })
41 .collect();
42
43 let facts: Map<String, Value> = pairs.into_iter().collect();
45 Ok(facts)
46}
47
48pub fn display(facts: Map<String, Value>) -> Result<()> {
49 let _j = serde_json::to_string(&Value::Object(facts))?;
50 println!("{}", _j);
51 Ok(())
52}
53
54pub fn run() -> Result<()> {
55 let facts = build()?;
56 display(facts)?;
57 Ok(())
58}