use super::{msg::LogMessage, position, LogLevel, Setting};
use chrono::FixedOffset;
#[cfg(not(feature = "async"))]
use std::fs::{self, File};
#[cfg(not(feature = "async"))]
use std::io::Write;
#[cfg(feature = "async")]
use tokio::fs::{self, File};
#[cfg(feature = "async")]
use tokio::io::AsyncWriteExt;
#[derive(Debug)]
pub struct Logger {
file: Option<File>,
current_index: usize,
used_length: usize,
current_file_prefix: String,
init: bool,
setting: Setting,
}
impl Logger {
pub(crate) fn new() -> Self {
let setting = Setting {
..Default::default()
};
let mut buffer = Self {
file: None,
current_index: 0,
used_length: 0,
init: false,
current_file_prefix: format!(
"{}",
chrono::Utc::now()
.with_timezone(&FixedOffset::east_opt(setting.time_zone * 3600).unwrap())
.format(&setting.file_time_format)
),
setting,
};
buffer.check_dir();
buffer.current_index = buffer.get_index_not_async(&buffer.current_file_prefix);
buffer
}
fn get_path(&self, time_prefix: &str, index: usize) -> String {
format!("{}/{}_{}.log", self.setting.dir_path, time_prefix, index)
}
pub(crate) fn disable(&mut self) {
self.setting.disabled = true;
}
pub(crate) fn enable(&mut self) {
self.setting.disabled = false;
}
fn get_index_not_async(&self, time_prefix: &str) -> usize {
let mut count = 0;
loop {
let path = self.get_path(time_prefix, count);
if let Ok(_) = std::fs::File::open(path) {
count += 1
} else {
return count;
}
}
}
fn check_dir(&self) {
if !std::path::Path::new(&self.setting.dir_path).exists() {
std::fs::create_dir(&self.setting.dir_path).expect("Failed to create directory");
}
}
}
#[cfg(feature = "async")]
impl Logger {
pub(crate) async fn init(&mut self, setting: Setting) {
if self.init {
let position = position!().to_string();
self.warn("Log writer had been initialized!", position)
.await;
return;
}
self.file = None;
self.used_length = 0;
self.setting = setting;
self.init = true;
self.current_file_prefix = format!(
"{}",
chrono::Utc::now()
.with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
.format("%Y-%m-%d")
);
self.current_index = self.get_index(&self.current_file_prefix).await;
}
pub(crate) async fn clear_dir(&mut self) {
fs::remove_dir_all(&self.setting.dir_path)
.await
.expect("Cannot remove the dir.");
fs::create_dir(&self.setting.dir_path)
.await
.expect("Cannot create the dir.");
self.current_index = 0;
self.used_length = 0;
self.file = None;
}
async fn write(&mut self, msg: &LogMessage) {
if self.setting.disabled {
return;
}
for i in msg.split_enter() {
if self.file.is_none() {
self.file = Some(self.get_file().await);
}
let time_prefix = format!(
"{}",
chrono::Utc::now()
.with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
.format("%Y-%m-%d")
);
if self.current_file_prefix != time_prefix {
self.current_file_prefix = time_prefix;
self.current_index = self.get_index(&self.current_file_prefix).await;
self.used_length = 0;
self.file = Some(self.get_file().await);
};
if self.setting.print_out
&& self.setting.terminal_print_level.get_level() <= i.get_level()
{
println!("{}", i.print())
};
if self.setting.file_record_level.get_level() <= i.get_level() {
self.file
.as_mut()
.unwrap()
.write_all((i.print() + "\n").as_bytes())
.await
.expect("Cannot write into the log file.");
self.used_length += 1;
};
}
if self.setting.single_length != 0 && self.used_length >= self.setting.single_length {
self.current_index += 1;
self.used_length = 0;
self.file = None;
}
}
pub async fn record(&mut self, log_level: LogLevel, message: &str, position: String) {
if !self.init {
self.init = true
}
let mut msg = LogMessage::new(
log_level,
message.to_string(),
self.setting.time_zone,
position,
);
msg.time.detailed_display = self.setting.time_detailed_display;
self.write(&msg).await;
}
pub async fn info(&mut self, message: &str, position: String) {
self.record(LogLevel::Info, message, position).await;
}
pub async fn debug(&mut self, message: &str, position: String) {
self.record(LogLevel::Debug, message, position).await;
}
pub async fn warn(&mut self, message: &str, position: String) {
self.record(LogLevel::Warn, message, position).await;
}
pub async fn error(&mut self, message: &str, position: String) {
self.record(LogLevel::Error, message, position).await;
}
pub async fn trace(&mut self, message: &str, position: String) {
self.record(LogLevel::Trace, message, position).await;
}
async fn get_file(&self) -> File {
let path = self.get_path(&self.current_file_prefix, self.current_index);
File::options()
.read(true)
.write(true)
.create_new(true)
.open(path)
.await
.expect("Cannot create the log file.")
}
async fn get_index(&self, time_prefix: &str) -> usize {
let mut count = 0;
loop {
let path = self.get_path(time_prefix, count);
if let Ok(_) = File::open(path).await {
count += 1
} else {
return count;
}
}
}
}
#[cfg(not(feature = "async"))]
impl Logger {
pub(crate) fn init(&mut self, setting: Setting) {
if self.init {
let position = position!().to_string();
self.warn("Log writer had been initialized!", position);
return;
}
self.file = None;
self.used_length = 0;
self.setting = setting;
self.init = true;
self.current_file_prefix = format!(
"{}",
chrono::Utc::now()
.with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
.format("%Y-%m-%d")
);
self.current_index = self.get_index(&self.current_file_prefix);
}
pub(crate) fn clear_dir(&mut self) {
fs::remove_dir_all(&self.setting.dir_path).expect("Cannot remove the dir.");
fs::create_dir(&self.setting.dir_path).expect("Cannot create the dir.");
self.current_index = 0;
self.used_length = 0;
self.file = None;
self.current_file_prefix = format!(
"{}",
chrono::Utc::now()
.with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
.format(&self.setting.file_time_format)
);
}
fn write(&mut self, msg: &LogMessage) {
if self.setting.disabled {
return;
}
if self.file.is_none() {
self.file = Some(self.get_file());
}
for i in msg.split_enter() {
let time_prefix = format!(
"{}",
chrono::Utc::now()
.with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
.format("%Y-%m-%d")
);
if self.current_file_prefix != time_prefix {
self.current_file_prefix = time_prefix;
self.current_index = self.get_index(&self.current_file_prefix);
self.used_length = 0;
self.file = Some(self.get_file());
};
if self.setting.print_out
&& self.setting.terminal_print_level.get_level() <= i.get_level()
{
println!("{}", i.print())
};
if self.setting.file_record_level.get_level() <= i.get_level() {
self.file
.as_mut()
.unwrap()
.write_all((i.print() + "\n").as_bytes())
.expect("Cannot write into the log file.");
self.used_length += 1;
};
}
if self.setting.single_length != 0 && self.used_length >= self.setting.single_length {
self.current_index += 1;
self.used_length = 0;
self.file = None;
}
}
pub fn record(&mut self, log_level: LogLevel, message: &str, position: String) {
if !self.init {
self.init = true
}
let mut msg = LogMessage::new(
log_level,
message.to_string(),
self.setting.time_zone,
position,
);
msg.time.detailed_display = self.setting.time_detailed_display;
self.write(&msg);
}
pub fn info(&mut self, message: &str, position: String) {
self.record(LogLevel::Info, message, position);
}
pub fn debug(&mut self, message: &str, position: String) {
self.record(LogLevel::Debug, message, position);
}
pub fn warn(&mut self, message: &str, position: String) {
self.record(LogLevel::Warn, message, position);
}
pub fn error(&mut self, message: &str, position: String) {
self.record(LogLevel::Error, message, position);
}
pub fn trace(&mut self, message: &str, position: String) {
self.record(LogLevel::Trace, message, position);
}
fn get_index(&self, time_prefix: &str) -> usize {
let mut count = 0;
loop {
let path = self.get_path(time_prefix, count);
if let Ok(_) = File::open(path) {
count += 1
} else {
return count;
}
}
}
fn get_file(&self) -> File {
let path = self.get_path(&self.current_file_prefix, self.current_index);
File::options()
.read(true)
.write(true)
.create_new(true)
.open(path)
.expect("Cannot create the log file.")
}
}
unsafe impl Send for Logger {}