wip
This commit is contained in:
9
node_notifier/Cargo.lock
generated
9
node_notifier/Cargo.lock
generated
@@ -644,7 +644,7 @@ dependencies = [
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sysinfo",
|
||||
"system_monitor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1093,6 +1093,13 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system_monitor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"sysinfo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.20.0"
|
||||
|
||||
@@ -8,5 +8,22 @@ dotenvy = "0.15.7"
|
||||
reqwest = { version = "0.12.22", features = ["blocking", "json"] }
|
||||
serde = "1.0.219"
|
||||
serde_json = "1.0.140"
|
||||
sysinfo = "0.35.2"
|
||||
discord_client = { path = "../discord_client" }
|
||||
system_monitor = { path = "../system_monitor" }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
[[example]]
|
||||
name = "basic_monitoring"
|
||||
path = "../examples/basic_monitoring.rs"
|
||||
|
||||
[[example]]
|
||||
name = "custom_thresholds"
|
||||
path = "../examples/custom_thresholds.rs"
|
||||
|
||||
[[example]]
|
||||
name = "discord_notifications"
|
||||
path = "../examples/discord_notifications.rs"
|
||||
|
||||
[[example]]
|
||||
name = "continuous_monitoring"
|
||||
path = "../examples/continuous_monitoring.rs"
|
||||
|
||||
226
node_notifier/README.md
Normal file
226
node_notifier/README.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Node Notifier (Application principale)
|
||||
|
||||
Point d'entrée principal du système de surveillance avec notifications Discord.
|
||||
|
||||
## 📋 Description
|
||||
|
||||
Cette crate constitue l'application principale qui orchestre la surveillance des ressources système et l'envoi de notifications Discord. Elle utilise les crates `system_monitor` et `discord_client` pour fournir un système de monitoring complet.
|
||||
|
||||
## 🔧 Fonctionnalités
|
||||
|
||||
- Orchestration du monitoring système
|
||||
- Gestion des configurations via variables d'environnement
|
||||
- Coordination entre surveillance et notifications
|
||||
- Point d'entrée unique pour l'application
|
||||
|
||||
## 📦 Dépendances
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
dotenvy = "0.15.7" # Gestion des fichiers .env
|
||||
discord_client = { path = "../discord_client" } # Notifications Discord
|
||||
system_monitor = { path = "../system_monitor" } # Surveillance système
|
||||
```
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
### Variables d'environnement
|
||||
|
||||
Créez un fichier `.env` dans le répertoire racine du projet :
|
||||
|
||||
```env
|
||||
# Obligatoire : URL du webhook Discord
|
||||
DISCORD_WEBHOOK=https://discord.com/api/webhooks/your/webhook/url
|
||||
```
|
||||
|
||||
### Configuration Discord
|
||||
|
||||
1. Accédez à votre serveur Discord
|
||||
2. Allez dans les paramètres du canal où vous voulez recevoir les notifications
|
||||
3. Créez un webhook et copiez l'URL
|
||||
4. Ajoutez l'URL dans votre fichier `.env`
|
||||
|
||||
## 🚀 Utilisation
|
||||
|
||||
### Exécution simple
|
||||
|
||||
```bash
|
||||
cargo run
|
||||
```
|
||||
|
||||
### Compilation et exécution
|
||||
|
||||
```bash
|
||||
# Mode debug
|
||||
cargo build
|
||||
./target/debug/node-notifier
|
||||
|
||||
# Mode release (optimisé)
|
||||
cargo build --release
|
||||
./target/release/node-notifier
|
||||
```
|
||||
|
||||
### Exécution en tâche de fond
|
||||
|
||||
```bash
|
||||
# Avec nohup
|
||||
nohup cargo run > monitoring.log 2>&1 &
|
||||
|
||||
# Avec systemd (recommandé pour la production)
|
||||
# Voir section "Déploiement" ci-dessous
|
||||
```
|
||||
|
||||
## 🔄 Flux d'exécution
|
||||
|
||||
1. **Initialisation** : Chargement de la configuration depuis `.env`
|
||||
2. **Création du notifier Discord** : Configuration du client avec webhook
|
||||
3. **Initialisation du monitor système** : Création avec seuils par défaut
|
||||
4. **Vérification des seuils** : Contrôle des ressources système
|
||||
5. **Envoi d'alertes** : Notifications pour les seuils dépassés
|
||||
6. **Rapport final** : Synthèse complète des ressources
|
||||
|
||||
## 🎛️ Personnalisation
|
||||
|
||||
### Modification des seuils
|
||||
|
||||
Pour personnaliser les seuils de surveillance, vous pouvez modifier le code pour utiliser `SystemMonitor::new_with_thresholds()` :
|
||||
|
||||
```rust
|
||||
use system_monitor::{SystemMonitor, ResourceThreshold, get_cpu_usage};
|
||||
|
||||
let custom_thresholds = vec![
|
||||
ResourceThreshold::new(
|
||||
"CPU".to_string(),
|
||||
get_cpu_usage,
|
||||
90.0, // Seuil à 90% au lieu de 80%
|
||||
"CPU critique !".to_string(),
|
||||
),
|
||||
// ... autres seuils
|
||||
];
|
||||
|
||||
let mut monitor = SystemMonitor::new_with_thresholds(custom_thresholds);
|
||||
```
|
||||
|
||||
### Avatar et nom du bot Discord
|
||||
|
||||
Modifiez ces valeurs dans `main.rs` :
|
||||
|
||||
```rust
|
||||
let notifier = DiscordNotifier::new(
|
||||
webhook_url,
|
||||
"Mon Monitor".to_string(), // Nom personnalisé
|
||||
"https://mon-site.com/avatar.png".to_string(), // Avatar personnalisé
|
||||
);
|
||||
```
|
||||
|
||||
## 🚀 Déploiement
|
||||
|
||||
### Service systemd (recommandé)
|
||||
|
||||
1. Créez un fichier de service `/etc/systemd/system/node-notifier.service` :
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Node Notifier System Monitor
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=your-user
|
||||
WorkingDirectory=/path/to/node-notifier/node_notifier
|
||||
ExecStart=/path/to/node-notifier/target/release/node-notifier
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
Environment=DISCORD_WEBHOOK=your-webhook-url
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
2. Activez et démarrez le service :
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable node-notifier
|
||||
sudo systemctl start node-notifier
|
||||
```
|
||||
|
||||
### Cron (alternative)
|
||||
|
||||
Pour une exécution périodique plutôt que continue :
|
||||
|
||||
```bash
|
||||
# Exécution toutes les 5 minutes
|
||||
*/5 * * * * cd /path/to/node-notifier/node_notifier && /path/to/cargo run
|
||||
```
|
||||
|
||||
## 📊 Logs et debugging
|
||||
|
||||
### Activation des logs
|
||||
|
||||
Ajoutez des logs pour le debugging :
|
||||
|
||||
```bash
|
||||
RUST_LOG=debug cargo run
|
||||
```
|
||||
|
||||
### Redirection des logs
|
||||
|
||||
```bash
|
||||
# Logs dans un fichier
|
||||
cargo run > monitoring.log 2>&1
|
||||
|
||||
# Logs avec rotation
|
||||
cargo run 2>&1 | tee -a monitoring.log
|
||||
```
|
||||
|
||||
## 🔧 Dépannage
|
||||
|
||||
### Erreurs courantes
|
||||
|
||||
**"DISCORD_WEBHOOK environment variable not set"**
|
||||
```bash
|
||||
# Vérifiez votre fichier .env
|
||||
cat .env
|
||||
# Ou définissez directement
|
||||
export DISCORD_WEBHOOK="https://discord.com/api/webhooks/..."
|
||||
```
|
||||
|
||||
**"Failed to send notification"**
|
||||
- Vérifiez la connectivité réseau
|
||||
- Validez l'URL du webhook Discord
|
||||
- Consultez les logs Discord pour les erreurs
|
||||
|
||||
**Permissions système insuffisantes**
|
||||
- Certaines métriques peuvent nécessiter des privilèges élevés
|
||||
- Exécutez avec `sudo` si nécessaire
|
||||
|
||||
## 🧪 Tests
|
||||
|
||||
```bash
|
||||
# Tests unitaires
|
||||
cargo test
|
||||
|
||||
# Tests avec logs
|
||||
RUST_LOG=debug cargo test
|
||||
|
||||
# Tests spécifiques
|
||||
cargo test test_name
|
||||
```
|
||||
|
||||
## 📈 Métriques
|
||||
|
||||
L'application surveille par défaut :
|
||||
|
||||
- **CPU** : Utilisation globale en pourcentage
|
||||
- **Mémoire** : RAM utilisée vs totale
|
||||
- **Swap** : Espace swap utilisé vs total
|
||||
- **Disque** : Espace utilisé sur `/` et `/home`
|
||||
|
||||
## 🔮 Extensions possibles
|
||||
|
||||
- Configuration via fichier TOML/YAML
|
||||
- Support de multiples webhooks
|
||||
- Planification d'exécutions
|
||||
- Interface CLI avec arguments
|
||||
- Mode daemon avec rechargement de config
|
||||
@@ -1,100 +1,54 @@
|
||||
use discord_client::DiscordNotifier;
|
||||
use dotenvy::dotenv;
|
||||
use sysinfo::{Disks, System};
|
||||
use system_monitor::{SystemMonitor, ThresholdViolation, Severity};
|
||||
|
||||
struct ResourceThreshold {
|
||||
name: String,
|
||||
get_usage_fn: fn(&System, &Disks) -> f32,
|
||||
threshold: f32,
|
||||
value: f32,
|
||||
messagef: String,
|
||||
}
|
||||
struct AlertFormatter;
|
||||
|
||||
impl ResourceThreshold {
|
||||
fn check(&mut self, sys: &System, disks: &Disks) -> Option<String> {
|
||||
self.value = (self.get_usage_fn)(sys, disks);
|
||||
if self.value > self.threshold {
|
||||
Some(
|
||||
format!(
|
||||
"{}: {:.2}% - {}",
|
||||
self.name, self.value, self.messagef
|
||||
)
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
impl AlertFormatter {
|
||||
fn format_violation(&self, violation: &ThresholdViolation) -> String {
|
||||
let emoji = match violation.severity {
|
||||
Severity::Warning => "⚠️",
|
||||
Severity::Critical => "🚨",
|
||||
};
|
||||
|
||||
let level = match violation.severity {
|
||||
Severity::Warning => "ALERTE",
|
||||
Severity::Critical => "CRITIQUE",
|
||||
};
|
||||
|
||||
format!(
|
||||
"{} **{}** - {}\n\n**Valeur actuelle:** {:.2}%\n**Seuil:** {:.2}%",
|
||||
emoji,
|
||||
level,
|
||||
self.get_message_for_metric(&violation.metric_name, &violation.severity),
|
||||
violation.current_value,
|
||||
violation.threshold
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cpu_usage(sys: &System, _: &Disks) -> f32 {
|
||||
sys.global_cpu_usage()
|
||||
}
|
||||
|
||||
fn get_memory_usage(sys: &System, _: &Disks) -> f32 {
|
||||
let total_memory = sys.total_memory() as f32;
|
||||
let used_memory = sys.used_memory() as f32;
|
||||
|
||||
used_memory / total_memory * 100.0
|
||||
}
|
||||
|
||||
fn get_swap_usage(sys: &System, _: &Disks) -> f32 {
|
||||
let total_swap = sys.total_swap() as f32;
|
||||
let used_swap = sys.used_swap() as f32;
|
||||
|
||||
used_swap / total_swap * 100.0
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
fn get_message_for_metric(&self, metric: &str, severity: &Severity) -> String {
|
||||
match (metric, severity) {
|
||||
("CPU", Severity::Warning) => "Utilisation CPU élevée détectée".to_string(),
|
||||
("CPU", Severity::Critical) => "CPU en surchauffe - Intervention requise !".to_string(),
|
||||
("Memory", Severity::Warning) => "Utilisation mémoire élevée".to_string(),
|
||||
("Memory", Severity::Critical) => "Mémoire saturée - Risque de crash !".to_string(),
|
||||
("Swap", Severity::Warning) => "Utilisation swap élevée".to_string(),
|
||||
("Swap", Severity::Critical) => "Swap saturé - Performance dégradée !".to_string(),
|
||||
("Disk", Severity::Warning) => "Espace disque faible".to_string(),
|
||||
("Disk", Severity::Critical) => "Disque presque plein - Nettoyage urgent !".to_string(),
|
||||
(metric, _) => format!("Problème détecté sur {}", metric),
|
||||
}
|
||||
}
|
||||
|
||||
if total_space == 0.0 {
|
||||
return 0.0; // Avoid division by zero
|
||||
fn format_summary(&self, metrics: &system_monitor::SystemMetrics) -> String {
|
||||
format!(
|
||||
"📊 **Rapport Système**\n\n```\nCPU: {:.1}%\nMémoire: {:.1}%\nSwap: {:.1}%\nDisque: {:.1}%\n```\n\n*Surveillance automatique*",
|
||||
metrics.cpu_usage,
|
||||
metrics.memory_usage,
|
||||
metrics.swap_usage,
|
||||
metrics.disk_usage
|
||||
)
|
||||
}
|
||||
|
||||
(total_used_space / total_space) * 100.0
|
||||
}
|
||||
|
||||
fn get_resource_thresholds() -> Vec<ResourceThreshold> {
|
||||
vec![
|
||||
ResourceThreshold {
|
||||
name: "CPU".to_string(),
|
||||
get_usage_fn: get_cpu_usage,
|
||||
threshold: 80.0,
|
||||
value: 0.0,
|
||||
messagef: "High CPU usage detected".to_string(),
|
||||
},
|
||||
ResourceThreshold {
|
||||
name: "Memory".to_string(),
|
||||
get_usage_fn: get_memory_usage,
|
||||
threshold: 80.0,
|
||||
value: 0.0,
|
||||
messagef: "High memory usage detected".to_string(),
|
||||
},
|
||||
ResourceThreshold {
|
||||
name: "Swap".to_string(),
|
||||
get_usage_fn: get_swap_usage,
|
||||
threshold: 80.0,
|
||||
value: 0.0,
|
||||
messagef: "High swap usage detected".to_string(),
|
||||
},
|
||||
ResourceThreshold {
|
||||
name: "Disk".to_string(),
|
||||
get_usage_fn: get_disk_usage,
|
||||
threshold: 80.0,
|
||||
value: 0.0,
|
||||
messagef: "High disk usage detected".to_string(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -106,29 +60,20 @@ fn main() {
|
||||
"https://cdn.shopify.com/s/files/1/0262/1423/6212/files/Lord_of_the_Rings_eye_of_Sauron_-_Ghtic.com_-_Blog.png?v=1579680018".to_string(),
|
||||
);
|
||||
|
||||
let mut sys = System::new_all();
|
||||
let mut disks: Disks = Disks::new_with_refreshed_list();
|
||||
sys.refresh_all();
|
||||
disks.refresh(true);
|
||||
let mut monitor = SystemMonitor::new();
|
||||
let formatter = AlertFormatter;
|
||||
|
||||
let mut thresholds = get_resource_thresholds();
|
||||
|
||||
for threshold in &mut thresholds {
|
||||
if let Some(message) = threshold.check(&sys, &disks) {
|
||||
notifier.send_notification(&message).expect("Failed to send notification");
|
||||
}
|
||||
// Check for threshold violations and send alerts
|
||||
let violations = monitor.check_thresholds();
|
||||
for violation in violations {
|
||||
let message = formatter.format_violation(&violation);
|
||||
notifier.send_notification(&message).expect("Failed to send notification");
|
||||
}
|
||||
|
||||
// Send a final notification with all system information
|
||||
let mut final_message = String::new();
|
||||
for threshold in thresholds {
|
||||
final_message.push_str(&format!(
|
||||
"{} usage: {:.2}%\n",
|
||||
threshold.name, threshold.value
|
||||
));
|
||||
}
|
||||
|
||||
let metrics = monitor.get_metrics();
|
||||
let summary = formatter.format_summary(&metrics);
|
||||
notifier
|
||||
.send_notification(&final_message)
|
||||
.send_notification(&summary)
|
||||
.expect("Failed to send final notification");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user