1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use std::{
fs::File,
io::{BufWriter, Write},
mem,
path::Path,
sync::atomic::Ordering,
};
use atomic::Atomic;
use crate::{
formatter::{Formatter, FullFormatter},
sink::Sink,
utils, Error, LevelFilter, Record, Result, StringBuf,
};
pub struct FileSink {
level_filter: Atomic<LevelFilter>,
formatter: spin::RwLock<Box<dyn Formatter>>,
file: spin::Mutex<BufWriter<File>>,
}
impl FileSink {
pub fn new<P>(path: P, truncate: bool) -> Result<FileSink>
where
P: AsRef<Path>,
{
let file = utils::open_file(path, truncate)?;
let sink = FileSink {
level_filter: Atomic::new(LevelFilter::All),
formatter: spin::RwLock::new(Box::new(FullFormatter::new())),
file: spin::Mutex::new(BufWriter::new(file)),
};
Ok(sink)
}
}
impl Sink for FileSink {
fn log(&self, record: &Record) -> Result<()> {
if !self.should_log(record.level()) {
return Ok(());
}
let mut string_buf = StringBuf::new();
self.formatter.read().format(record, &mut string_buf)?;
self.file
.lock()
.write_all(string_buf.as_bytes())
.map_err(Error::WriteRecord)?;
Ok(())
}
fn flush(&self) -> Result<()> {
self.file.lock().flush().map_err(Error::FlushBuffer)
}
fn level_filter(&self) -> LevelFilter {
self.level_filter.load(Ordering::Relaxed)
}
fn set_level_filter(&self, level_filter: LevelFilter) {
self.level_filter.store(level_filter, Ordering::Relaxed);
}
fn swap_formatter(&self, mut formatter: Box<dyn Formatter>) -> Box<dyn Formatter> {
mem::swap(&mut *self.formatter.write(), &mut formatter);
formatter
}
}
impl Drop for FileSink {
fn drop(&mut self) {
if let Err(err) = self.file.lock().flush() {
crate::default_error_handler("FileSink", Error::FlushBuffer(err));
}
}
}