use std::{
fs::{File, OpenOptions},
io::Write,
path::{Path, PathBuf},
};
use time::{macros::format_description, OffsetDateTime};
#[derive(Debug)]
pub struct AdminLog {
filename: PathBuf,
file: File,
}
impl AdminLog {
pub fn open(filename: &Path) -> Result<Self, LogError> {
let file = OpenOptions::new()
.append(true)
.create(true)
.open(filename)
.map_err(|e| LogError::OpenLogFile(filename.into(), e))?;
Ok(Self {
filename: filename.into(),
file,
})
}
pub fn writeln(&mut self, text: &str) -> Result<(), LogError> {
self.write("[")?;
self.write(&now()?)?;
self.write("] ")?;
self.write(text)?;
self.write("\n")?;
Ok(())
}
fn write(&mut self, msg: &str) -> Result<(), LogError> {
self.file
.write_all(msg.as_bytes())
.map_err(|e| LogError::WriteLogFile(self.filename.clone(), e))
}
}
fn now() -> Result<String, LogError> {
let fmt = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]Z");
OffsetDateTime::now_utc()
.format(fmt)
.map_err(LogError::TimeFormat)
}
#[derive(Debug, thiserror::Error)]
pub enum LogError {
#[error("failed to open log file {0}")]
OpenLogFile(PathBuf, #[source] std::io::Error),
#[error("failed to write to log file {0}")]
WriteLogFile(PathBuf, #[source] std::io::Error),
#[error("failed to format time stamp")]
TimeFormat(#[source] time::error::Format),
}