ironlog 0.2.7

A web logger for multi-node system logging
Documentation
use log::{Metadata, Record};
use serde::Serialize;
use std::io::Write;
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use chrono::Utc;

#[derive(Serialize)]
struct LogMessage<'a> {
    timestamp: String,
    level: String,
    message: String,
    target: &'a str,
    module_path: Option<&'a str>,
    file: Option<&'a str>,
    line: Option<u32>,
    hash: String,
}

pub struct TcpLogger {
    server_addr: String,
    hash: String,
    stream: Arc<Mutex<TcpStream>>,
}

impl TcpLogger {
    pub fn init(server_addr: &str, hash: &str, level: log::LevelFilter) -> Result<(), log::SetLoggerError> {
        let stream = TcpStream::connect(server_addr).expect("Could not connect to log server");
        let logger = TcpLogger {
            server_addr: server_addr.to_string(),
            hash: hash.to_string(),
            stream: Arc::new(Mutex::new(stream)),
        };
        log::set_boxed_logger(Box::new(logger))?;
        log::set_max_level(level);
        Ok(())
    }

    pub fn new(server_addr: &str, hash: &str, _use_system_logger: bool) -> Result<Self, std::io::Error> {
        let stream = TcpStream::connect(server_addr)?;
        Ok(TcpLogger {
            server_addr: server_addr.to_string(),
            hash: hash.to_string(),
            stream: Arc::new(Mutex::new(stream)),
        })
    }

    pub fn info(&self, message: &str) {
        self.log_message(log::Level::Info, message);
    }

    pub fn error(&self, message: &str) {
        self.log_message(log::Level::Error, message);
    }

    pub fn debug(&self, message: &str) {
        self.log_message(log::Level::Debug, message);
    }

    pub fn warn(&self, message: &str) {
        self.log_message(log::Level::Warn, message);
    }

    fn log_message(&self, level: log::Level, message: &str) {
        let log_message = LogMessage {
            timestamp: Utc::now().to_rfc3339(),
            level: level.to_string(),
            message: message.to_string(),
            target: "independent_logger",
            module_path: None,
            file: None,
            line: None,
            hash: self.hash.clone(),
        };

        if let Ok(json) = serde_json::to_string(&log_message) {
            let mut stream = self.stream.lock().unwrap();
            if let Err(e) = writeln!(stream, "{}", json) {
                eprintln!("Failed to send log: {}", e);
            }
        }
    }
}

impl log::Log for TcpLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= log::max_level()
    }

    fn log(&self, record: &Record) {
        if self.enabled(record.metadata()) {
            let log_message = LogMessage {
                timestamp: Utc::now().to_rfc3339(),
                level: record.level().to_string(),
                message: record.args().to_string(),
                target: record.target(),
                module_path: record.module_path_static(),
                file: record.file_static(),
                line: record.line(),
                hash: self.hash.clone(),
            };
            if let Ok(json) = serde_json::to_string(&log_message) {
                let mut stream = self.stream.lock().unwrap();
                if let Err(e) = writeln!(stream, "{}", json) {
                    eprintln!("Failed to send log: {}", e);
                }
            }
        }
    }

    fn flush(&self) {}
}

pub mod config;
pub mod client_handler;
pub mod types;