1#![doc(
98 html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/logo-type.png",
99 html_favicon_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/favicon.ico",
100 issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
101)]
102#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
103#![warn(
104 missing_debug_implementations,
105 missing_docs,
106 rust_2018_idioms,
107 unreachable_pub,
108 bad_style,
109 dead_code,
110 improper_ctypes,
111 non_shorthand_field_patterns,
112 no_mangle_generic_items,
113 overflowing_literals,
114 path_statements,
115 patterns_in_fns_without_body,
116 private_interfaces,
117 private_bounds,
118 unconditional_recursion,
119 unused,
120 unused_allocation,
121 unused_comparisons,
122 unused_parens,
123 while_true
124)]
125use once_cell::sync::Lazy;
126
127use std::{fmt, io};
128
129use tracing_core::{
130 callsite::{self, Callsite},
131 dispatcher,
132 field::{self, Field, Visit},
133 identify_callsite,
134 metadata::{Kind, Level},
135 subscriber, Event, Metadata,
136};
137
138#[cfg(feature = "log-tracer")]
139#[cfg_attr(docsrs, doc(cfg(feature = "log-tracer")))]
140pub mod log_tracer;
141
142#[cfg(feature = "log-tracer")]
143#[cfg_attr(docsrs, doc(cfg(feature = "log-tracer")))]
144#[doc(inline)]
145pub use self::log_tracer::LogTracer;
146
147pub use log;
148
149#[cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std"))]
150mod interest_cache;
151
152#[cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std"))]
153#[cfg_attr(
154 docsrs,
155 doc(cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std")))
156)]
157pub use crate::interest_cache::InterestCacheConfig;
158
159pub fn format_trace(record: &log::Record<'_>) -> io::Result<()> {
161 dispatch_record(record);
162 Ok(())
163}
164
165pub(crate) fn dispatch_record(record: &log::Record<'_>) {
169 dispatcher::get_default(|dispatch| {
170 let filter_meta = record.as_trace();
171 if !dispatch.enabled(&filter_meta) {
172 return;
173 }
174
175 let (_, keys, meta) = loglevel_to_cs(record.level());
176
177 let log_module = record.module_path();
178 let log_file = record.file();
179 let log_line = record.line();
180
181 let module = log_module.as_ref().map(|s| s as &dyn field::Value);
182 let file = log_file.as_ref().map(|s| s as &dyn field::Value);
183 let line = log_line.as_ref().map(|s| s as &dyn field::Value);
184
185 dispatch.event(&Event::new(
186 meta,
187 &meta.fields().value_set(&[
188 (&keys.message, Some(record.args() as &dyn field::Value)),
189 (&keys.target, Some(&record.target())),
190 (&keys.module, module),
191 (&keys.file, file),
192 (&keys.line, line),
193 ]),
194 ));
195 });
196}
197
198pub trait AsLog: crate::sealed::Sealed {
201 type Log;
203 fn as_log(&self) -> Self::Log;
205}
206
207pub trait AsTrace: crate::sealed::Sealed {
210 type Trace;
212 fn as_trace(&self) -> Self::Trace;
214}
215
216impl crate::sealed::Sealed for Metadata<'_> {}
217
218impl<'a> AsLog for Metadata<'a> {
219 type Log = log::Metadata<'a>;
220 fn as_log(&self) -> Self::Log {
221 log::Metadata::builder()
222 .level(self.level().as_log())
223 .target(self.target())
224 .build()
225 }
226}
227impl crate::sealed::Sealed for log::Metadata<'_> {}
228
229impl<'a> AsTrace for log::Metadata<'a> {
230 type Trace = Metadata<'a>;
231 fn as_trace(&self) -> Self::Trace {
232 let cs_id = identify_callsite!(loglevel_to_cs(self.level()).0);
233 Metadata::new(
234 "log record",
235 self.target(),
236 self.level().as_trace(),
237 None,
238 None,
239 None,
240 field::FieldSet::new(FIELD_NAMES, cs_id),
241 Kind::EVENT,
242 )
243 }
244}
245
246struct Fields {
247 message: field::Field,
248 target: field::Field,
249 module: field::Field,
250 file: field::Field,
251 line: field::Field,
252}
253
254static FIELD_NAMES: &[&str] = &[
255 "message",
256 "log.target",
257 "log.module_path",
258 "log.file",
259 "log.line",
260];
261
262impl Fields {
263 fn new(cs: &'static dyn Callsite) -> Self {
264 let fieldset = cs.metadata().fields();
265 let message = fieldset.field("message").unwrap();
266 let target = fieldset.field("log.target").unwrap();
267 let module = fieldset.field("log.module_path").unwrap();
268 let file = fieldset.field("log.file").unwrap();
269 let line = fieldset.field("log.line").unwrap();
270 Fields {
271 message,
272 target,
273 module,
274 file,
275 line,
276 }
277 }
278}
279
280macro_rules! log_cs {
281 ($level:expr, $cs:ident, $meta:ident, $ty:ident) => {
282 struct $ty;
283 static $cs: $ty = $ty;
284 static $meta: Metadata<'static> = Metadata::new(
285 "log event",
286 "log",
287 $level,
288 ::core::option::Option::None,
289 ::core::option::Option::None,
290 ::core::option::Option::None,
291 field::FieldSet::new(FIELD_NAMES, identify_callsite!(&$cs)),
292 Kind::EVENT,
293 );
294
295 impl callsite::Callsite for $ty {
296 fn set_interest(&self, _: subscriber::Interest) {}
297 fn metadata(&self) -> &'static Metadata<'static> {
298 &$meta
299 }
300 }
301 };
302}
303
304log_cs!(
305 tracing_core::Level::TRACE,
306 TRACE_CS,
307 TRACE_META,
308 TraceCallsite
309);
310log_cs!(
311 tracing_core::Level::DEBUG,
312 DEBUG_CS,
313 DEBUG_META,
314 DebugCallsite
315);
316log_cs!(tracing_core::Level::INFO, INFO_CS, INFO_META, InfoCallsite);
317log_cs!(tracing_core::Level::WARN, WARN_CS, WARN_META, WarnCallsite);
318log_cs!(
319 tracing_core::Level::ERROR,
320 ERROR_CS,
321 ERROR_META,
322 ErrorCallsite
323);
324
325static TRACE_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&TRACE_CS));
326static DEBUG_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&DEBUG_CS));
327static INFO_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&INFO_CS));
328static WARN_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&WARN_CS));
329static ERROR_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&ERROR_CS));
330
331fn level_to_cs(level: Level) -> (&'static dyn Callsite, &'static Fields) {
332 match level {
333 Level::TRACE => (&TRACE_CS, &*TRACE_FIELDS),
334 Level::DEBUG => (&DEBUG_CS, &*DEBUG_FIELDS),
335 Level::INFO => (&INFO_CS, &*INFO_FIELDS),
336 Level::WARN => (&WARN_CS, &*WARN_FIELDS),
337 Level::ERROR => (&ERROR_CS, &*ERROR_FIELDS),
338 }
339}
340
341fn loglevel_to_cs(
342 level: log::Level,
343) -> (
344 &'static dyn Callsite,
345 &'static Fields,
346 &'static Metadata<'static>,
347) {
348 match level {
349 log::Level::Trace => (&TRACE_CS, &*TRACE_FIELDS, &TRACE_META),
350 log::Level::Debug => (&DEBUG_CS, &*DEBUG_FIELDS, &DEBUG_META),
351 log::Level::Info => (&INFO_CS, &*INFO_FIELDS, &INFO_META),
352 log::Level::Warn => (&WARN_CS, &*WARN_FIELDS, &WARN_META),
353 log::Level::Error => (&ERROR_CS, &*ERROR_FIELDS, &ERROR_META),
354 }
355}
356
357impl crate::sealed::Sealed for log::Record<'_> {}
358
359impl<'a> AsTrace for log::Record<'a> {
360 type Trace = Metadata<'a>;
361 fn as_trace(&self) -> Self::Trace {
362 let cs_id = identify_callsite!(loglevel_to_cs(self.level()).0);
363 Metadata::new(
364 "log record",
365 self.target(),
366 self.level().as_trace(),
367 self.file(),
368 self.line(),
369 self.module_path(),
370 field::FieldSet::new(FIELD_NAMES, cs_id),
371 Kind::EVENT,
372 )
373 }
374}
375
376impl crate::sealed::Sealed for tracing_core::Level {}
377
378impl AsLog for tracing_core::Level {
379 type Log = log::Level;
380 fn as_log(&self) -> log::Level {
381 match *self {
382 tracing_core::Level::ERROR => log::Level::Error,
383 tracing_core::Level::WARN => log::Level::Warn,
384 tracing_core::Level::INFO => log::Level::Info,
385 tracing_core::Level::DEBUG => log::Level::Debug,
386 tracing_core::Level::TRACE => log::Level::Trace,
387 }
388 }
389}
390
391impl crate::sealed::Sealed for log::Level {}
392
393impl AsTrace for log::Level {
394 type Trace = tracing_core::Level;
395 #[inline]
396 fn as_trace(&self) -> tracing_core::Level {
397 match self {
398 log::Level::Error => tracing_core::Level::ERROR,
399 log::Level::Warn => tracing_core::Level::WARN,
400 log::Level::Info => tracing_core::Level::INFO,
401 log::Level::Debug => tracing_core::Level::DEBUG,
402 log::Level::Trace => tracing_core::Level::TRACE,
403 }
404 }
405}
406
407impl crate::sealed::Sealed for log::LevelFilter {}
408
409impl AsTrace for log::LevelFilter {
410 type Trace = tracing_core::LevelFilter;
411 #[inline]
412 fn as_trace(&self) -> tracing_core::LevelFilter {
413 match self {
414 log::LevelFilter::Off => tracing_core::LevelFilter::OFF,
415 log::LevelFilter::Error => tracing_core::LevelFilter::ERROR,
416 log::LevelFilter::Warn => tracing_core::LevelFilter::WARN,
417 log::LevelFilter::Info => tracing_core::LevelFilter::INFO,
418 log::LevelFilter::Debug => tracing_core::LevelFilter::DEBUG,
419 log::LevelFilter::Trace => tracing_core::LevelFilter::TRACE,
420 }
421 }
422}
423
424impl crate::sealed::Sealed for tracing_core::LevelFilter {}
425
426impl AsLog for tracing_core::LevelFilter {
427 type Log = log::LevelFilter;
428 #[inline]
429 fn as_log(&self) -> Self::Log {
430 match *self {
431 tracing_core::LevelFilter::OFF => log::LevelFilter::Off,
432 tracing_core::LevelFilter::ERROR => log::LevelFilter::Error,
433 tracing_core::LevelFilter::WARN => log::LevelFilter::Warn,
434 tracing_core::LevelFilter::INFO => log::LevelFilter::Info,
435 tracing_core::LevelFilter::DEBUG => log::LevelFilter::Debug,
436 tracing_core::LevelFilter::TRACE => log::LevelFilter::Trace,
437 }
438 }
439}
440pub trait NormalizeEvent<'a>: crate::sealed::Sealed {
458 fn normalized_metadata(&'a self) -> Option<Metadata<'a>>;
464 fn is_log(&self) -> bool;
466}
467
468impl crate::sealed::Sealed for Event<'_> {}
469
470impl<'a> NormalizeEvent<'a> for Event<'a> {
471 fn normalized_metadata(&'a self) -> Option<Metadata<'a>> {
472 let original = self.metadata();
473 if self.is_log() {
474 let mut fields = LogVisitor::new_for(self, level_to_cs(*original.level()).1);
475 self.record(&mut fields);
476
477 Some(Metadata::new(
478 "log event",
479 fields.target.unwrap_or("log"),
480 *original.level(),
481 fields.file,
482 fields.line.map(|l| l as u32),
483 fields.module_path,
484 field::FieldSet::new(&["message"], original.callsite()),
485 Kind::EVENT,
486 ))
487 } else {
488 None
489 }
490 }
491
492 fn is_log(&self) -> bool {
493 self.metadata().callsite() == identify_callsite!(level_to_cs(*self.metadata().level()).0)
494 }
495}
496
497struct LogVisitor<'a> {
498 target: Option<&'a str>,
499 module_path: Option<&'a str>,
500 file: Option<&'a str>,
501 line: Option<u64>,
502 fields: &'static Fields,
503}
504
505impl<'a> LogVisitor<'a> {
506 fn new_for(_event: &'a Event<'a>, fields: &'static Fields) -> Self {
510 Self {
511 target: None,
512 module_path: None,
513 file: None,
514 line: None,
515 fields,
516 }
517 }
518}
519
520impl Visit for LogVisitor<'_> {
521 fn record_debug(&mut self, _field: &Field, _value: &dyn fmt::Debug) {}
522
523 fn record_u64(&mut self, field: &Field, value: u64) {
524 if field == &self.fields.line {
525 self.line = Some(value);
526 }
527 }
528
529 fn record_str(&mut self, field: &Field, value: &str) {
530 unsafe {
531 if field == &self.fields.file {
537 self.file = Some(&*(value as *const _));
538 } else if field == &self.fields.target {
539 self.target = Some(&*(value as *const _));
540 } else if field == &self.fields.module {
541 self.module_path = Some(&*(value as *const _));
542 }
543 }
544 }
545}
546
547mod sealed {
548 pub trait Sealed {}
549}
550
551#[cfg(test)]
552mod test {
553 use super::*;
554
555 fn test_callsite(level: log::Level) {
556 let record = log::Record::builder()
557 .args(format_args!("Error!"))
558 .level(level)
559 .target("myApp")
560 .file(Some("server.rs"))
561 .line(Some(144))
562 .module_path(Some("server"))
563 .build();
564
565 let meta = record.as_trace();
566 let (cs, _keys, _) = loglevel_to_cs(record.level());
567 let cs_meta = cs.metadata();
568 assert_eq!(
569 meta.callsite(),
570 cs_meta.callsite(),
571 "actual: {:#?}\nexpected: {:#?}",
572 meta,
573 cs_meta
574 );
575 assert_eq!(meta.level(), &level.as_trace());
576 }
577
578 #[test]
579 fn error_callsite_is_correct() {
580 test_callsite(log::Level::Error);
581 }
582
583 #[test]
584 fn warn_callsite_is_correct() {
585 test_callsite(log::Level::Warn);
586 }
587
588 #[test]
589 fn info_callsite_is_correct() {
590 test_callsite(log::Level::Info);
591 }
592
593 #[test]
594 fn debug_callsite_is_correct() {
595 test_callsite(log::Level::Debug);
596 }
597
598 #[test]
599 fn trace_callsite_is_correct() {
600 test_callsite(log::Level::Trace);
601 }
602}