use std::fs::create_dir_all;
use std::io::Result;
use std::path::Path;
use log::LevelFilter;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use crate::helper::types::{ContigFmt, DataType, InputFmt, SeqReadFmt};
use crate::helper::utils;
pub const LOG_FILE: &str = "segul.log";
pub fn init_logger(file_path: &Path) -> Result<()> {
if let Some(dir) = file_path.parent() {
create_dir_all(dir)?;
}
let target = file_path.with_extension("log");
let tofile = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(
"{d(%Y-%m-%d %H:%M:%S %Z)} - {l} - {m}\n",
)))
.build(target)?;
let stdout = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::new("{m}\n")))
.build();
let config = Config::builder()
.appender(Appender::builder().build("stdout", Box::new(stdout)))
.appender(Appender::builder().build("logfile", Box::new(tofile)))
.build(
Root::builder()
.appender("stdout")
.appender("logfile")
.build(LevelFilter::Info),
)
.expect("Failed building log configuration");
log4rs::init_config(config).expect("Cannot initiate log configuration");
Ok(())
}
pub fn init_file_logger(file_path: &Path) -> Result<()> {
if let Some(dir) = file_path.parent() {
create_dir_all(dir)?;
}
let target = file_path.with_extension("log");
let tofile = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(
"{d(%Y-%m-%d %H:%M:%S %Z)} - {l} - {m}\n",
)))
.build(target)
.expect("Failed building log file");
let config = Config::builder()
.appender(Appender::builder().build("logfile", Box::new(tofile)))
.build(Root::builder().appender("logfile").build(LevelFilter::Info))
.expect("Failed building log configuration");
log4rs::init_config(config).expect("Cannot initiate log configuration");
Ok(())
}
pub fn strip_color(text: &str) -> String {
let re = regex::Regex::new(r"\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]").expect("Failed regex");
re.replace_all(text, "").to_string()
}
trait InputLogger {
fn log_input_info(&self) {}
}
impl InputLogger for ReadLogger<'_> {
fn log_input_info(&self) {
if let Some(input) = self.input {
log::info!("{:18}: {}", "Input dir", &input.display());
} else {
log::info!("{:18}: {}", "Input path", "STDIN");
}
log::info!("{:18}: {}", "File counts", utils::fmt_num(&self.fcounts));
}
}
pub struct ReadLogger<'a> {
pub input: Option<&'a Path>,
pub input_fmt: &'a SeqReadFmt,
pub fcounts: usize,
}
impl<'a> ReadLogger<'a> {
pub fn new(input: Option<&'a Path>, input_fmt: &'a SeqReadFmt, fcounts: usize) -> Self {
Self {
input,
input_fmt,
fcounts,
}
}
pub fn log(&self, task: &str) {
self.log_input_info();
log::info!("{:18}: {}\n", "Input format:", self.input_fmt);
log::info!("{:18}: {}\n", "Task", task);
}
}
impl InputLogger for ContigLogger<'_> {
fn log_input_info(&self) {
if let Some(input) = self.input {
log::info!("{:18}: {}", "Input dir", &input.display());
} else {
log::info!("{:18}: {}", "Input path", "STDIN");
}
log::info!("{:18}: {}", "File counts", utils::fmt_num(&self.fcounts));
}
}
pub struct ContigLogger<'a> {
pub input: Option<&'a Path>,
pub input_fmt: &'a ContigFmt,
pub fcounts: usize,
}
impl<'a> ContigLogger<'a> {
pub fn new(input: Option<&'a Path>, input_fmt: &'a ContigFmt, fcounts: usize) -> Self {
Self {
input,
input_fmt,
fcounts,
}
}
pub fn log(&self, task: &str) {
self.log_input_info();
log::info!("{:18}: {}\n", "Input format:", self.input_fmt);
log::info!("{:18}: {}\n", "Task", task);
}
}
impl InputLogger for AlignSeqLogger<'_> {
fn log_input_info(&self) {
if let Some(input) = self.input {
log::info!("{:18}: {}", "Input dir", &input.display());
} else {
log::info!("{:18}: {}", "Input path", "STDIN");
}
log::info!("{:18}: {}", "File counts", utils::fmt_num(&self.fcounts));
}
}
pub struct AlignSeqLogger<'a> {
pub input: Option<&'a Path>,
pub input_fmt: &'a InputFmt,
pub datatype: &'a DataType,
pub fcounts: usize,
}
impl<'a> AlignSeqLogger<'a> {
pub fn new(
input: Option<&'a Path>,
input_fmt: &'a InputFmt,
datatype: &'a DataType,
fcounts: usize,
) -> Self {
Self {
input,
input_fmt,
datatype,
fcounts,
}
}
pub fn log(&self, task: &str) {
self.log_input_info();
self.log_seq_input_fmt();
self.log_seq_datatype();
log::info!("{:18}: {}\n", "Task", task);
}
fn log_seq_datatype(&self) {
match self.datatype {
DataType::Aa => log::info!("{:18}: {}", "Data type", "Amino Acid"),
DataType::Dna => log::info!("{:18}: {}", "Data type", "DNA"),
DataType::Ignore => log::info!("{:18}: {}", "Data type", "Ignore"),
}
}
fn log_seq_input_fmt(&self) {
match self.input_fmt {
InputFmt::Auto => log::info!("{:18}: {}", "Input format", "Auto"),
InputFmt::Fasta => log::info!("{:18}: {}", "Input format", "FASTA"),
InputFmt::Nexus => log::info!("{:18}: {}", "Input format", "NEXUS"),
InputFmt::Phylip => log::info!("{:18}: {}", "Input format", "PHYLIP"),
}
}
}
pub fn log_input_partition(input: Option<&Path>, input_counts: usize) {
match input {
Some(input) => log::info!("{:18}: {}", "Input dir", input.display()),
None => log::info!("{:18}: {}", "Input path", "STDIN"),
}
log::info!("{:18}: {}", "File counts", utils::fmt_num(&input_counts));
log::info!("{:18}: {}\n", "Task", "Converting partitions");
}