use std::sync::{Arc, Mutex};
use std::time::{Instant, Duration};
use crate::config;
struct LogRateLimiter {
last_log: Instant,
min_interval: Duration,
dropped_count: u32, }
impl LogRateLimiter {
fn new(interval_ms: u64) -> Self {
LogRateLimiter {
last_log: Instant::now() - Duration::from_millis(interval_ms), min_interval: Duration::from_millis(interval_ms),
dropped_count: 0,
}
}
fn try_log(&mut self) -> bool {
let now = Instant::now();
if now.duration_since(self.last_log) >= self.min_interval {
self.last_log = now;
true
} else {
self.dropped_count += 1;
false
}
}
fn take_dropped(&mut self) -> u32 {
std::mem::take(&mut self.dropped_count)
}
}
static LOG_LIMITER_INFO: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();
static LOG_LIMITER_ERROR: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();
static LOG_LIMITER_TRACE: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();
static LOG_LIMITER_WARN: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();
fn get_limiter(level: &str) -> Arc<Mutex<LogRateLimiter>> {
match level {
"info" => LOG_LIMITER_INFO.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(100)))).clone(),
"error" => LOG_LIMITER_ERROR.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(200)))).clone(),
"trace" => LOG_LIMITER_TRACE.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(50)))).clone(),
"warn" => LOG_LIMITER_WARN.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(150)))).clone(),
_ => Arc::new(Mutex::new(LogRateLimiter::new(100))),
}
}
pub fn log_info(loginfo: String) -> Option<String> {
if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
return Some("Rejected by mint: info too long.".to_string());
}
let limiter = get_limiter("info");
match limiter.lock() {
Ok(mut guard) => {
if guard.try_log() {
let dropped = guard.take_dropped();
if dropped > 0 {
log::info!("... ({} messages suppressed)", dropped);
}
drop(guard); log::info!("{}", loginfo);
}
None }
Err(_) => Some("Mutex lock failed".to_string()),
}
}
pub fn log_error(loginfo: String) -> Option<String> {
if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
return Some("Rejected by mint: error too long.".to_string());
}
let limiter = get_limiter("error");
match limiter.lock() {
Ok(mut guard) => {
if guard.try_log() {
let dropped = guard.take_dropped();
if dropped > 0 {
log::error!("... ({} messages suppressed)", dropped);
}
drop(guard);
log::error!("{}", loginfo);
}
None
}
Err(_) => Some("Mutex lock failed".to_string()),
}
}
pub fn log_trace(loginfo: String) -> Option<String> {
if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
return Some("Rejected by mint: trace too long.".to_string());
}
let limiter = get_limiter("trace");
match limiter.lock() {
Ok(mut guard) => {
if guard.try_log() {
let dropped = guard.take_dropped();
if dropped > 0 {
log::trace!("... ({} messages suppressed)", dropped);
}
drop(guard);
log::trace!("{}", loginfo);
}
None
}
Err(_) => Some("Mutex lock failed".to_string()),
}
}
pub fn log_warn(loginfo: String) -> Option<String> {
if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
return Some("Rejected by mint: warn too long.".to_string());
}
let limiter = get_limiter("warn");
match limiter.lock() {
Ok(mut guard) => {
if guard.try_log() {
let dropped = guard.take_dropped();
if dropped > 0 {
log::warn!("... ({} messages suppressed)", dropped);
}
drop(guard);
log::warn!("{}", loginfo);
}
None
}
Err(_) => Some("Mutex lock failed".to_string()),
}
}