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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use chrono::Local;
use die::die;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::sync::mpsc::{sync_channel, SyncSender};
use std::sync::Arc;
use std::sync::Barrier;
use std::thread;
pub struct LogFast {
pub filename: String,
src: Option<SyncSender<String>>,
barrier: Arc<Barrier>,
}
impl LogFast {
pub fn new(filename: &str, buffer_size: usize) -> Result<LogFast, String> {
if buffer_size == 0 {
return Err("Buffer size needs to be bigger than 0".to_string());
}
let mut log_file = match OpenOptions::new().create(true).append(true).open(filename) {
Ok(log_file) => log_file,
Err(err) => return Err(format!("Error opening log file '{}': {}", filename, err)),
};
let (src, dest) = sync_channel::<String>(buffer_size);
let barrier = Arc::new(Barrier::new(2));
{
let barrier_moved = barrier.clone();
let filename_moved = filename.to_string();
thread::spawn(move || {
while let Ok(msg) = dest.recv() {
writeln!(log_file, "{}", msg).unwrap_or_else(|err| {
die!("Error writing to log file '{}': {}", filename_moved, err)
})
}
barrier_moved.wait();
})
};
Ok(LogFast {
filename: filename.to_string(),
src: Some(src),
barrier,
})
}
pub fn log(&mut self, msg: &str) {
self.src
.as_ref()
.unwrap_or_else(|| {
die!(
"Error talking to logging thread for log file '{}'",
self.filename
)
})
.send(format!("{}: {}", Local::now().naive_local(), &msg))
.unwrap_or_else(|err| {
die!(
"Error talking to logging thread for log file '{}': {}",
self.filename,
err
)
})
}
}
impl Drop for LogFast {
fn drop(&mut self) {
self.src = None;
self.barrier.wait();
}
}