Skip to content

Dynamically add more log layers at run-time #2499

@emilk

Description

@emilk

Feature Request

Crates

tracing-subscriber

Motivation

There are many places I want to pipe my log events:

  • stderr
  • a log file
  • The GUI
  • the network

These can all be implemented as Layers.

The first thing I want to add is the stderr and file layers. The GUI and the network layers I want to add later once the GUI and network connections are up and running. That way any problems with the GUI/network setup is properly logged to stdout and to file.

In other words: I want to dynamically add layers as the program runs.

Proposal

I propose some sort of simple API along the lines of tracing_subscriber::registry().add(layer);

Prior art

My own C++ logging Loguru has a simple method for adding new log sinks (https://emilk.github.io/loguru/index.html#callbacks):

loguru::add_callback("network_logger", user_data, logging_function, loguru::Verbosity_INFO);

This lets different sub-modules of an application can easily add new log sinks at will.

Alternatives

As I was trying to get this work, several helpful people on Discord pointed me towards tracing_subscriber::reload.

I've tried to get it to work, but so far I've failed. My code thus far:

use tracing_subscriber::prelude::*;

let stdout_layer = tracing_subscriber::fmt::layer().with_filter(tracing_subscriber::EnvFilter::from_default_env());
    
let tracing_layers: Vec<Box<dyn tracing_subscriber::layer::Layer<_> + 'static> = vec![Box::new(stdout_layer)];
let (tracing_layers, reload_handle) = tracing_subscriber::reload::Layer::new(tracing_layers);
tracing_subscriber::registry().with(tracing_layers).init();

// set up GUI or network connect or similar, then:

reload_handle.modify(|layers| {
    let gui_layer = GuiLayer::new(gui_handle);
    layers.push(Box::new(gui_layer));
});

There are several issues with this approach:

  • It is using a lot of different features that are hard to find ("Vec implements Layer!")
  • It is too difficult to use (I can't get it to compile)
  • It requires one to keep track of the reload_handle
  • It is VERY verbose

Perhaps all the above issues could be solved by an tracing_subscriber expert plus a little bit of documentation. I don't know - I'm not an expert :)

The error message for the above code:

 1  error[E0277]: the size for values of type `dyn tracing_subscriber::Layer<tracing_subscriber::Registry>` cannot be known at compilation time                                                                                              ▐
     --> examples/rust/api_demo/src/main.rs:652:41                                                                                                                                                                                           ▐
      |                                                                                                                                                                                                                                      ▐
 652  |     tracing_subscriber::registry().with(tracing_layers).init();
      |                                    ---- ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
      |                                    |
      |                                    required by a bound introduced by this call
      |
      = help: the trait `std::marker::Sized` is not implemented for `dyn tracing_subscriber::Layer<tracing_subscriber::Registry>`
      = help: the trait `tracing_subscriber::Layer<S>` is implemented for `tracing_subscriber::reload::Layer<L, S>`
      = note: required for `std::boxed::Box<dyn tracing_subscriber::Layer<tracing_subscriber::Registry>>` to implement `tracing_subscriber::Layer<tracing_subscriber::Registry>`
      = note: 2 redundant requirements hidden
      = note: required for `tracing_subscriber::reload::Layer<std::vec::Vec<std::boxed::Box<dyn tracing_subscriber::Layer<...>>>, ...>` to implement `tracing_subscriber::Layer<tracing_subscriber::Registry>`
      = note: the full type name has been written to '/Users/emilk/code/rerun/rerun/target/debug/deps/api_demo-118a8d78b3eddbda.long-type-14231036155949571826.txt'
 note: required by a bound in `tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt::with`
     --> /Users/emilk/.cargo/registry/src/github.com-1ecc6299db9ec823/tracing-subscriber-0.3.16/src/layer/mod.rs:1485:12
      |
 1485 |         L: Layer<Self>,
      |            ^^^^^^^^^^^ required by this bound in `tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt::with`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions