estk / log4rs

A highly configurable logging framework for Rust
Apache License 2.0
973 stars 143 forks source link

Redirect to a custom function using a custom appender #330

Open adrien3d opened 7 months ago

adrien3d commented 7 months ago

I have already a log4rs configuration that outputs logs to console and to a file, but I want to be able to use a custom function that will output to a websocket. My configuration:

    log::set_logger(&crate::logger::LOGGER);
    let console_logs = console::ConsoleAppender::builder()
        .encoder(Box::new(pattern::PatternEncoder::new(
            "{h({d(%Y-%m-%dT%H:%M:%S%.3f)(utc)} [{l}]\t {m}{n})}",
        )))
        .build();
    // Build file appender to log console outputs in a file
    let log_file = file::FileAppender::builder()
        .encoder(Box::new(pattern::PatternEncoder::new(
            "{h({d(%Y-%m-%dT%H:%M:%S%.3f)(utc)} [{l}]\t {m}{n})}",
        )))
        .build(my_path)?;

    // Log at the argument specified level with Info as the default level for the logger.
    let config = Config::builder()
        .appender(Appender::builder().build("file_logs", Box::new(log_file)))
        .appender(Appender::builder().build("console_logs", Box::new(console_logs)))
        .logger(Logger::builder().build(
            "hyper",
            log_level.min(if reduce_db_logs {
                LevelFilter::Info
            } else {
                log_level
            }),
        ))
        .build(
            Root::builder()
                .appender("file_logs")
                .appender("console_logs")
                .build(log_level),
        )?;

    log4rs::init_config(config)?;

I have tried to build a custom logger:

pub static LOGGER: MyLogger = MyLogger ;
pub struct MyLogger;
impl log::Log for MyLogger {
    fn enabled(&self, _: &log::Metadata) -> bool {
        true
    }

    fn log(&self, record: &log::Record) {
        //let now = crate::ntp::Ntp::current_time(&self)
        if self.enabled(record.metadata()) {
            println!("My logger: {} - {}", record.level(), record.args());
        }
    }

    fn flush(&self) {}
}

But I am struggling to be able to call the custom logger with log4rs or log, it does not even compiles:

env_logger::init should not be called after logger initialized: SetLoggerError(())

Any idea on how to simply being able to access log level and content to call another function, while keeping logging on console and on file?