use chrono::Utc;
use notify_rust::Notification;
use serde_json::json;
use std::sync::atomic::{AtomicU8, Ordering};
use crate::events::{LogLevel, LogMode, SentinelEvent};
static CURRENT_LOG_LEVEL: AtomicU8 = AtomicU8::new(3); static CURRENT_LOG_MODE: AtomicU8 = AtomicU8::new(0);
pub fn set_logging_level(l: LogLevel) {
CURRENT_LOG_LEVEL.store(l as u8, Ordering::Relaxed);
}
pub fn set_logging_mode(m: LogMode) {
CURRENT_LOG_MODE.store(m as u8, Ordering::Relaxed);
}
pub fn get_log_level() -> LogLevel {
LogLevel::from_u8(CURRENT_LOG_LEVEL.load(Ordering::Relaxed))
}
fn get_log_mode() -> LogMode {
LogMode::from_u8(CURRENT_LOG_MODE.load(Ordering::Relaxed))
}
pub fn emit(event: &SentinelEvent<'_>) {
if event.severity() > get_log_level() {
return;
}
emit_notification(event);
match get_log_mode() {
LogMode::Json => log_json(event),
LogMode::Compact => log_compact(event),
}
}
fn log_compact(event: &SentinelEvent<'_>) {
println!(
"{} [{}] {}",
Utc::now().to_rfc3339(),
event.severity().as_str(),
event
);
}
fn log_json(event: &SentinelEvent<'_>) {
let mut log_entry = serde_json::to_value(event).unwrap_or(json!({
"event": "SerializationError"
}));
if let Some(map) = log_entry.as_object_mut() {
map.insert("timestamp".into(), Utc::now().to_rfc3339().into());
map.insert("level".into(), event.severity().as_str().into());
match event {
SentinelEvent::Message { level: _, text } => {
map.insert("message".into(), (*text).into());
map.remove("text");
}
_ => {}
}
}
println!("{}", serde_json::to_string(&log_entry).unwrap());
}
fn emit_notification(event: &SentinelEvent<'_>) {
match event {
SentinelEvent::LowMemoryWarn { .. }
| SentinelEvent::LowSwapWarn { .. }
| SentinelEvent::PsiPressureWarn { .. } => {
send_notification("Low Memory Warning", &event.to_string(), "dialog-warning");
}
SentinelEvent::KillExecuted { .. } => {
send_notification("System Load Shedding", &event.to_string(), "process-stop");
}
SentinelEvent::KillTriggered { .. } => {
send_notification(
"Kill Sequence Initiated",
&event.to_string(),
"process-stop",
);
}
SentinelEvent::KillSequenceAborted { .. } => {
send_notification("Kill Sequence Aborted", &event.to_string(), "dialog-error");
}
SentinelEvent::Message { level, text, .. } => match level {
LogLevel::Warn => {
send_notification("Ram Sentinel Warning", *text, "dialog-warning");
}
LogLevel::Error => {
send_notification("Ram Sentinel Error", *text, "dialog-error");
}
_ => {}
},
_ => {}
}
}
fn send_notification(summary: &str, body: &str, icon: &str) {
let _ = Notification::new()
.summary(summary)
.body(body)
.icon(icon)
.show();
}