use std::{
env,
fmt::Debug,
fs,
io::{self, Write},
};
use once_cell::sync::Lazy;
#[doc(hidden)]
pub static LOGGER: Lazy<Index> = Lazy::new(Index::default);
#[macro_export]
macro_rules! log {
($name:tt $ext:tt, $($arg:tt)*) => {
file_log::LOGGER.write_log($name, $ext, format!($($arg)*)).unwrap();
};
($name:tt, $($arg:tt)*) => {
file_log::LOGGER.write_log($name, "log", format!($($arg)*)).unwrap();
};
}
const INDEX: &str = "log_index";
const FILE_LOG_INDEX_ENV_VAR: &str = "FILE_LOG_INDEX";
#[doc(hidden)]
#[derive(Debug)]
pub struct Index(usize);
impl Index {
pub fn next(&mut self) {
self.0 += 1;
}
fn get() -> Index {
match env::var(FILE_LOG_INDEX_ENV_VAR) {
Ok(index) => Index(index.parse().unwrap_or_default()),
Err(_) => Index(
fs::read_to_string(INDEX)
.map(|i| i.parse().unwrap_or_default())
.unwrap_or_default(),
),
}
}
fn save(&self) {
fs::write(INDEX, format!("{}", self.0)).unwrap();
}
pub fn index(&self) -> usize {
self.0
}
pub fn write_log<C: AsRef<[u8]>>(&self, log: &str, extension: &str, data: C) -> io::Result<()> {
let mut file = fs::OpenOptions::new()
.create(true)
.append(true)
.open(format!("{log}_{}.{extension}", self.0))?;
file.write_all(data.as_ref())?;
file.write_all("\n".as_bytes())
}
}
impl Default for Index {
fn default() -> Self {
let mut index = Index::get();
if env::var(FILE_LOG_INDEX_ENV_VAR).is_err() {
index.next();
index.save();
}
index
}
}
pub fn index() -> usize {
LOGGER.index()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_index_next() {
let mut index = Index::default();
let initial_value = index.index();
index.next();
assert_eq!(index.index(), initial_value + 1);
}
#[test]
fn test_index_write_log() {
let index = Index::default();
let log_name = "test_log";
let extension = "txt";
let data = "Test log data";
let result = index.write_log(log_name, extension, data);
assert!(result.is_ok());
let file_path = format!(
"{log}_{}.{extension}",
index.index(),
log = log_name,
extension = extension
);
assert!(fs::metadata(&file_path).is_ok());
fs::remove_file(file_path).unwrap();
}
}