1use file_reader::{FileReader,
2 FileReaderParam};
3use file_writer::{FileWriter,
4 FileWriterParam};
5use general_error::Error;
6use std::fmt;
7
8use std::time::Duration;
9
10use std::sync::atomic::AtomicBool;
11use std::sync::atomic::Ordering;
12
13use std::sync::Arc;
14use std::sync::Mutex;
15
16use std::thread;
17
18const LOG_MAX_SIZE : usize = 1024;
19
20const LOG_WRITE_INTERVAL_IN_MILLISEC : u64 = 1000;
21
22pub struct LogHandler<T : 'static + Log + Send> {
23 log_file : Option<String>,
24 stats : Arc<Mutex<T>>,
25 write_flag : Arc<AtomicBool>,
26}
27
28#[derive(Clone, Copy, PartialEq)]
29pub enum ErrorKind {
30 ParseError,
31}
32
33#[derive(Clone)]
34pub struct LogError {
35 kind : ErrorKind,
36 path : String,
37}
38
39impl fmt::Display for LogError {
40 fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
41 use self::ErrorKind::*;
42 match self.kind {
43 ParseError => write!(f, "failed to parse log file \"{}\"", self.path),
44 }
45 }
46}
47
48impl LogError {
49 pub fn new(kind : ErrorKind, path : &str) -> LogError {
50 LogError {
51 kind,
52 path : String::from(path),
53 }
54 }
55}
56
57pub fn to_err(e : LogError) -> super::Error {
58 use super::{Error, ErrorKind};
59 Error::new(ErrorKind::LogError(e))
60}
61
62pub trait Log {
63 fn serialize(&self) -> String;
64
65 fn deserialize(&mut self, &[u8]) -> Result<(), ()>;
66
67 fn read_from_file(&mut self, log_file : &str) -> Result<(), Error> {
68 let mut reader = FileReader::new(log_file,
69 FileReaderParam { write : false,
70 buffered : false })?;
71 let mut buffer : [u8; LOG_MAX_SIZE] = [0; LOG_MAX_SIZE];
72 let _len_read = reader.read(&mut buffer)?;
73
74 match self.deserialize(&buffer) {
75 Ok(()) => Ok(()),
76 Err(()) => Err(to_err(LogError::new(ErrorKind::ParseError, log_file))),
77 }
78 }
79
80 fn write_to_file(&self, log_file : &str) -> Result<(), Error> {
81 let mut writer = FileWriter::new(log_file,
82 FileWriterParam { read : false,
83 append : false,
84 buffered : false })?;
85 let output = self.serialize();
86
87 let _len_written = writer.write(output.as_bytes())?;
88
89 Ok(())
90 }
91}
92
93impl<T : 'static + Log + Send> LogHandler<T> {
94 pub fn new(log_file : Option<&str>,
95 stats : &Arc<Mutex<T>>) -> LogHandler<T> {
96 let log_file = match log_file {
97 None => None,
98 Some(ref lg) => Some(lg.to_string()),
99 };
100 let write_flag = Arc::new(AtomicBool::new(true));
101 let runner_write_flag = Arc::clone(&write_flag);
102 thread::spawn(move || {
103 loop {
104 runner_write_flag.store(true, Ordering::Relaxed);
105
106 thread::sleep(Duration::from_millis(LOG_WRITE_INTERVAL_IN_MILLISEC));
107 }
108 });
109 LogHandler {
110 log_file,
111 stats : Arc::clone(stats),
112 write_flag,
113 }
114 }
115
116 pub fn read_from_file(&self) -> Result<(), Error> {
117 use super::ErrorKind;
118 use super::file_error;
119
120 match self.log_file {
121 None => Ok(()),
122 Some(ref lg) => {
123 let res = self.stats.lock().unwrap().read_from_file(lg);
124
125 if let Err(ref e) = res {
126 if let ErrorKind::FileError(ref fe) = e.kind {
127 if let file_error::ErrorKind::NotFound = fe.kind {
128 return Ok(());
129 }
130 }
131 }
132 res
133 }
134 }
135 }
136
137 pub fn write_to_file(&self, force_write : bool) -> Result<(), Error> {
138 if force_write || self.write_flag.swap(false, Ordering::SeqCst) {
139 match self.log_file {
140 None => {},
141 Some(ref x) => self.stats.lock().unwrap().write_to_file(x)?,
142 }
143 }
144
145 Ok(())
146 }
147}