micromegas_telemetry_sink/
tracing_interop.rs1use micromegas_tracing::{
2 dispatch::log_interop,
3 levels::LevelFilter,
4 logs::{FILTER_LEVEL_UNSET_VALUE, LogMetadata},
5};
6use std::sync::atomic::AtomicU32;
7use tracing_subscriber::{layer::Context, prelude::*};
8
9use std::fmt::{self, Write};
10use tracing::field::{Field, Visit};
11pub struct FieldFormatVisitor<'a> {
12 pub buffer: &'a mut String,
13 pub target: Option<String>,
14}
15
16impl Visit for FieldFormatVisitor<'_> {
17 fn record_str(&mut self, field: &Field, value: &str) {
18 if field.name() == "log.target" {
19 self.target = Some(value.to_owned());
20 } else {
21 self.record_debug(field, &value)
22 }
23 }
24 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
25 if field.name() == "message" {
26 write!(self.buffer, "{value:?} ").unwrap();
27 } else {
28 write!(self.buffer, "{}={:?} ", field.name(), value).unwrap();
29 }
30 }
31}
32
33pub struct TracingCaptureLayer {
37 pub max_level: LevelFilter,
38}
39
40impl<S> tracing_subscriber::Layer<S> for TracingCaptureLayer
41where
42 S: tracing::Subscriber,
43{
44 fn enabled(&self, metadata: &tracing::Metadata<'_>, _ctx: Context<'_, S>) -> bool {
45 let level = tracing_level_to_mm_level(metadata.level());
46 level <= self.max_level
47 }
48
49 fn on_event(
50 &self,
51 event: &tracing::Event<'_>,
52 _ctx: tracing_subscriber::layer::Context<'_, S>,
53 ) {
54 let level = tracing_level_to_mm_level(event.metadata().level());
55 if level > self.max_level {
56 return;
57 }
58 let mut buffer = String::new();
59 let mut formatter = FieldFormatVisitor {
60 buffer: &mut buffer,
61 target: None,
62 };
63 event.record(&mut formatter);
64 let log_desc = LogMetadata {
65 level,
66 level_filter: AtomicU32::new(FILTER_LEVEL_UNSET_VALUE),
67 fmt_str: "{}",
68 target: formatter
69 .target
70 .as_deref()
71 .unwrap_or(event.metadata().target()),
72 module_path: event.metadata().module_path().unwrap_or_default(),
73 file: "",
74 line: 0,
75 };
76
77 log_interop(&log_desc, format_args!("{}", &buffer));
78 }
79}
80
81pub fn install_tracing_interop(interop_max_level_override: Option<LevelFilter>) {
90 let max_level = interop_max_level_override.unwrap_or(micromegas_tracing::levels::max_level());
91
92 tracing_subscriber::registry()
93 .with(TracingCaptureLayer { max_level })
94 .init();
95 tracing::debug!("installed tracing interop");
96}
97
98fn tracing_level_to_mm_level(level: &tracing_core::Level) -> micromegas_tracing::levels::Level {
99 match *level {
100 tracing_core::Level::ERROR => micromegas_tracing::levels::Level::Error,
101 tracing_core::Level::WARN => micromegas_tracing::levels::Level::Warn,
102 tracing_core::Level::INFO => micromegas_tracing::levels::Level::Info,
103 tracing_core::Level::DEBUG => micromegas_tracing::levels::Level::Debug,
104 tracing_core::Level::TRACE => micromegas_tracing::levels::Level::Trace,
105 }
106}