This commit is contained in:
2025-07-30 22:13:58 +02:00
parent af48990cf7
commit 357790ac34
21 changed files with 4257 additions and 110 deletions

238
system_monitor/Cargo.lock generated Normal file
View File

@@ -0,0 +1,238 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]]
name = "objc2-core-foundation"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
"bitflags",
]
[[package]]
name = "objc2-io-kit"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
dependencies = [
"libc",
"objc2-core-foundation",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "sysinfo"
version = "0.35.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e"
dependencies = [
"libc",
"memchr",
"ntapi",
"objc2-core-foundation",
"objc2-io-kit",
"windows",
]
[[package]]
name = "system_monitor"
version = "0.1.0"
dependencies = [
"sysinfo",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections",
"windows-core",
"windows-future",
"windows-link",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-core",
]
[[package]]
name = "windows-core"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-future"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
"windows-core",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-numerics"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core",
"windows-link",
]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-threading"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
dependencies = [
"windows-link",
]

View File

@@ -0,0 +1,7 @@
[package]
name = "system_monitor"
version = "0.1.0"
edition = "2021"
[dependencies]
sysinfo = "0.35.2"

329
system_monitor/README.md Normal file
View File

@@ -0,0 +1,329 @@
# System Monitor
Une crate Rust pour surveiller les ressources système (CPU, mémoire, swap, disque) avec des seuils configurables.
## 📋 Description
Cette crate fournit une API complète pour surveiller les ressources système et détecter les dépassements de seuils. Elle encapsule la complexité de `sysinfo` dans une interface simple et extensible, parfaite pour des systèmes d'alerte et de monitoring.
## 🚀 Fonctionnalités
- ✅ Surveillance du CPU, mémoire, swap et disque
- ✅ Seuils configurables pour déclencher des alertes
- ✅ API simple et extensible
- ✅ Support pour des fonctions de surveillance personnalisées
- ✅ Gestion automatique des cas d'erreur (division par zéro, etc.)
- ✅ Structure orientée objet avec `SystemMonitor`
- ✅ Surveillance spécifique des points de montage (`/` et `/home`)
## 📦 Installation
Ajoutez cette dépendance à votre `Cargo.toml` :
```toml
[dependencies]
system_monitor = { path = "path/to/system_monitor" }
```
## 🔧 Utilisation
### Utilisation basique
```rust
use system_monitor::SystemMonitor;
// Utilisation avec les seuils par défaut
let mut monitor = SystemMonitor::new();
// Vérifier les seuils et obtenir les alertes
let alerts = monitor.check_thresholds();
for alert in alerts {
println!("🚨 Alerte: {}", alert);
}
// Obtenir un résumé du système
let summary = monitor.get_system_summary();
println!("📊 État système:\n{}", summary);
```
### Seuils personnalisés
```rust
use system_monitor::{SystemMonitor, ResourceThreshold, get_cpu_usage, get_memory_usage};
// Créer des seuils personnalisés
let custom_thresholds = vec![
ResourceThreshold::new(
"CPU".to_string(),
get_cpu_usage,
90.0, // Seuil à 90% au lieu de 80%
"CPU critique ! Intervention requise".to_string(),
),
ResourceThreshold::new(
"Memory".to_string(),
get_memory_usage,
85.0, // Seuil mémoire à 85%
"Mémoire élevée détectée".to_string(),
),
];
let mut monitor = SystemMonitor::new_with_thresholds(custom_thresholds);
```
### Surveillance continue
```rust
use system_monitor::SystemMonitor;
use std::time::Duration;
use std::thread;
let mut monitor = SystemMonitor::new();
loop {
// Actualiser les données système
monitor.refresh();
// Vérifier les seuils
let alerts = monitor.check_thresholds();
if !alerts.is_empty() {
for alert in alerts {
println!("🚨 {}", alert);
// Ici vous pourriez envoyer une notification
}
} else {
println!("✅ Système OK");
}
// Attendre 30 secondes avant la prochaine vérification
thread::sleep(Duration::from_secs(30));
}
```
## 📊 Métriques surveillées
### Seuils par défaut
- **CPU**: 80% - Utilisation globale du processeur
- **Mémoire**: 80% - RAM utilisée vs totale
- **Swap**: 80% - Espace swap utilisé vs total
- **Disque**: 80% - Espace utilisé sur les points de montage `/` et `/home`
### Détails des métriques
#### CPU
- Mesure l'utilisation globale du CPU en pourcentage
- Basé sur la moyenne de tous les cœurs
- Actualisé à chaque appel de `refresh()`
#### Mémoire
- Calcule le pourcentage de RAM utilisée
- Inclut les buffers et cache système
- Formule : `(mémoire_utilisée / mémoire_totale) * 100`
#### Swap
- Surveille l'utilisation de l'espace swap
- Important pour détecter la saturation mémoire
- Retourne 0% si aucun swap n'est configuré
#### Disque
- Surveille spécifiquement `/` (racine) et `/home`
- Calcule l'espace utilisé combiné
- Formule : `((total - disponible) / total) * 100`
## 🎛️ API Reference
### `SystemMonitor`
#### Constructeurs
```rust
// Avec seuils par défaut
pub fn new() -> Self
// Avec seuils personnalisés
pub fn new_with_thresholds(thresholds: Vec<ResourceThreshold>) -> Self
```
#### Méthodes
```rust
// Actualise les données système
pub fn refresh(&mut self)
// Vérifie les seuils et retourne les alertes
pub fn check_thresholds(&mut self) -> Vec<String>
// Retourne un résumé des ressources système
pub fn get_system_summary(&self) -> String
```
### `ResourceThreshold`
Structure pour définir des seuils personnalisés :
```rust
pub struct ResourceThreshold {
pub name: String, // Nom de la ressource
pub get_usage_fn: fn(&System, &Disks) -> f32, // Fonction de mesure
pub threshold: f32, // Seuil (en %)
pub value: f32, // Valeur actuelle
pub message: String, // Message d'alerte
}
impl ResourceThreshold {
pub fn new(name: String, get_usage_fn: fn(&System, &Disks) -> f32, threshold: f32, message: String) -> Self
pub fn check(&mut self, sys: &System, disks: &Disks) -> Option<String>
}
```
### Fonctions de surveillance
```rust
// Utilisation du CPU (%)
pub fn get_cpu_usage(sys: &System, _: &Disks) -> f32
// Utilisation de la mémoire (%)
pub fn get_memory_usage(sys: &System, _: &Disks) -> f32
// Utilisation du swap (%)
pub fn get_swap_usage(sys: &System, _: &Disks) -> f32
// Utilisation du disque (%)
pub fn get_disk_usage(_: &System, disks: &Disks) -> f32
// Seuils par défaut
pub fn get_default_resource_thresholds() -> Vec<ResourceThreshold>
```
## 🔧 Surveillance personnalisée
### Créer une fonction de surveillance custom
```rust
use system_monitor::{ResourceThreshold, SystemMonitor};
use sysinfo::{System, Disks};
// Fonction personnalisée pour surveiller la température CPU (exemple)
fn get_cpu_temperature(sys: &System, _: &Disks) -> f32 {
// Implémentation exemple (nécessite une crate additionnelle)
// Retourne la température en degrés Celsius
65.0 // Valeur d'exemple
}
// Utilisation
let custom_threshold = ResourceThreshold::new(
"CPU Temperature".to_string(),
get_cpu_temperature,
80.0, // Alerte si > 80°C
"Température CPU élevée !".to_string(),
);
let monitor = SystemMonitor::new_with_thresholds(vec![custom_threshold]);
```
### Surveiller des processus spécifiques
```rust
use sysinfo::{System, ProcessExt, Pid};
fn get_process_memory_usage(sys: &System, _: &Disks) -> f32 {
if let Some(process) = sys.process(Pid::from(1234)) { // PID du processus
let process_memory = process.memory() as f32;
let total_memory = sys.total_memory() as f32;
(process_memory / total_memory) * 100.0
} else {
0.0
}
}
```
## 🧪 Tests
```bash
# Exécuter tous les tests
cargo test
# Tests avec logs détaillés
RUST_LOG=debug cargo test
# Tests de performance
cargo test --release
```
### Exemple de test
```rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cpu_usage() {
let sys = System::new_all();
let disks = Disks::new();
let usage = get_cpu_usage(&sys, &disks);
assert!(usage >= 0.0 && usage <= 100.0);
}
#[test]
fn test_threshold_check() {
let mut threshold = ResourceThreshold::new(
"Test".to_string(),
|_, _| 85.0, // Fonction qui retourne toujours 85%
80.0, // Seuil à 80%
"Test alert".to_string(),
);
let sys = System::new();
let disks = Disks::new();
// Devrait déclencher une alerte
assert!(threshold.check(&sys, &disks).is_some());
}
}
```
## 🔧 Dépannage
### Problèmes courants
**Valeurs de métrique à 0**
- Sur certains systèmes, l'initialisation peut prendre du temps
- Appelez `refresh()` et attendez quelques secondes
**Permissions insuffisantes**
- Certaines métriques peuvent nécessiter des privilèges élevés
- Exécutez avec `sudo` si nécessaire
**Pas de disque détecté**
- Vérifiez que `/` et `/home` sont montés
- Adaptez la fonction `get_disk_usage()` pour vos points de montage
### Debug
```rust
// Activer les logs sysinfo
RUST_LOG=sysinfo=debug cargo run
// Inspecter les valeurs
let monitor = SystemMonitor::new();
println!("Disques détectés:");
for disk in &monitor.disks {
println!("- {}: {} bytes", disk.mount_point().display(), disk.total_space());
}
```
## 🚀 Extensions possibles
- Surveillance réseau (bande passante, latence)
- Surveillance de la température
- Métriques de processus spécifiques
- Historique des valeurs
- Export vers des formats standards (Prometheus, etc.)
- Surveillance de services système
## 📄 Licence
Cette crate est sous licence MIT.

