captains_log/
tracing_bridge.rs

1use crate::log::Log;
2use crate::log_impl::GlobalLogger;
3use log::Record;
4use std::fmt::{self, Write};
5use tracing::field::{Field, Visit};
6use tracing::{span, Event, Metadata, Subscriber};
7use tracing_subscriber::layer::{Context, Layer};
8use tracing_subscriber::registry::LookupSpan;
9
10/// An tracing-subscriber layer implementation, for capturing event from tracing
11pub struct CaptainsLogLayer {
12    /// This is a cycle pointer to the parent, to be filled after initialization.
13    logger: &'static GlobalLogger,
14}
15
16unsafe impl Send for CaptainsLogLayer {}
17unsafe impl Sync for CaptainsLogLayer {}
18
19macro_rules! log_span {
20    ($logger: expr, $id: expr, $meta: expr, $action: expr, $v: expr) => {{
21        let msg = $v.as_str();
22        if msg.len() == 0 {
23            $logger.log(
24                &Record::builder()
25                    .level(convert_tracing_level($meta.level()))
26                    .target($meta.target())
27                    .module_path($meta.module_path())
28                    .file($meta.file())
29                    .line($meta.line())
30                    .args(format_args!("span({}) {}", $id.into_u64(), $action))
31                    .build(),
32            );
33        } else {
34            $logger.log(
35                &Record::builder()
36                    .level(convert_tracing_level($meta.level()))
37                    .target($meta.target())
38                    .module_path($meta.module_path())
39                    .file($meta.file())
40                    .line($meta.line())
41                    .args(format_args!("span({}) {}: {}", $id.into_u64(), $action, msg))
42                    .build(),
43            );
44        }
45    }};
46}
47
48impl CaptainsLogLayer {
49    #[inline(always)]
50    pub(crate) fn new(logger: &'static GlobalLogger) -> Self {
51        Self { logger }
52    }
53}
54
55impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for CaptainsLogLayer {
56    #[inline(always)]
57    fn enabled(&self, meta: &Metadata<'_>, _ctx: Context<'_, S>) -> bool {
58        convert_tracing_level(meta.level()) <= log::STATIC_MAX_LEVEL
59    }
60
61    #[inline]
62    fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
63        let data = ctx.span(id).expect("Span not found");
64        let meta = data.metadata();
65        let mut extensions = data.extensions_mut();
66        if extensions.get_mut::<StringVisitor>().is_none() {
67            let mut v = StringVisitor::new();
68            attrs.record(&mut v);
69            log_span!(self.logger, id, meta, "new", v);
70            extensions.insert(v);
71        }
72    }
73
74    #[inline]
75    fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
76        let data = ctx.span(id).expect("Span not found");
77        let meta = data.metadata();
78        let mut extensions = data.extensions_mut();
79        if let Some(v) = extensions.get_mut::<StringVisitor>() {
80            values.record(v);
81            log_span!(self.logger, id, meta, "record", v);
82        } else {
83            let mut v = StringVisitor::new();
84            values.record(&mut v);
85            log_span!(self.logger, id, meta, "record", v);
86            extensions.insert(v);
87        }
88    }
89
90    #[inline]
91    fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
92        let data = ctx.span(&id).expect("Span not found, this is a bug");
93        let meta = data.metadata();
94        let extensions = data.extensions();
95        if let Some(v) = extensions.get::<StringVisitor>() {
96            log_span!(self.logger, id, meta, "enter", v);
97        }
98    }
99
100    #[inline]
101    fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
102        let data = ctx.span(&id).expect("Span not found, this is a bug");
103        let meta = data.metadata();
104        let extensions = data.extensions();
105        if let Some(v) = extensions.get::<StringVisitor>() {
106            log_span!(self.logger, id, meta, "exit", v);
107        }
108    }
109
110    #[inline]
111    fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
112        let data = ctx.span(&id).expect("Span not found, this is a bug");
113        let meta = data.metadata();
114        let extensions = data.extensions();
115        if let Some(v) = extensions.get::<StringVisitor>() {
116            log_span!(self.logger, id, meta, "close", v);
117        }
118    }
119
120    #[inline(always)]
121    fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
122        let meta = event.metadata();
123        let mut v = StringVisitor::new();
124        event.record(&mut v);
125        self.logger.log(
126            &Record::builder()
127                .level(convert_tracing_level(meta.level()))
128                .args(format_args!("{}", v.as_str()))
129                .target(meta.target())
130                .module_path(meta.module_path())
131                .file(meta.file())
132                .line(meta.line())
133                .build(),
134        );
135    }
136}
137
138#[inline(always)]
139pub fn convert_tracing_level(level: &tracing::Level) -> log::Level {
140    match *level {
141        tracing::Level::TRACE => log::Level::Trace,
142        tracing::Level::DEBUG => log::Level::Debug,
143        tracing::Level::INFO => log::Level::Info,
144        tracing::Level::WARN => log::Level::Warn,
145        tracing::Level::ERROR => log::Level::Error,
146    }
147}
148
149struct StringVisitor(String);
150
151impl Visit for StringVisitor {
152    fn record_str(&mut self, field: &Field, value: &str) {
153        if self.0.len() == 0 {
154            if field.name() == "message" {
155                write!(self.0, "{}", value).unwrap();
156                return;
157            } else {
158                write!(self.0, "{}={}", field.name(), value).unwrap();
159            }
160        } else {
161            write!(self.0, ", {}={}", field.name(), value).unwrap();
162        }
163    }
164
165    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
166        if self.0.len() == 0 {
167            if field.name() == "message" {
168                write!(self.0, "{:?}", value).unwrap();
169            } else {
170                write!(self.0, "{}={:?}", field.name(), value).unwrap();
171            }
172        } else {
173            write!(self.0, ", {}={:?}", field.name(), value).unwrap();
174        }
175    }
176}
177
178impl StringVisitor {
179    #[inline(always)]
180    fn new() -> Self {
181        Self(String::new())
182    }
183
184    #[inline(always)]
185    fn as_str(&self) -> &str {
186        self.0.as_str()
187    }
188}