Skip to main content

detsys_ids_client/system_snapshot/
mod.rs

1use std::io::IsTerminal;
2
3use sysinfo::System;
4
5use crate::Map;
6
7mod generic;
8pub use generic::Generic;
9
10#[derive(Clone, Debug, serde::Serialize)]
11pub struct SystemSnapshot {
12    /// Example: `grahams-macbook-pro.local`
13    pub host_name: Option<String>,
14
15    /// Example: `macOS Version 14.4.1 (Build 23E224)`
16    #[serde(rename = "$os", skip_serializing_if = "Option::is_none")]
17    pub operating_system: Option<String>,
18
19    /// Example: `14.4.1`
20    #[serde(rename = "$os_version", skip_serializing_if = "Option::is_none")]
21    pub operating_system_version: Option<String>,
22
23    #[serde(rename = "$locale", skip_serializing_if = "Option::is_none")]
24    pub locale: Option<String>,
25
26    #[serde(rename = "$timezone", skip_serializing_if = "Option::is_none")]
27    pub timezone: Option<String>,
28
29    pub target_triple: String,
30    pub stdin_is_terminal: bool,
31    pub is_ci: bool,
32
33    /// Example: `14`
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub processor_count: Option<u64>,
36
37    /// Example: `38654705664`
38    pub physical_memory_bytes: u64,
39
40    /// Unix timestamp of the time the system booted. Example: `1713092739`
41    pub boot_time: u64,
42
43    /// Example: `determinate-nixd`
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub process_name: Option<String>,
46
47    /// Additional fields to be flattened into the snapshot data
48    #[serde(flatten)]
49    pub extra_fields: Option<Map>,
50}
51
52impl Default for SystemSnapshot {
53    fn default() -> Self {
54        let system = System::new_all();
55
56        let is_ci = is_ci::cached()
57            || std::env::var("DETSYS_IDS_IN_CI").unwrap_or_else(|_| "0".into()) == "1";
58
59        Self {
60            locale: sys_locale::get_locale(),
61            timezone: iana_time_zone::get_timezone().ok(),
62
63            host_name: System::host_name(),
64            operating_system: System::long_os_version(),
65            operating_system_version: System::os_version(),
66
67            target_triple: target_lexicon::HOST.to_string(),
68            stdin_is_terminal: std::io::stdin().is_terminal(),
69            is_ci,
70
71            processor_count: System::physical_core_count().map(
72                |count| count as u64, /* safety: `as` truncates on overflow */
73            ),
74            physical_memory_bytes: system.total_memory(),
75            boot_time: System::boot_time(),
76            process_name: std::env::args().next(),
77
78            extra_fields: None,
79        }
80    }
81}
82
83pub trait SystemSnapshotter: Send + Sync + 'static {
84    fn snapshot(&self) -> impl std::future::Future<Output = SystemSnapshot> + std::marker::Send;
85}