211
system_monitor/src/lib.rs Normal file
View File

@@ -0,0 +1,211 @@
use sysinfo::{Disks, System};
#[derive(Debug, Clone)]
pub struct SystemMetrics {
pub cpu_usage: f32,
pub memory_usage: f32,
pub swap_usage: f32,
pub disk_usage: f32,
}
#[derive(Debug, Clone)]
pub struct ThresholdViolation {
pub metric_name: String,
pub current_value: f32,
pub threshold: f32,
pub severity: Severity,
}
#[derive(Debug, Clone)]
pub enum Severity {
Warning,
Critical,
}
pub struct ResourceThreshold {
pub name: String,
pub get_usage_fn: fn(&System, &Disks) -> f32,
pub threshold: f32,
pub critical_threshold: Option<f32>, // Nouveau: seuil critique
pub value: f32,
}
impl ResourceThreshold {
pub fn new(name: String, get_usage_fn: fn(&System, &Disks) -> f32, threshold: f32) -> Self {
Self {
name,
get_usage_fn,
threshold,
critical_threshold: None,
value: 0.0,
}
}
pub fn with_critical_threshold(mut self, critical_threshold: f32) -> Self {
self.critical_threshold = Some(critical_threshold);
self
}
pub fn check(&mut self, sys: &System, disks: &Disks) -> Option<ThresholdViolation> {
self.value = (self.get_usage_fn)(sys, disks);
if let Some(critical) = self.critical_threshold {
if self.value > critical {
return Some(ThresholdViolation {
metric_name: self.name.clone(),
current_value: self.value,
threshold: critical,
severity: Severity::Critical,
});
}
}
if self.value > self.threshold {
Some(ThresholdViolation {
metric_name: self.name.clone(),
current_value: self.value,
threshold: self.threshold,
severity: Severity::Warning,
})
} else {
None
}
}
}
pub fn get_cpu_usage(sys: &System, _: &Disks) -> f32 {
sys.global_cpu_usage()
}
pub fn get_memory_usage(sys: &System, _: &Disks) -> f32 {
let total_memory = sys.total_memory() as f32;
let used_memory = sys.used_memory() as f32;
if total_memory == 0.0 {
return 0.0;
}
used_memory / total_memory * 100.0
}
pub fn get_swap_usage(sys: &System, _: &Disks) -> f32 {
let total_swap = sys.total_swap() as f32;
let used_swap = sys.used_swap() as f32;
if total_swap == 0.0 {
return 0.0;
}
used_swap / total_swap * 100.0
}
pub fn get_disk_usage(_: &System, disks: &Disks) -> f32 {
let mut total_used_space = 0.0;
let mut total_space = 0.0;
for disk in disks {
if let Some(mount_point) = disk.mount_point().to_str() {
if mount_point == "/" || mount_point == "/home" {
total_used_space += disk.total_space() as f32 - disk.available_space() as f32;
total_space += disk.total_space() as f32;
}
}
}
if total_space == 0.0 {
return 0.0; // Avoid division by zero
}
(total_used_space / total_space) * 100.0
}
pub fn get_default_resource_thresholds() -> Vec<ResourceThreshold> {
vec![
ResourceThreshold::new(
"CPU".to_string(),
get_cpu_usage,
80.0,
).with_critical_threshold(95.0),
ResourceThreshold::new(
"Memory".to_string(),
get_memory_usage,
80.0,
).with_critical_threshold(95.0),
ResourceThreshold::new(
"Swap".to_string(),
get_swap_usage,
80.0,
).with_critical_threshold(95.0),
ResourceThreshold::new(
"Disk".to_string(),
get_disk_usage,
80.0,
).with_critical_threshold(90.0),
]
}
pub struct SystemMonitor {
pub system: System,
pub disks: Disks,
pub thresholds: Vec<ResourceThreshold>,
}
impl SystemMonitor {
pub fn new() -> Self {
let mut system = System::new_all();
let mut disks = Disks::new_with_refreshed_list();
system.refresh_all();
disks.refresh(true);
Self {
system,
disks,
thresholds: get_default_resource_thresholds(),
}
}
pub fn new_with_thresholds(thresholds: Vec<ResourceThreshold>) -> Self {
let mut system = System::new_all();
let mut disks = Disks::new_with_refreshed_list();
system.refresh_all();
disks.refresh(true);
Self {
system,
disks,
thresholds,
}
}
pub fn refresh(&mut self) {
self.system.refresh_all();
self.disks.refresh(true);
}
pub fn check_thresholds(&mut self) -> Vec<ThresholdViolation> {
let mut violations = Vec::new();
for threshold in &mut self.thresholds {
if let Some(violation) = threshold.check(&self.system, &self.disks) {
violations.push(violation);
}
}
violations
}
pub fn get_metrics(&self) -> SystemMetrics {
SystemMetrics {
cpu_usage: get_cpu_usage(&self.system, &self.disks),
memory_usage: get_memory_usage(&self.system, &self.disks),
swap_usage: get_swap_usage(&self.system, &self.disks),
disk_usage: get_disk_usage(&self.system, &self.disks),
}
}
}
impl Default for SystemMonitor {
fn default() -> Self {
Self::new()
}
}