1use rerun::{RecordingStream, TextLogLevel};
2use tracing::{Event, Level, Subscriber};
3use tracing_subscriber::{layer::Context, Layer};
4
5fn to_rerun_log_level(tracing_level: &Level) -> TextLogLevel {
6 match *tracing_level {
7 Level::ERROR => TextLogLevel::ERROR.into(),
8 Level::WARN => TextLogLevel::WARN.into(),
9 Level::INFO => TextLogLevel::INFO.into(),
10 Level::DEBUG => TextLogLevel::DEBUG.into(),
11 Level::TRACE => TextLogLevel::TRACE.into(),
12 }
13}
14
15pub struct RerunLayer {
17 pub rec: RecordingStream,
18 pub path: String, }
20
21impl<S> Layer<S> for RerunLayer
22where
23 S: Subscriber + for<'lookup> tracing_subscriber::registry::LookupSpan<'lookup>,
24{
25 fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
26 use std::fmt::Write;
27 let spans = ctx
29 .lookup_current()
30 .map(|s| {
31 s.scope()
32 .map(|s| s.metadata().name().to_string())
33 .collect::<Vec<_>>()
34 .join("::")
35 })
36 .unwrap_or_default();
37
38 struct Visitor<'a> { buf: &'a mut String }
40 impl<'a> tracing::field::Visit for Visitor<'a> {
41 fn record_debug(
42 &mut self,
43 _field: &tracing::field::Field,
44 value: &dyn std::fmt::Debug
45 ) {
46 let _ = write!(self.buf, "{:?} ", value);
47 }
48 }
49
50 let meta = event.metadata();
51 let mut msg = String::new();
52 let span_prefix = if spans.is_empty() {
53 String::new()
54 } else {
55 format!("{spans}: ")
56 };
57 let _ = write!(
58 msg,
59 "{}{}: ",
60 span_prefix,
61 meta.target()
62 );
63 let mut v = Visitor { buf: &mut msg };
64 event.record(&mut v);
65
66 let text = rerun::archetypes::TextLog::new(msg).with_level(to_rerun_log_level(meta.level()));
68 let _ = self.rec.log(self.path.as_str(), &text);
69 }
70}