mod log;
pub use log::init_on_addr;
use chrono::Local;
use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{self, Sender};
use std::thread;
use std::time::Duration;
pub struct Logger {
tx: Sender<String>,
}
impl Logger {
pub fn new(address: &str) -> Self {
let (tx, rx) = mpsc::channel::<String>();
let addr = address.to_string();
thread::spawn(move || {
let mut stream = tcp_connect(&addr);
while let Ok(msg) = rx.recv() {
send_str_retry(&mut stream, &addr, &msg);
}
});
Self { tx }
}
pub fn log(&self, message: &str) {
let formatted = format_log(message);
self.log_raw(formatted);
}
pub fn log_raw(&self, message: impl ToString) {
if let Err(e) = self.tx.send(message.to_string()) {
eprintln!("Error sending message to queue: {e}");
}
}
}
fn send_str_retry(stream: &mut TcpStream, addr: &str, message: &str) {
if let Err(e) = stream.write_all(message.as_bytes()) {
eprintln!("Error sending log: {e}, reconnecting...");
*stream = tcp_connect(addr);
if let Err(e) = stream.write_all(message.as_bytes()) {
eprintln!("Failed to send log after reconnect: {e}");
}
}
}
fn tcp_connect(addr: &str) -> TcpStream {
loop {
match TcpStream::connect(addr) {
Ok(s) => break s,
Err(e) => {
eprintln!("Error connecting to server: {e}, retrying in 1s...");
thread::sleep(Duration::from_secs(1));
}
}
}
}
fn format_log(message: &str) -> String {
let timestamp = Local::now().format("[%Y-%m-%d %H:%M:%S]").to_string();
format!("\x1b[90m{timestamp}\x1b[0m {message}\n")
}