mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-08 00:00:13 +02:00
trace: Allow trace instrumentation to emit log records (#992)
## Motivation `tokio-trace` currently offers a strategy for compatibility with the `log` crate: its macros can be dropped in as a replacement for `log`'s macros, and a subscriber can be used that translates trace events to log records. However, this requires the application to be aware of `tokio-trace` and manually set up this subscriber. Many libraries currently emit `log` records, and would like to be able to emit `tokio-trace` instrumentation instead. The `tokio` runtimes are one such example. However, with the current log compatibility strategy, replacing existing logging with trace instrumentation would break `tokio`'s logs for any downstream user which is using only `log` and not `tokio-trace`. It is desirable for libraries to have the option to emit both `log` _and_ `tokio-trace` diagnostics from the same instrumentation points. ## Solution This branch adds a `log` feature flag to the `tokio-trace` crate, which when set, causes `tokio-trace` instrumentation to emit log records as well as `tokio-trace` instrumentation. ## Notes In order to allow spans to log their names when they are entered and exited even when the span is disabled, this branch adds an `&'static Metadata` to the `Span` type. This was previously stored in the `Inner` type and was thus only present when the span was enabled. This makes disabled spans one word longer, but enabled spans remain the same size. Fixes: #949 Signed-off-by: Eliza Weisman <[email protected]>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "test_log_support"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
tokio-trace = { path = "..", features = ["log"] }
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
@@ -0,0 +1,71 @@
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate tokio_trace;
|
||||
|
||||
use log::{LevelFilter, Log, Metadata, Record};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
struct State {
|
||||
last_log: Mutex<Option<String>>,
|
||||
}
|
||||
|
||||
struct Logger(Arc<State>);
|
||||
|
||||
impl Log for Logger {
|
||||
fn enabled(&self, _: &Metadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
let line = format!("{}", record.args());
|
||||
println!("{:<5} {} {}", record.level(), record.target(), line);
|
||||
*self.0.last_log.lock().unwrap() = Some(line);
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_always_log() {
|
||||
let me = Arc::new(State {
|
||||
last_log: Mutex::new(None),
|
||||
});
|
||||
let a = me.clone();
|
||||
log::set_boxed_logger(Box::new(Logger(me))).unwrap();
|
||||
log::set_max_level(LevelFilter::Trace);
|
||||
|
||||
error!(foo = 5);
|
||||
last(&a, "foo=5");
|
||||
warn!("hello {};", "world");
|
||||
last(&a, "hello world;");
|
||||
info!(message = "hello world;", thingy = 42, other_thingy = 666);
|
||||
last(&a, "hello world; thingy=42 other_thingy=666");
|
||||
|
||||
let mut foo = span!("foo");
|
||||
last(&a, "foo;");
|
||||
foo.enter(|| {
|
||||
last(&a, "-> foo");
|
||||
|
||||
trace!({foo = 3, bar = 4}, "hello {};", "san francisco");
|
||||
last(&a, "hello san francisco; foo=3 bar=4");
|
||||
});
|
||||
last(&a, "<- foo");
|
||||
|
||||
span!("foo", bar = 3, baz = false);
|
||||
last(&a, "foo; bar=3 baz=false");
|
||||
|
||||
let mut span = span!("foo", bar, baz);
|
||||
span.record("bar", &3);
|
||||
last(&a, "foo; bar=3");
|
||||
span.record("baz", &"a string");
|
||||
last(&a, "foo; baz=\"a string\"");
|
||||
}
|
||||
|
||||
fn last(state: &State, expected: &str) {
|
||||
let mut lock = state.last_log.lock().unwrap();
|
||||
{
|
||||
let last = lock.as_ref().map(|s| s.as_str().trim());
|
||||
assert_eq!(last, Some(expected));
|
||||
}
|
||||
*lock = None;
|
||||
}
|
||||
Reference in New Issue
Block a user