use crate::{
config::{LogFormat, SinkConfigBuild, SinkConfigTrait},
log_impl::{LogSink, LogSinkTrait},
time::Timer,
};
use log::*;
use ring_file::*;
use std::hash::{Hash, Hasher};
use std::io::{stdout, Write};
use std::path::{Path, PathBuf};
#[derive(Hash)]
pub struct LogRingFile {
pub file_path: Box<Path>,
pub level: Level,
pub format: LogFormat,
pub buf_size: i32,
}
impl LogRingFile {
pub fn new<P: Into<PathBuf>>(
file_path: P, buf_size: i32, max_level: Level, format: LogFormat,
) -> Self {
assert!(buf_size > 0);
Self { buf_size, file_path: file_path.into().into_boxed_path(), level: max_level, format }
}
}
impl SinkConfigBuild for LogRingFile {
fn build(&self) -> LogSink {
LogSink::RingFile(LogSinkRingFile::new(self))
}
}
impl SinkConfigTrait for LogRingFile {
fn get_level(&self) -> Level {
self.level
}
fn get_file_path(&self) -> Option<Box<Path>> {
Some(self.file_path.clone())
}
fn write_hash(&self, hasher: &mut Box<dyn Hasher>) {
self.hash(hasher);
hasher.write(b"LogRingFile");
}
}
pub(crate) struct LogSinkRingFile {
max_level: Level,
formatter: LogFormat,
ring: RingFile,
}
unsafe impl Send for LogSinkRingFile {}
unsafe impl Sync for LogSinkRingFile {}
impl LogSinkRingFile {
fn new(config: &LogRingFile) -> Self {
Self {
max_level: config.level,
formatter: config.format.clone(),
ring: RingFile::new(config.buf_size, config.file_path.clone()),
}
}
fn dump(&self) -> std::io::Result<()> {
let mut f = stdout();
let _ = f.write_all(b"RingFile: start dumping\n");
if let Err(e) = self.ring.dump() {
eprintln!("RingFile: dump error {:?}", e);
return Err(e);
}
let _ = f.write_all(b"RingFile: dump complete\n");
Ok(())
}
}
impl LogSinkTrait for LogSinkRingFile {
fn open(&self) -> std::io::Result<()> {
let mut f = stdout();
let _ = f.write_all(b"ringfile is on\n");
self.ring.clear();
Ok(())
}
fn reopen(&self) -> std::io::Result<()> {
let _ = self.dump();
std::process::exit(-2);
}
#[inline(always)]
fn log(&self, now: &Timer, r: &Record) {
if r.level() <= self.max_level {
let content = self.formatter.process(now, r);
self.ring.write(content);
}
}
#[inline(always)]
fn flush(&self) {
let _ = self.dump();
}
}