How to write logs to multiple destinations conditionally with tracing?

3.7k Views Asked by At

I'm try to implement some centralized logging with the tracing crate. I can write to a rolling file with the tracing-appender crate or to a Graylog application with the following code:

let mut guards = Vec::new();
if let Some(log) = config.logs {
    if let Some(file) = log.file {
        let file_appender = tracing_appender::rolling::hourly(file.directory, file.filename);
        let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
        guards.push(guard);
        let file_logger = tracing_subscriber::fmt()
            .with_writer(non_blocking)
            .init();
    }

    if let Some(graylog) = log.graylog {
        let address: SocketAddr = graylog.host.parse().expect("Unable to parse graylog host address");
        let bg_task = Logger::builder()
            .additional_field("module_id", graylog.module_id)
            .init_tcp(address)
            .unwrap();

        tokio::spawn(bg_task);
    }
}

If the log configuration contains only one of .file or .graylog definition it works, but if I define both the application crashes at startup.

I think there is a conflict because both are trying to set default collector. There is any way to define both to accept every spans and events?

1

There are 1 best solutions below

3
On BEST ANSWER

You can use Option<Layer> in with when composing layers:

let mut guards = Vec::new();
if let Some(log) = config.logs {
    let file_log = if let Some(file) = log.file {
        let file_appender = tracing_appender::rolling::hourly(file.directory, file.filename);
        let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
        guards.push(guard);
        Some(fmt::Layer::new().with_writer(non_blocking))
    } else {
        None
    };

    let grey_log = if let Some(graylog) = log.graylog {
        let address: SocketAddr = graylog
            .host
            .parse()
            .expect("Unable to parse graylog host address");
        let (layer, task) = tracing_gelf::Logger::builder().connect_tcp(address)?;
        tokio::spawn(task);
        Some(layer)
    } else {
        None
    };

    let mut subscriber = tracing_subscriber::registry()
        .with(EnvFilter::...)
        .with(file_log)
        .with(grey_log);
}