use std::{fs, thread, time::Duration};
use loggit::{
info,
logger::{init, set_file, set_log_level, set_print_to_terminal},
Level,
};
const THREADS: usize = 8;
const MSG_PER_THREAD: usize = 200;
fn find_log_file(prefix: &str) -> std::path::PathBuf {
fs::read_dir(".")
.unwrap()
.filter_map(|e| e.ok())
.map(|e| e.path())
.find(|p| {
p.file_name()
.and_then(|n| n.to_str())
.map(|n| n.starts_with(prefix) && n.ends_with(".txt"))
.unwrap_or(false)
})
.expect("log file not found")
}
fn cleanup(path: &std::path::Path) {
let _ = fs::remove_file(path);
}
#[test]
fn concurrent_file_logging() {
init();
set_print_to_terminal(false).unwrap();
set_log_level(Level::INFO).unwrap();
let prefix = format!("mt_log_{}", chrono::Utc::now().timestamp_nanos());
let pattern = format!("{prefix}_{{date}}_{{time}}.txt");
set_file(&pattern).unwrap();
let mut handles = Vec::with_capacity(THREADS);
for id in 0..THREADS {
handles.push(thread::spawn(move || {
for n in 0..MSG_PER_THREAD {
info!("thread={id} line={n}");
}
}));
}
for h in handles {
h.join().expect("worker panicked");
}
let log_path = find_log_file(&prefix);
let contents = fs::read_to_string(&log_path).expect("unable to read log file");
let line_count = contents.lines().count();
assert_eq!(
line_count,
THREADS * MSG_PER_THREAD,
"expected {} lines, got {}",
THREADS * MSG_PER_THREAD,
line_count
);
cleanup(&log_path);
}
#[test]
fn concurrent_level_switching() {
init();
set_print_to_terminal(false).unwrap();
let prefix = format!("level_flip_{}", chrono::Utc::now().timestamp_nanos());
set_file(&format!("{prefix}_{{date}}_{{time}}.txt")).unwrap();
let mut handles = Vec::with_capacity(THREADS);
for id in 0..(THREADS / 2) {
handles.push(thread::spawn(move || {
for i in 0..500 {
info!("logging‑thread={id} i={i}");
}
}));
}
let levels = [
Level::TRACE,
Level::DEBUG,
Level::INFO,
Level::WARN,
Level::ERROR,
];
handles.push(thread::spawn(move || {
for lvl in levels.iter().cycle().take(1000) {
set_log_level(*lvl).unwrap();
thread::sleep(Duration::from_millis(1));
}
}));
for h in handles {
h.join().expect("thread panicked");
}
let log_path = find_log_file(&prefix);
let bytes = fs::read(&log_path).expect("could not read file");
assert!(!bytes.is_empty(), "file should contain at least some lines");
cleanup(&log_path);
}