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
10pub struct CaptainsLogLayer {
12 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}