#[macro_use]
extern crate lazy_static;
extern crate chrono;
extern crate regex;
mod parser;
use crate::parser::Parser;
use chrono::{Date, Duration, Local, TimeZone};
use regex::Regex;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::fmt;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io::{BufWriter, Write};
use std::ops::Add;
use std::path::Path;
use std::process;
use std::sync::Mutex;
use std::thread;
#[cfg(windows)]
const NEW_LINE: &'static str = "\r\n";
#[cfg(windows)]
const NEW_LINE_ESCAPED_CHARS: &'static [char; 4] = &['\\', 'r', '\\', 'n'];
#[cfg(not(windows))]
const NEW_LINE: &'static str = "\n";
#[cfg(not(windows))]
const NEW_LINE_ESCAPED_CHARS: &'static [char; 2] = &['\\', 'n'];
#[derive(Clone, Copy)]
pub enum Level {
#[allow(dead_code)]
Fatal,
Error,
Warn,
Notice,
Info,
Debug,
Trace,
}
impl Level {
pub fn number(&self) -> usize {
match self {
Level::Fatal => 1,
Level::Error => 2,
Level::Warn => 3,
Level::Notice => 4,
Level::Info => 5,
Level::Debug => 6,
Level::Trace => 7,
}
}
}
impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Level::Fatal => write!(f, "Fatal"),
Level::Error => write!(f, "Error"),
Level::Warn => write!(f, "Warn"),
Level::Notice => write!(f, "Notice"),
Level::Info => write!(f, "Info"),
Level::Debug => write!(f, "Debug"),
Level::Trace => write!(f, "Trace"),
}
}
}
lazy_static! {
#[deprecated(
since = "0.3.10",
note = "Please use the casual_logger::Log::xxxx() methods instead"
)]
pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::default());
static ref QUEUE_T: Mutex<VecDeque<(InternalTable)>> = Mutex::new(VecDeque::<(InternalTable)>::new());
static ref QUEUE_F: Mutex<VecDeque<(InternalTable)>> = Mutex::new(VecDeque::<(InternalTable)>::new());
static ref RESERVE_TARGET: Mutex<ReserveTarget> = Mutex::new(ReserveTarget::default());
static ref SIGNAL_CAN_FLUSH: Mutex<SignalCanFlush> = Mutex::new(SignalCanFlush::default());
static ref RE_TOML_KEY: Mutex<Regex> = Mutex::new(Regex::new(r"^[A-Za-z0-9_-]+$").unwrap());
static ref RE_WHITE_SPACE: Mutex<Regex> = Mutex::new(Regex::new(r"\s").unwrap());
static ref OPT_STATE: Mutex<OptState> = Mutex::new(OptState::default());
}
thread_local!(static SEQ: RefCell<u128> = {
RefCell::new(1)
});
struct InternalTable {
thread_id: String,
seq: u128,
table: Table,
}
impl InternalTable {
fn new(thread_id: &str, seq: u128, table: &Table) -> Self {
InternalTable {
thread_id: thread_id.to_string(),
seq: seq,
table: table.clone(),
}
}
}
#[derive(Clone)]
pub struct Table {
level: Level,
message: String,
message_trailing_newline: bool,
sorted_map: BTreeMap<String, String>,
}
impl Default for Table {
fn default() -> Self {
Table {
sorted_map: BTreeMap::new(),
level: Level::Trace,
message: "".to_string(),
message_trailing_newline: false,
}
}
}
impl Table {
fn new(level: Level, message: &str, trailing_newline: bool) -> Self {
Table {
sorted_map: BTreeMap::new(),
level: level,
message: message.to_string(),
message_trailing_newline: trailing_newline,
}
}
#[deprecated(since = "0.4.1", note = "This is private method")]
pub fn format_str_value(value: &str) -> String {
Parser::format_str_value(value)
}
fn correct_key(key: &str) -> String {
if let Ok(logger) = LOGGER.lock() {
match Logger::get_optimization(&logger) {
Opt::Release => {
return key.to_string();
}
_ => {}
}
};
if let Ok(re_toml_key) = RE_TOML_KEY.lock() {
if re_toml_key.is_match(key) {
return key.to_string();
}
}
if let Ok(re_white_space) = RE_WHITE_SPACE.lock() {
format!(
"\"{}\"",
Parser::escape_double_quotation(&re_white_space.replace_all(key, " "))
)
} else {
key.to_string()
}
}
pub fn literal<'a>(&'a mut self, key: &'a str, value: &str) -> &'a mut Self {
self.sorted_map.insert(
Table::correct_key(key),
value.to_string(),
);
self
}
pub fn str<'a>(&'a mut self, key: &'a str, value: &str) -> &'a mut Self {
self.sorted_map.insert(
Table::correct_key(key),
Table::format_str_value(value).to_string(),
);
self
}
pub fn char<'a>(&'a mut self, key: &'a str, value: char) -> &'a mut Self {
self.sorted_map.insert(
Table::correct_key(key),
Table::format_str_value(&value.to_string()).to_string(),
);
self
}
pub fn int<'a>(&'a mut self, key: &'a str, value: i128) -> &'a mut Self {
self.sorted_map.insert(
Table::correct_key(key),
value.to_string(),
);
self
}
pub fn uint<'a>(&'a mut self, key: &'a str, value: u128) -> &'a mut Self {
self.sorted_map.insert(
Table::correct_key(key),
value.to_string(),
);
self
}
pub fn float<'a>(&'a mut self, key: &'a str, value: f64) -> &'a mut Self {
self.sorted_map.insert(
Table::correct_key(key),
value.to_string(),
);
self
}
pub fn bool<'a>(&'a mut self, key: &'a str, value: bool) -> &'a mut Self {
self.sorted_map.insert(
Table::correct_key(key),
value.to_string(),
);
self
}
}
pub struct Log {}
impl Log {
pub fn set_file_name(prefix: &str) {
if let Ok(mut logger) = LOGGER.lock() {
if !logger.file_name_important {
logger.file_prefix = prefix.to_string();
}
}
}
pub fn get_file_name() -> Result<String, String> {
match LOGGER.lock() {
Ok(logger) => Ok(logger.file_prefix.to_string()),
Err(e) => Err(e.to_string()),
}
}
pub fn set_file_name_important(prefix: &str) {
Log::set_file_name(prefix);
if let Ok(mut logger) = LOGGER.lock() {
logger.file_name_important = true;
}
}
pub fn set_file_ext(ext: Extension) {
if let Ok(mut logger) = LOGGER.lock() {
if !logger.file_ext_important {
match ext {
Extension::LogToml => {
logger.file_suffix = ".log".to_string();
logger.file_extension = ".toml".to_string();
}
Extension::Log => {
logger.file_suffix = "".to_string();
logger.file_extension = ".log".to_string();
}
}
}
}
}
pub fn set_file_ext_important(ext: Extension) {
Log::set_file_ext(ext);
if let Ok(mut logger) = LOGGER.lock() {
logger.file_ext_important = true;
}
}
pub fn get_file_ext_str() -> Result<String, String> {
match LOGGER.lock() {
Ok(logger) => Ok(format!("{}{}", logger.file_suffix, logger.file_extension)),
Err(e) => Err(e.to_string()),
}
}
pub fn set_level(level: Level) {
if let Ok(mut logger) = LOGGER.lock() {
if !logger.level_important {
logger.level = level;
}
}
}
pub fn set_level_important(level: Level) {
Log::set_level(level);
if let Ok(mut logger) = LOGGER.lock() {
logger.level_important = true;
}
}
pub fn get_level() -> Result<Level, String> {
match LOGGER.lock() {
Ok(logger) => Ok(logger.level),
Err(e) => Err(e.to_string()),
}
}
pub fn set_retention_days(days: u32) {
if let Ok(mut logger) = LOGGER.lock() {
if !logger.retention_days_important {
logger.retention_days = days as i64;
}
}
}
pub fn set_retention_days_important(retention_days: u32) {
Log::set_retention_days(retention_days);
if let Ok(mut logger) = LOGGER.lock() {
logger.retention_days_important = true;
}
}
pub fn get_retention_days() -> Result<u32, String> {
match LOGGER.lock() {
Ok(logger) => Ok(logger.retention_days as u32),
Err(e) => Err(e.to_string()),
}
}
pub fn set_timeout_secs(secs: u64) {
if let Ok(mut logger) = LOGGER.lock() {
if !logger.timeout_secs_important {
logger.timeout_secs = secs;
}
}
}
pub fn set_timeout_secs_important(secs: u64) {
Log::set_timeout_secs(secs);
if let Ok(mut logger) = LOGGER.lock() {
logger.timeout_secs_important = true;
}
}
pub fn get_timeout_secs() -> Result<u64, String> {
match LOGGER.lock() {
Ok(logger) => Ok(logger.timeout_secs),
Err(e) => Err(e.to_string()),
}
}
#[deprecated(
since = "0.4.7",
note = "Please use the casual_logger::Log::set_opt(Opt::Development) method instead"
)]
pub fn set_development(during_development: bool) {
if let Ok(opt_state) = OPT_STATE.lock() {
if !opt_state.opt_important {
if let Ok(mut logger) = LOGGER.lock() {
logger.development = during_development;
}
}
}
}
pub fn set_opt(optimization: Opt) {
if let Ok(mut opt_state) = OPT_STATE.lock() {
if !opt_state.opt_important {
opt_state.set(optimization);
}
}
}
pub fn set_opt_important(optimization: Opt) {
Log::set_opt(optimization);
if let Ok(mut opt_state) = OPT_STATE.lock() {
opt_state.opt_important = true;
}
}
pub fn get_opt() -> Result<Opt, String> {
match OPT_STATE.lock() {
Ok(opt_state) => Ok(opt_state.opt),
Err(e) => Err(e.to_string()),
}
}
pub fn remove_old_logs() -> usize {
let remove_num = if let Ok(logger) = LOGGER.lock() {
let remove_num = logger.remove_old_logs();
match Logger::get_optimization(&logger) {
Opt::Development => {
if 0 < remove_num {
println!("casual_logger: Remove {} log file(s).", remove_num);
}
}
_ => {}
}
remove_num
} else {
0
};
remove_num
}
#[deprecated(
since = "0.5.1",
note = "Please use the casual_logger::Log::flush() method instead"
)]
pub fn wait() {
Log::flush();
}
pub fn flush() {
let (timeout_secs, opt) = if let Ok(logger) = LOGGER.lock() {
(
Logger::get_timeout_sec(&logger),
Logger::get_optimization(&logger),
)
} else {
(0, Opt::BeginnersSupport)
};
Log::wait_for_logging_to_complete(timeout_secs, |secs, message| {
match opt {
Opt::Development => {
eprintln!("casual_logger: {} sec(s). {}", secs, message,);
}
_ => {}
}
});
}
fn print_message(queue_len: Option<usize>) -> String {
format!(
"{}",
if let Some(queue_len_val) = queue_len {
if 0 < queue_len_val {
format!("{} table(s) left. ", queue_len_val)
} else {
"".to_string()
}
} else {
"".to_string()
},
)
.trim_end()
.to_string()
}
#[deprecated(
since = "0.3.2",
note = "Please use the casual_logger::Log::flush() method instead"
)]
pub fn wait_for_logging_to_complete<F>(timeout_secs: u64, count_down: F)
where
F: Fn(u64, String),
{
let mut elapsed_milli_secs = 0;
thread::sleep(std::time::Duration::from_millis(20));
elapsed_milli_secs += 20;
let mut empty_que_count = 0;
while empty_que_count < 2 && elapsed_milli_secs < timeout_secs * 1000 {
let mut queue_len = None;
if let Ok(reserve_target) = RESERVE_TARGET.lock() {
if reserve_target.is_t() {
if let Ok(queue) = QUEUE_T.lock() {
if queue.is_empty() {
break;
}
queue_len = Some(queue.len());
}
} else {
if let Ok(queue) = QUEUE_F.lock() {
if queue.is_empty() {
break;
}
queue_len = Some(queue.len());
}
}
}
if let Some(completed) = Log::flush_target_queue() {
if completed {
empty_que_count = 0;
} else {
empty_que_count += 1;
}
} else {
empty_que_count = 0;
}
if elapsed_milli_secs % 1000 == 0 {
count_down(elapsed_milli_secs / 1000, Log::print_message(queue_len));
}
thread::sleep(std::time::Duration::from_millis(20));
elapsed_milli_secs += 20;
}
}
pub fn enabled(level: Level) -> bool {
if let Ok(logger) = LOGGER.lock() {
if logger.enabled(level) {
return true;
}
}
false
}
#[allow(dead_code)]
pub fn trace(message: &str) {
if Log::enabled(Level::Trace) {
Log::reserve(&Table::new(Level::Trace, message, false));
}
}
#[allow(dead_code)]
pub fn traceln(message: &str) {
if Log::enabled(Level::Trace) {
Log::reserve(&Table::new(Level::Trace, message, true));
}
}
#[allow(dead_code)]
pub fn trace_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Trace) {
table.level = Level::Trace;
table.message = message.to_string();
table.message_trailing_newline = false;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn traceln_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Trace) {
table.level = Level::Trace;
table.message = message.to_string();
table.message_trailing_newline = true;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn debug(message: &str) {
if Log::enabled(Level::Debug) {
Log::reserve(&Table::new(Level::Debug, message, false));
}
}
#[allow(dead_code)]
pub fn debugln(message: &str) {
if Log::enabled(Level::Debug) {
Log::reserve(&Table::new(Level::Debug, message, true));
}
}
#[allow(dead_code)]
pub fn debug_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Debug) {
table.level = Level::Debug;
table.message = message.to_string();
table.message_trailing_newline = false;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn debugln_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Debug) {
table.level = Level::Debug;
table.message = message.to_string();
table.message_trailing_newline = true;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn info(message: &str) {
if Log::enabled(Level::Info) {
Log::reserve(&Table::new(Level::Info, message, false));
}
}
#[allow(dead_code)]
pub fn infoln(message: &str) {
if Log::enabled(Level::Info) {
Log::reserve(&Table::new(Level::Info, message, true));
}
}
#[allow(dead_code)]
pub fn info_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Info) {
table.level = Level::Info;
table.message = message.to_string();
table.message_trailing_newline = false;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn infoln_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Info) {
table.level = Level::Info;
table.message = message.to_string();
table.message_trailing_newline = true;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn notice(message: &str) {
if Log::enabled(Level::Notice) {
Log::reserve(&Table::new(Level::Notice, message, false));
}
}
#[allow(dead_code)]
pub fn noticeln(message: &str) {
if Log::enabled(Level::Notice) {
Log::reserve(&Table::new(Level::Notice, message, true));
}
}
#[allow(dead_code)]
pub fn notice_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Notice) {
table.level = Level::Notice;
table.message = message.to_string();
table.message_trailing_newline = false;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn noticeln_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Notice) {
table.level = Level::Notice;
table.message = message.to_string();
table.message_trailing_newline = true;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn warn(message: &str) {
if Log::enabled(Level::Warn) {
Log::reserve(&Table::new(Level::Warn, message, false));
}
}
#[allow(dead_code)]
pub fn warnln(message: &str) {
if Log::enabled(Level::Warn) {
Log::reserve(&Table::new(Level::Warn, message, true));
}
}
#[allow(dead_code)]
pub fn warn_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Warn) {
table.level = Level::Warn;
table.message = message.to_string();
table.message_trailing_newline = false;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn warnln_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Warn) {
table.level = Level::Warn;
table.message = message.to_string();
table.message_trailing_newline = true;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn error(message: &str) {
if Log::enabled(Level::Error) {
Log::reserve(&Table::new(Level::Error, message, false));
}
}
#[allow(dead_code)]
pub fn errorln(message: &str) {
if Log::enabled(Level::Error) {
Log::reserve(&Table::new(Level::Error, message, true));
}
}
#[allow(dead_code)]
pub fn error_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Error) {
table.level = Level::Error;
table.message = message.to_string();
table.message_trailing_newline = false;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn errorln_t(message: &str, table: &mut Table) {
if Log::enabled(Level::Error) {
table.level = Level::Error;
table.message = message.to_string();
table.message_trailing_newline = true;
Log::reserve(table);
}
}
#[allow(dead_code)]
pub fn fatal(message: &str) -> String {
Log::reserve(&Table::new(Level::Fatal, message, false));
Log::flush();
message.to_string()
}
#[allow(dead_code)]
pub fn fatalln(message: &str) -> String {
Log::reserve(&Table::new(Level::Fatal, message, true));
Log::flush();
format!("{}{}", message, NEW_LINE).to_string()
}
#[allow(dead_code)]
pub fn fatal_t(message: &str, table: &mut Table) -> String {
table.level = Level::Fatal;
table.message = message.to_string();
table.message_trailing_newline = false;
Log::reserve(table);
Log::flush();
message.to_string()
}
#[allow(dead_code)]
pub fn fatalln_t(message: &str, table: &mut Table) -> String {
table.level = Level::Fatal;
table.message = message.to_string();
table.message_trailing_newline = true;
Log::reserve(table);
Log::flush();
format!("{}{}", message, NEW_LINE).to_string()
}
fn reserve(table: &Table) {
let seq = SEQ.with(move |seq| {
let old = *seq.borrow();
*seq.borrow_mut() += 1;
old
});
let internal_table =
InternalTable::new(&format!("{:?}", thread::current().id()), seq, &table);
if let Ok(reseve_target) = RESERVE_TARGET.lock() {
if reseve_target.is_t() {
if let Ok(mut queue) = QUEUE_T.lock() {
queue.push_front(internal_table);
}
} else {
if let Ok(mut queue) = QUEUE_F.lock() {
queue.push_front(internal_table);
}
}
} else {
return;
}
if let Ok(mut signal) = SIGNAL_CAN_FLUSH.lock() {
if signal.can_flush() {
signal.set_can_flush(false);
thread::spawn(move || {
Log::flush_target_queue();
});
}
}
}
fn flush_target_queue() -> Option<bool> {
let mut str_buf = String::new();
let flush_target = if let Ok(mut reserve_target) = RESERVE_TARGET.lock() {
let old = reserve_target.is_t();
reserve_target.switch();
old
} else {
return None;
};
let mut count = 0;
if flush_target {
if let Ok(mut queue) = QUEUE_T.lock() {
loop {
if let Some(internal_table) = queue.pop_back() {
str_buf.push_str(&Log::convert_table_to_string(&internal_table));
count += 1;
} else {
break;
}
}
} else {
}
} else {
if let Ok(mut queue) = QUEUE_F.lock() {
loop {
if let Some(internal_table) = queue.pop_back() {
str_buf.push_str(&Log::convert_table_to_string(&internal_table));
count += 1;
} else {
break;
}
}
} else {
}
}
if let Ok(mut logger) = LOGGER.lock() {
let mut file_buf = BufWriter::new(logger.current_file());
if let Err(_why) = file_buf.write_all(str_buf.as_bytes()) {
return None;
}
if let Ok(mut signal) = SIGNAL_CAN_FLUSH.lock() {
signal.set_can_flush(true);
}
}
Some(0 < count)
}
fn convert_table_to_string(wrapper: &InternalTable) -> String {
let message = if wrapper.table.message_trailing_newline {
format!("{}{}", wrapper.table.message, NEW_LINE)
} else {
wrapper.table.message.to_string()
};
let mut toml = format!(
"[\"Now={}&Pid={}&Thr={}&Seq={}\"]
{} = {}
",
Local::now().format("%Y-%m-%d %H:%M:%S"),
process::id(),
wrapper.thread_id,
wrapper.seq,
wrapper.table.level,
Table::format_str_value(&message)
)
.to_string();
for (k, formatted_v) in &wrapper.table.sorted_map {
toml.push_str(&format!(
"{} = {}
",
k, formatted_v
));
}
toml.push_str(
"
",
);
toml
}
}
#[deprecated(
since = "0.4.0",
note = "Please use the casual_logger::Log::xxxx() methods instead"
)]
pub struct Logger {
file_name_important: bool,
file_prefix: String,
file_ext_important: bool,
file_suffix: String,
file_extension: String,
level_important: bool,
#[deprecated(
since = "0.3.7",
note = "Please use the casual_logger::Log::set_level() method instead"
)]
pub level: Level,
retention_days_important: bool,
#[deprecated(
since = "0.3.8",
note = "Please use the casual_logger::Log::set_retention_days() method instead"
)]
pub retention_days: i64,
timeout_secs_important: bool,
#[deprecated(
since = "0.3.9",
note = "Please use the casual_logger::Log::set_timeout_secs() method instead"
)]
pub timeout_secs: u64,
#[deprecated(
since = "0.3.2",
note = "Please use the casual_logger::Log::set_timeout_secs() method instead"
)]
pub fatal_timeout_secs: u64,
#[deprecated(
since = "0.3.10",
note = "Please use the casual_logger::Log::set_opt(Opt::Development) method instead"
)]
pub development: bool,
log_file: Option<LogFile>,
}
impl Default for Logger {
fn default() -> Self {
let prefix = "default";
let suffix = ".log";
let extension = ".toml";
Logger {
file_name_important: false,
file_prefix: prefix.to_string(),
file_ext_important: false,
file_suffix: suffix.to_string(),
file_extension: extension.to_string(),
level_important: false,
level: Level::Trace,
retention_days_important: false,
retention_days: 7,
timeout_secs_important: false,
timeout_secs: 30,
fatal_timeout_secs: 30,
development: false,
log_file: None,
}
}
}
impl Logger {
fn get_timeout_sec(logger: &Logger) -> u64 {
if logger.timeout_secs != 30 {
logger.timeout_secs
} else if logger.fatal_timeout_secs != 30 {
logger.fatal_timeout_secs
} else {
logger.timeout_secs
}
}
fn get_optimization(logger: &Logger) -> Opt {
if logger.development == true {
Opt::Development
} else {
if let Ok(opt_state) = OPT_STATE.lock() {
opt_state.get()
} else {
Opt::BeginnersSupport
}
}
}
pub fn enabled(&self, level: Level) -> bool {
if level.number() <= self.level.number() {
return true;
}
false
}
#[deprecated(
since = "0.5.2",
note = "Please use the casual_logger::Log::get_file_name() method instead"
)]
#[allow(dead_code)]
pub fn get_file_prefix(&self) -> &str {
&self.file_prefix
}
#[allow(dead_code)]
pub fn get_file_suffix(&self) -> &str {
&self.file_suffix
}
#[allow(dead_code)]
pub fn get_file_extension(&self) -> &str {
&self.file_extension
}
#[deprecated(
since = "0.3.6",
note = "Please use the casual_logger::Log::set_file_name() or casual_logger::Log::set_toml_ext() method instead"
)]
#[allow(dead_code)]
pub fn set_file_name(&mut self, prefix: &str, suffix: &str, extension: &str) {
if !self.file_name_important {
self.file_prefix = prefix.to_string();
}
if !self.file_ext_important {
self.file_suffix = suffix.to_string();
self.file_extension = extension.to_string();
}
}
fn new_today_file(
file_prefix: &str,
file_suffix: &str,
file_extension: &str,
) -> (Date<Local>, File) {
let start_date = Local::today();
let file = OpenOptions::new()
.create(true)
.append(true)
.open(Path::new(&format!(
"{}-{}{}{}",
file_prefix,
start_date.format("%Y-%m-%d"),
file_suffix,
file_extension
)))
.unwrap();
(start_date, file)
}
#[deprecated(
since = "0.3.3",
note = "Please use the casual_logger::Log::remove_old_logs() method instead"
)]
pub fn remove_old_logs(&self) -> usize {
let mut count = 0;
let re = if let Ok(x) = Regex::new(&format!(
"./{}-{}{}{}",
self.file_prefix, r"(\d{4})-(\d{2})-(\d{2})", self.file_suffix, self.file_extension
)) {
x
} else {
return 0;
};
let paths = if let Ok(x) = fs::read_dir("./") {
x
} else {
return 0;
};
for path in paths {
let name = if let Ok(x) = path {
x.path().display().to_string()
} else {
continue;
};
if let Some(caps) = re.captures(&name) {
let year: i32 = if let Some(cap) = caps.get(1) {
if let Ok(n) = cap.as_str().parse() {
n
} else {
0
}
} else {
0
};
let month: u32 = if let Some(cap) = caps.get(2) {
if let Ok(n) = cap.as_str().parse() {
n
} else {
0
}
} else {
0
};
let day: u32 = if let Some(cap) = caps.get(3) {
if let Ok(n) = cap.as_str().parse() {
n
} else {
0
}
} else {
0
};
if month != 0 && day != 0 {
let file_date = Local.ymd(year, month, day);
if file_date.add(Duration::days(self.retention_days)) < Local::today() {
if let Ok(_why) = fs::remove_file(name) {
count += 1;
}
}
}
}
}
count
}
fn current_file(&mut self) -> &File {
let date_changed = if let Some(log_file) = &self.log_file {
log_file.start_date < Local::today()
} else {
false
};
if date_changed {
self.log_file = None;
}
if let None = self.log_file {
let (start_date, file) =
Logger::new_today_file(&self.file_prefix, &self.file_suffix, &self.file_extension);
self.log_file = Some(LogFile::new(start_date, file));
}
&self.log_file.as_ref().unwrap().file
}
}
struct LogFile {
pub start_date: Date<Local>,
pub file: File,
}
impl LogFile {
pub fn new(start_date: Date<Local>, file: File) -> Self {
LogFile {
start_date: start_date,
file: file,
}
}
}
pub enum Extension {
Log,
LogToml,
}
#[derive(Clone, Copy)]
struct ReserveTarget {
target: bool,
}
impl Default for ReserveTarget {
fn default() -> Self {
ReserveTarget { target: false }
}
}
impl ReserveTarget {
fn is_t(self) -> bool {
self.target
}
fn switch(&mut self) {
self.target = !self.target;
}
}
struct SignalCanFlush {
can_flush: bool,
}
impl Default for SignalCanFlush {
fn default() -> Self {
SignalCanFlush { can_flush: true }
}
}
impl SignalCanFlush {
pub fn can_flush(&self) -> bool {
self.can_flush
}
pub fn set_can_flush(&mut self, val: bool) {
self.can_flush = val;
}
}
#[derive(Clone, Copy, Debug)]
pub enum Opt {
Development,
BeginnersSupport,
Release,
}
struct OptState {
opt_important: bool,
opt: Opt,
}
impl Default for OptState {
fn default() -> Self {
OptState {
opt_important: false,
opt: Opt::BeginnersSupport,
}
}
}
impl OptState {
fn get(&self) -> Opt {
self.opt
}
fn set(&mut self, val: Opt) {
self.opt = val;
}
}