1pub mod logging_implementations {
2
3 extern crate chrono;
4 use crate::logging_abstraction::Logger;
5 use contracts::*;
6 use std::{fs::File, io::Write};
7
8 const UNINITIALIZED_FILE_HANDLE_EXCEPTION: &str = "The log file was not initialized before writing to the log.";
9
10 pub struct FileLogger {
11 pub logfile_path: String,
13
14 file_handle: Option<File>
16 }
17
18 impl FileLogger {
19
20 #[debug_requires(!file_path.trim().is_empty(), "Empty or whitespace filepaths are not allowed")]
22 pub fn new_from_string(file_path: String) -> Result<FileLogger, std::io::Error> {
23 let mut new_logger = FileLogger {
24 logfile_path: file_path,
25 file_handle: None };
26
27 match new_logger.open() {
29 Some(error) => Err(error),
30 None => return Ok(new_logger)
31 }
32 }
33
34 pub fn new_from_static_string(file_path: &str) -> Result<FileLogger, std::io::Error> {
36 return FileLogger::new_from_string(String::from(file_path));
37 }
38
39 #[debug_requires(!to_write.to_string().is_empty(), "We shouldn't try to write empty data to the log")]
41 #[debug_ensures(!ret.trim().is_empty(), "The formatted log entry shouldn't be empty")]
42 fn format_entry<T>(&self, to_write: T) -> String
43 where T: std::fmt::Display
44 {
45 let current_time = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
46 return std::format!("[{}]: {}\n", current_time, to_write);
47 }
48 }
49
50 impl Logger for FileLogger {
51
52 fn open(&mut self) -> Option<std::io::Error>
53 {
54 let created_file = File::create(&self.logfile_path);
55
56 match created_file {
57 Ok(created_file_handle) => self.file_handle = Some(created_file_handle),
58 Err(error) => return Some(error)
59 }
60
61 None
62 }
63
64 fn write<T: std::fmt::Display>(&self, to_write: T) -> Option<std::io::Error>
65 {
66 if self.file_handle.is_none() {
68 return Some(std::io::Error::new(std::io::ErrorKind::NotFound, UNINITIALIZED_FILE_HANDLE_EXCEPTION));
69 }
70
71 let mut log_file = self.file_handle.as_ref().unwrap();
72 let to_write = self.format_entry(to_write);
74 println!("{}", to_write);
75 let write_result = log_file.write_all(to_write.as_bytes());
76
77 if write_result.is_err() {
78 return write_result.err();
79 }
80
81 None
82 }
83
84 fn write_slice<T>(&self, to_write: &[&T]) -> std::option::Option<std::io::Error>
85 where T: std::fmt::Display
86 {
87 for item in to_write {
89 let write_result = self.write(item);
90 if write_result.is_some() {
91 return write_result;
92 }
93 }
94
95 None
96 }
97 }
98}