1use crate::log::Log;
69use crate::log_impl::GlobalLogger;
70use log::Record;
71use std::fmt::{self, Write};
72use tracing::field::{Field, Visit};
73pub use tracing::{dispatcher, Dispatch};
74use tracing::{span, Event, Metadata, Subscriber};
75use tracing_subscriber::layer::{Context, Layer};
76use tracing_subscriber::registry::LookupSpan;
77pub use tracing_subscriber::{prelude::*, registry};
78
79pub struct CaptainsLogLayer<F = TracingText>
81where
82 F: TracingFormatter,
83{
84 logger: &'static GlobalLogger,
86 disable_span_new: bool,
87 disable_record: bool,
88 disable_enter: bool,
89 disable_exit: bool,
90 disable_close: bool,
91 _phan: F,
92}
93
94unsafe impl<F: TracingFormatter> Send for CaptainsLogLayer<F> {}
95unsafe impl<F: TracingFormatter> Sync for CaptainsLogLayer<F> {}
96
97macro_rules! log_span {
98 ($logger: expr, $id: expr, $meta: expr, $action: expr, $v: expr) => {{
99 let msg = $v.as_ref();
100 if msg.len() == 0 {
101 $logger.log(
102 &Record::builder()
103 .level(convert_tracing_level($meta.level()))
104 .target($meta.target())
105 .module_path($meta.module_path())
106 .file($meta.file())
107 .line($meta.line())
108 .args(format_args!("span({}) {}", $id.into_u64(), $action))
109 .build(),
110 );
111 } else {
112 $logger.log(
113 &Record::builder()
114 .level(convert_tracing_level($meta.level()))
115 .target($meta.target())
116 .module_path($meta.module_path())
117 .file($meta.file())
118 .line($meta.line())
119 .args(format_args!("span({}) {}: {}", $id.into_u64(), $action, msg))
120 .build(),
121 );
122 }
123 }};
124}
125
126impl<F> CaptainsLogLayer<F>
127where
128 F: TracingFormatter,
129{
130 #[inline(always)]
131 pub(crate) fn new(logger: &'static GlobalLogger) -> Self {
132 Self {
133 logger,
134 _phan: Default::default(),
135 disable_span_new: false,
136 disable_record: false,
137 disable_enter: false,
138 disable_exit: false,
139 disable_close: false,
140 }
141 }
142
143 #[inline]
144 pub fn disable_enter(mut self) -> Self {
145 self.disable_enter = true;
146 self
147 }
148
149 #[inline]
150 pub fn disable_exit(mut self) -> Self {
151 self.disable_exit = true;
152 self
153 }
154
155 #[inline]
156 pub fn disable_close(mut self) -> Self {
157 self.disable_close = true;
158 self
159 }
160
161 #[inline]
162 pub fn disable_record(mut self) -> Self {
163 self.disable_record = true;
164 self
165 }
166
167 #[inline]
168 pub fn disable_span(mut self) -> Self {
169 self.disable_span_new = true;
170 self.disable_record = true;
171 self.disable_enter = true;
172 self.disable_exit = true;
173 self.disable_close = true;
174 self
175 }
176}
177
178impl<S, F> Layer<S> for CaptainsLogLayer<F>
179where
180 S: Subscriber + for<'a> LookupSpan<'a>,
181 F: TracingFormatter + 'static,
182{
183 #[inline(always)]
184 fn enabled(&self, meta: &Metadata<'_>, _ctx: Context<'_, S>) -> bool {
185 convert_tracing_level(meta.level()) <= log::STATIC_MAX_LEVEL
186 }
187
188 #[inline]
189 fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
190 if self.disable_span_new {
191 return;
192 }
193 let data = ctx.span(id).expect("Span not found");
194 let meta = data.metadata();
195 let mut extensions = data.extensions_mut();
196 if extensions.get_mut::<F>().is_none() {
197 let mut v = F::default();
198 attrs.record(&mut v);
199 log_span!(self.logger, id, meta, "new", v);
200 extensions.insert(v);
201 }
202 }
203
204 #[inline]
205 fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
206 if self.disable_span_new {
207 return;
208 }
209 let data = ctx.span(id).expect("Span not found");
210 let meta = data.metadata();
211 let mut extensions = data.extensions_mut();
212 if let Some(v) = extensions.get_mut::<F>() {
213 values.record(v);
214 if !self.disable_record {
215 log_span!(self.logger, id, meta, "record", v);
216 }
217 } else {
218 let mut v = F::default();
219 values.record(&mut v);
220 if !self.disable_record {
221 log_span!(self.logger, id, meta, "record", v);
222 }
223 extensions.insert(v);
224 }
225 }
226
227 #[inline]
228 fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
229 if self.disable_enter {
230 return;
231 }
232 let data = ctx.span(&id).expect("Span not found, this is a bug");
233 let meta = data.metadata();
234 let extensions = data.extensions();
235 if let Some(v) = extensions.get::<F>() {
236 log_span!(self.logger, id, meta, "enter", v);
237 }
238 }
239
240 #[inline]
241 fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
242 if self.disable_exit {
243 return;
244 }
245 let data = ctx.span(&id).expect("Span not found, this is a bug");
246 let meta = data.metadata();
247 let extensions = data.extensions();
248 if let Some(v) = extensions.get::<F>() {
249 log_span!(self.logger, id, meta, "exit", v);
250 }
251 }
252
253 #[inline]
254 fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
255 if self.disable_close {
256 return;
257 }
258 let data = ctx.span(&id).expect("Span not found, this is a bug");
259 let meta = data.metadata();
260 let extensions = data.extensions();
261 if let Some(v) = extensions.get::<F>() {
262 log_span!(self.logger, id, meta, "close", v);
263 }
264 }
265
266 #[inline(always)]
267 fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
268 let meta = event.metadata();
269 let mut v = F::default();
270 event.record(&mut v);
271 self.logger.log(
272 &Record::builder()
273 .level(convert_tracing_level(meta.level()))
274 .args(format_args!("{}", v.as_ref()))
275 .target(meta.target())
276 .module_path(meta.module_path())
277 .file(meta.file())
278 .line(meta.line())
279 .build(),
280 );
281 }
282}
283
284#[inline(always)]
286pub fn convert_tracing_level(level: &tracing::Level) -> log::Level {
287 match *level {
288 tracing::Level::TRACE => log::Level::Trace,
289 tracing::Level::DEBUG => log::Level::Debug,
290 tracing::Level::INFO => log::Level::Info,
291 tracing::Level::WARN => log::Level::Warn,
292 tracing::Level::ERROR => log::Level::Error,
293 }
294}
295
296pub trait TracingFormatter: Visit + Default + AsRef<str> + Send + Sync + 'static {}
298
299pub struct TracingText(String);
301
302impl Visit for TracingText {
303 fn record_str(&mut self, field: &Field, value: &str) {
304 if self.0.len() == 0 {
305 if field.name() == "message" {
306 write!(self.0, "{}", value).unwrap();
307 return;
308 } else {
309 write!(self.0, "{}={}", field.name(), value).unwrap();
310 }
311 } else {
312 write!(self.0, ", {}={}", field.name(), value).unwrap();
313 }
314 }
315
316 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
317 if self.0.len() == 0 {
318 if field.name() == "message" {
319 write!(self.0, "{:?}", value).unwrap();
320 } else {
321 write!(self.0, "{}={:?}", field.name(), value).unwrap();
322 }
323 } else {
324 write!(self.0, ", {}={:?}", field.name(), value).unwrap();
325 }
326 }
327}
328
329impl Default for TracingText {
330 #[inline(always)]
331 fn default() -> Self {
332 Self(String::new())
333 }
334}
335
336impl AsRef<str> for TracingText {
337 #[inline(always)]
338 fn as_ref(&self) -> &str {
339 self.0.as_str()
340 }
341}
342
343impl TracingFormatter for TracingText {}