sysmonk/resources/
stream.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use std::collections::HashMap;
use sysinfo::{CpuRefreshKind, Disks, RefreshKind, System};

use crate::{resources, squire};
use serde_json;

/// Function to get disk statistics.
///
/// # Returns
///
/// A `Value` object with total and used disk space.
pub fn get_disk_stats() -> serde_json::Value {
    let disks = Disks::new_with_refreshed_list();
    let disks_total = resources::info::get_disk_usage(&disks);
    let mut disk_available: Vec<u64> = [].to_vec();
    for disk in disks.list() {
        disk_available.push(disk.available_space());
    }
    let disks_available: u64 = disk_available.iter().sum();
    serde_json::json!({
        "total": disks_total,
        "used": disks_total - disks_available,
    })
}

/// Function to get docker stats via commandline.
///
/// # Returns
///
/// A `Result` containing a `Vec` of `serde_json::Value` if successful, otherwise an empty `Vec`.
fn get_docker_stats() -> Result<Vec<serde_json::Value>, Box<dyn std::error::Error>> {
    // Check if there are any docker containers running
    // `docker -a` will show all containers including stopped, which will block `docker stats`
    let ps_result = squire::util::run_command("docker", &["ps", "-q"], false);
    let stats_result = match ps_result {
        Ok(output) if !output.is_empty() => {
            let stats_result = squire::util::run_command(
                "docker",
                &["stats", "--no-stream", "--format", "{{json .}}"],
                false,
            );
            match stats_result {
                Ok(stats) => stats,
                Err(err) => {
                    log::error!("Error running docker stats: {}", err);
                    return Ok(vec![]);
                }
            }
        }
        Ok(_) => {
            return Ok(vec![]);
        }
        Err(err) => {
            log::debug!("Error checking containers: {}", err);
            return Ok(vec![]);
        }
    };
    let stats: Vec<serde_json::Value> = stats_result
        .lines()
        .filter_map(|line| serde_json::from_str(line).ok())
        .collect();
    Ok(stats)
}

/// Function to get CPU usage percentage.
///
/// # Returns
///
/// A `Vec` containing the CPU usage percentage of each core.
fn get_cpu_percent() -> Vec<String> {
    let mut system = System::new_with_specifics(
        RefreshKind::new().with_cpu(CpuRefreshKind::everything()),
    );
    std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
    system.refresh_cpu_all();
    let mut cpu_usage = Vec::new();
    for core in system.cpus() {
        cpu_usage.push(format!("{:.2}", core.cpu_usage()));
    }
    cpu_usage
}

/// Function to get system metrics.
///
/// # Returns
///
/// A `HashMap` containing the system metrics with CPU load average, memory and swap usage.
fn get_system_metrics() -> HashMap<String, serde_json::Value> {
    let mut system = System::new_all();
    system.refresh_all();

    // https://docs.rs/sysinfo/0.31.4/sysinfo/struct.System.html#method.load_average
    // Currently this doesn't work on Windows
    let load_avg = System::load_average();
    let mut hash_vec = vec![
        (
            "memory_info".to_string(),
            serde_json::json!({
                "total": system.total_memory(),
                "used": system.used_memory(),
            }),
        ),
        (
            "load_averages".to_string(),
            serde_json::json!({
                "m1": load_avg.one,
                "m5": load_avg.five,
                "m15": load_avg.fifteen,
            }),
        ),
    ];

    let total_swap = system.total_swap();
    if total_swap != 0 {
        hash_vec.push((
            "swap_info".to_string(),
            serde_json::json!({
                "total": total_swap,
                "used": system.used_swap(),
            }),
        ));
    }
    HashMap::from_iter(hash_vec)
}


/// Function to get the system information.
///
/// # Returns
///
/// A `HashMap` containing the system information with basic system information and memory/storage information.
pub fn system_resources() -> HashMap<String, serde_json::Value> {
    let mut system_metrics = get_system_metrics();
    let cpu_percent = get_cpu_percent();
    let docker_stats = get_docker_stats().unwrap();
    system_metrics.insert("cpu_usage".to_string(), serde_json::json!(cpu_percent));
    system_metrics.insert("docker_stats".to_string(), serde_json::json!(docker_stats));
    system_metrics
}