-
Notifications
You must be signed in to change notification settings - Fork 715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamically add more log layers at run-time #2499
Comments
Hayden helped me on Discord to get it to compile: fn tracing_init() {
use tracing_subscriber::prelude::*;
use tracing_subscriber::{filter, fmt, registry, reload};
let stdout_layer = fmt::Layer::default()
.with_filter(filter::LevelFilter::INFO)
.boxed();
let tracing_layers = vec![stdout_layer];
let (tracing_layers, reload_handle) = reload::Layer::new(tracing_layers);
registry().with(tracing_layers).init();
tracing::info!("before reload");
let reload_result = reload_handle.modify(|layers| {
let json_layer = fmt::Layer::default()
.json()
.with_filter(filter::LevelFilter::INFO)
.boxed();
(*layers).push(json_layer);
});
match reload_result {
Ok(_) => {} // Great!
Err(err) => tracing::warn!("Unable to add new layer: {}", err),
}
tracing::info!("after reload");
} But according to Hayden, it panics at runtime, so this is still an issue. |
emilk
changed the title
A simple way to dynamicall add more log layers at run-time
Dynamically add more log layers at run-time
Mar 11, 2023
+1, I've run into this when adding https://github.com/tokio-rs/tracing-opentelemetry to an existing app. It has an early |
type SimplifiedHandle = reload::Handle<
LevelFilter,
fmt::Layer<Registry, DefaultFields, Format<Full, SystemTime>, Stdout>,
>;
lazy_static! {
static ref RELOAD_HANDLE: Option<SimplifiedHandle> = None;
}
pub fn initialize_logging(level: i32) {
// Create a LevelFilter and a reload::Layer
// let (level_filter, reload_handle) = reload::Layer::new(level_to_filter(level));
// Update the static handle.
// *RELOAD_HANDLE = Some(reload_handle);
let file_fmt_layer = fmt::Layer::default()
.with_level(false)
.with_writer(CallbackWriter)
.with_timer(WithoutTimeFormat)
.with_filter(level_to_filter(level)); // Use the same level filter
let console_fmt_layer = fmt::Layer::default()
.with_file(true)
.with_line_number(true)
.with_writer(std::io::stdout)
.with_timer(CustomTimeFormat)
.with_filter(level_to_filter(level)); // Use the same level filter
// let subscriber = Registry::default().with(level_filter);
let subscriber = Registry::default()
.with(file_fmt_layer)
.with(console_fmt_layer);
tracing::subscriber::set_global_default(subscriber).expect("Failed to set subscriber");
}
pub fn update_logging_level(level: i32) {
let level_filter = level_to_filter(level);
if let Some(reload_handle) = &*RELOAD_HANDLE {
reload_handle
.modify(|filter| *filter = level_filter)
.expect("Failed to update logging level");
}
}
fn level_to_filter(level: i32) -> LevelFilter {
match level {
0 => LevelFilter::ERROR,
1 => LevelFilter::WARN,
2 => LevelFilter::INFO,
3 => LevelFilter::DEBUG,
4 => LevelFilter::TRACE,
_ => LevelFilter::INFO,
}
} how to save a reload_handle, need help |
found correct usage 😸 lazy_static! {
static ref IS_INITIALIZED: AtomicBool = AtomicBool::new(false);
static ref RELOAD_HANDLE: Mutex<Option<reload::Handle<filter::LevelFilter, Registry>>> =
Mutex::new(None);
}
pub fn setup_logging(level: i32) {
if IS_INITIALIZED.load(Ordering::Acquire) {
update_logging_level(level);
return;
}
let result = IS_INITIALIZED.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed);
match result {
Ok(_) => {
let (level_filter, reload_handle) = reload::Layer::new(level_to_filter(level));
set_reload_handle(reload_handle);
tracing_subscriber::registry()
.with(level_filter)
.with(
fmt::Layer::default()
.with_level(false)
.with_writer(CStringWriter)
.with_timer(WithoutTimeFormat),
)
.with(
fmt::Layer::default()
.with_file(true)
.with_line_number(true)
.with_timer(CustomTimeFormat),
)
.init();
}
Err(_) => {
// if the logging has already been initialized, just update the logging level
update_logging_level(level);
}
}
}
pub fn update_logging_level(level: i32) {
if let Some(reload_handle) = &*RELOAD_HANDLE.lock().unwrap() {
reload_handle
.modify(|filter| *filter = level_to_filter(level))
.expect("Failed to update logging level");
}
}
fn set_reload_handle(reload_handle: reload::Handle<filter::LevelFilter, Registry>) {
let mut handle = RELOAD_HANDLE.lock().unwrap();
*handle = Some(reload_handle);
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Feature Request
Crates
tracing-subscriber
Motivation
There are many places I want to pipe my log events:
stderr
These can all be implemented as
Layer
s.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):
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:
There are several issues with this approach:
reload_handle
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:
The text was updated successfully, but these errors were encountered: