capsula_capture_machine/
lib.rs1mod error;
2
3use crate::error::MachineHookError;
4use capsula_core::captured::Captured;
5use capsula_core::error::CapsulaResult;
6use capsula_core::hook::{Hook, PhaseMarker, RuntimeParams};
7use capsula_core::run::PreparedRun;
8use serde::{Deserialize, Serialize};
9use sysinfo::{CpuRefreshKind, MemoryRefreshKind, RefreshKind, System};
10use tracing::debug;
11
12#[derive(Debug, Clone, Deserialize, Serialize, Default)]
13pub struct MachineHookConfig {}
14
15#[derive(Debug, Default)]
16pub struct MachineHook {
17 config: MachineHookConfig,
18}
19
20#[derive(Debug, Serialize)]
21pub struct CpuInfo {
22 name: String,
23 vender_id: String,
24 brand: String,
25 frequency_mhz: u64,
26}
27
28#[derive(Debug, Serialize)]
29pub struct MachineCaptured {
30 os: String,
31 os_version: String,
32 kernel_version: String,
33 architecture: String,
34 cpus: Vec<CpuInfo>,
35 total_memory: u64,
36 hostname: String,
37}
38
39impl<P> Hook<P> for MachineHook
40where
41 P: PhaseMarker,
42{
43 const ID: &'static str = "capture-machine";
44
45 type Config = MachineHookConfig;
46 type Output = MachineCaptured;
47
48 fn from_config(
49 _config: &serde_json::Value,
50 _project_root: &std::path::Path,
51 ) -> CapsulaResult<Self> {
52 Ok(Self {
53 config: MachineHookConfig {},
54 })
55 }
56
57 fn config(&self) -> &Self::Config {
58 &self.config
59 }
60
61 fn run(
62 &self,
63 _metadata: &PreparedRun,
64 _params: &RuntimeParams<P>,
65 ) -> CapsulaResult<Self::Output> {
66 debug!("MachineHook: Gathering system information");
67 let os = System::name().ok_or(MachineHookError::OsInfoError)?;
68 let os_version = System::os_version().ok_or(MachineHookError::OsInfoError)?;
69 let kernel_version = System::kernel_version().ok_or(MachineHookError::OsInfoError)?;
70 let architecture = std::env::consts::ARCH.to_string();
71 debug!(
72 "MachineHook: OS: {} {}, Kernel: {}, Arch: {}",
73 os, os_version, kernel_version, architecture
74 );
75
76 debug!("MachineHook: Querying CPU and memory information");
77 let system = System::new_with_specifics(
78 RefreshKind::nothing()
79 .with_cpu(CpuRefreshKind::nothing().with_frequency())
80 .with_memory(MemoryRefreshKind::nothing().with_ram()),
81 );
82 let cpus = system
83 .cpus()
84 .iter()
85 .map(|cpu| CpuInfo {
86 name: cpu.name().to_string(),
87 vender_id: cpu.vendor_id().to_string(),
88 brand: cpu.brand().to_string(),
89 frequency_mhz: cpu.frequency(),
90 })
91 .collect::<Vec<_>>();
92
93 let total_memory = system.total_memory();
94 let hostname = System::host_name().ok_or(MachineHookError::HostnameError)?;
95 debug!(
96 "MachineHook: Found {} CPUs, {} bytes total memory, hostname: {}",
97 cpus.len(),
98 total_memory,
99 hostname
100 );
101
102 Ok(MachineCaptured {
103 os,
104 os_version,
105 kernel_version,
106 architecture,
107 cpus,
108 total_memory,
109 hostname,
110 })
111 }
112}
113
114impl Captured for MachineCaptured {
115 fn serialize_json(&self) -> Result<serde_json::Value, serde_json::Error> {
116 serde_json::to_value(self)
117 }
118}