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