]> git.proxmox.com Git - rustc.git/blame - vendor/tracing-subscriber/src/fmt/format/mod.rs
New upstream version 1.51.0+dfsg1
[rustc.git] / vendor / tracing-subscriber / src / fmt / format / mod.rs
CommitLineData
f035d41b
XL
1//! Formatters for logging `tracing` events.
2use super::time::{self, FormatTime, SystemTime};
3use crate::{
4 field::{MakeOutput, MakeVisitor, RecordFields, VisitFmt, VisitOutput},
5 fmt::fmt_layer::FmtContext,
6 fmt::fmt_layer::FormattedFields,
7 registry::LookupSpan,
8};
9
10use std::{
11 fmt::{self, Write},
12 iter,
13};
14use tracing_core::{
15 field::{self, Field, Visit},
16 span, Event, Level, Subscriber,
17};
18
19#[cfg(feature = "tracing-log")]
20use tracing_log::NormalizeEvent;
21
22#[cfg(feature = "ansi")]
23use ansi_term::{Colour, Style};
24
25#[cfg(feature = "json")]
26mod json;
f035d41b
XL
27#[cfg(feature = "json")]
28#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
29pub use json::*;
30
5869c6ff
XL
31#[cfg(feature = "ansi")]
32mod pretty;
33#[cfg(feature = "ansi")]
34#[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
35pub use pretty::*;
36
37use fmt::{Debug, Display};
38
f035d41b
XL
39/// A type that can format a tracing `Event` for a `fmt::Write`.
40///
3dfed10e
XL
41/// `FormatEvent` is primarily used in the context of [`fmt::Subscriber`] or [`fmt::Layer`]. Each time an event is
42/// dispatched to [`fmt::Subscriber`] or [`fmt::Layer`], the subscriber or layer forwards it to
43/// its associated `FormatEvent` to emit a log message.
f035d41b
XL
44///
45/// This trait is already implemented for function pointers with the same
46/// signature as `format_event`.
47///
3dfed10e
XL
48/// [`fmt::Subscriber`]: ../struct.Subscriber.html
49/// [`fmt::Layer`]: ../struct.Layer.html
f035d41b
XL
50pub trait FormatEvent<S, N>
51where
52 S: Subscriber + for<'a> LookupSpan<'a>,
53 N: for<'a> FormatFields<'a> + 'static,
54{
55 /// Write a log message for `Event` in `Context` to the given `Write`.
56 fn format_event(
57 &self,
58 ctx: &FmtContext<'_, S, N>,
59 writer: &mut dyn fmt::Write,
60 event: &Event<'_>,
61 ) -> fmt::Result;
62}
63
64impl<S, N> FormatEvent<S, N>
65 for fn(ctx: &FmtContext<'_, S, N>, &mut dyn fmt::Write, &Event<'_>) -> fmt::Result
66where
67 S: Subscriber + for<'a> LookupSpan<'a>,
68 N: for<'a> FormatFields<'a> + 'static,
69{
70 fn format_event(
71 &self,
72 ctx: &FmtContext<'_, S, N>,
73 writer: &mut dyn fmt::Write,
74 event: &Event<'_>,
75 ) -> fmt::Result {
76 (*self)(ctx, writer, event)
77 }
78}
79/// A type that can format a [set of fields] to a `fmt::Write`.
80///
81/// `FormatFields` is primarily used in the context of [`FmtSubscriber`]. Each
82/// time a span or event with fields is recorded, the subscriber will format
83/// those fields with its associated `FormatFields` implementation.
84///
85/// [set of fields]: ../field/trait.RecordFields.html
86/// [`FmtSubscriber`]: ../fmt/struct.Subscriber.html
87pub trait FormatFields<'writer> {
88 /// Format the provided `fields` to the provided `writer`, returning a result.
89 fn format_fields<R: RecordFields>(
90 &self,
91 writer: &'writer mut dyn fmt::Write,
92 fields: R,
93 ) -> fmt::Result;
94
95 /// Record additional field(s) on an existing span.
96 ///
97 /// By default, this appends a space to the current set of fields if it is
98 /// non-empty, and then calls `self.format_fields`. If different behavior is
99 /// required, the default implementation of this method can be overridden.
100 fn add_fields(&self, current: &'writer mut String, fields: &span::Record<'_>) -> fmt::Result {
101 if !current.is_empty() {
102 current.push(' ');
103 }
104 self.format_fields(current, fields)
105 }
106}
107
108/// Returns the default configuration for an [event formatter].
109///
110/// Methods on the returned event formatter can be used for further
111/// configuration. For example:
112///
113/// ```rust
114/// let format = tracing_subscriber::fmt::format()
115/// .without_time() // Don't include timestamps
116/// .with_target(false) // Don't include event targets.
117/// .with_level(false) // Don't include event levels.
118/// .compact(); // Use a more compact, abbreviated format.
119///
120/// // Use the configured formatter when building a new subscriber.
121/// tracing_subscriber::fmt()
122/// .event_format(format)
123/// .init();
124/// ```
125pub fn format() -> Format {
126 Format::default()
127}
128
129/// Returns the default configuration for a JSON [event formatter].
130#[cfg(feature = "json")]
131#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
132pub fn json() -> Format<Json> {
133 format().json()
134}
135
136/// Returns a [`FormatFields`] implementation that formats fields using the
137/// provided function or closure.
138///
139/// [`FormatFields`]: trait.FormatFields.html
140pub fn debug_fn<F>(f: F) -> FieldFn<F>
141where
142 F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result + Clone,
143{
144 FieldFn(f)
145}
146
147/// A [`FormatFields`] implementation that formats fields by calling a function
148/// or closure.
149///
150/// [`FormatFields`]: trait.FormatFields.html
151#[derive(Debug, Clone)]
152pub struct FieldFn<F>(F);
153/// The [visitor] produced by [`FieldFn`]'s [`MakeVisitor`] implementation.
154///
155/// [visitor]: ../../field/trait.Visit.html
156/// [`FieldFn`]: struct.FieldFn.html
157/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html
158pub struct FieldFnVisitor<'a, F> {
159 f: F,
160 writer: &'a mut dyn fmt::Write,
161 result: fmt::Result,
162}
163/// Marker for `Format` that indicates that the compact log format should be used.
164///
165/// The compact format only includes the fields from the most recently entered span.
166#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
167pub struct Compact;
168
169/// Marker for `Format` that indicates that the verbose log format should be used.
170///
171/// The full format includes fields from all entered spans.
172#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
173pub struct Full;
174
175/// A pre-configured event formatter.
176///
177/// You will usually want to use this as the `FormatEvent` for a `FmtSubscriber`.
178///
179/// The default logging format, [`Full`] includes all fields in each event and its containing
180/// spans. The [`Compact`] logging format includes only the fields from the most-recently-entered
181/// span.
182#[derive(Debug, Clone)]
183pub struct Format<F = Full, T = SystemTime> {
184 format: F,
185 pub(crate) timer: T,
186 pub(crate) ansi: bool,
187 pub(crate) display_target: bool,
188 pub(crate) display_level: bool,
3dfed10e
XL
189 pub(crate) display_thread_id: bool,
190 pub(crate) display_thread_name: bool,
f035d41b
XL
191}
192
193impl Default for Format<Full, SystemTime> {
194 fn default() -> Self {
195 Format {
196 format: Full,
197 timer: SystemTime,
198 ansi: true,
199 display_target: true,
200 display_level: true,
3dfed10e
XL
201 display_thread_id: false,
202 display_thread_name: false,
f035d41b
XL
203 }
204 }
205}
206
207impl<F, T> Format<F, T> {
208 /// Use a less verbose output format.
209 ///
210 /// See [`Compact`].
211 pub fn compact(self) -> Format<Compact, T> {
212 Format {
213 format: Compact,
214 timer: self.timer,
215 ansi: self.ansi,
216 display_target: self.display_target,
217 display_level: self.display_level,
3dfed10e
XL
218 display_thread_id: self.display_thread_id,
219 display_thread_name: self.display_thread_name,
f035d41b
XL
220 }
221 }
222
5869c6ff
XL
223 /// Use an excessively pretty, human-readable output format.
224 ///
225 /// See [`Pretty`].
226 ///
227 /// Note that this requires the "ansi" feature to be enabled.
228 #[cfg(feature = "ansi")]
229 #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
230 pub fn pretty(self) -> Format<Pretty, T> {
231 Format {
232 format: Pretty::default(),
233 timer: self.timer,
234 ansi: self.ansi,
235 display_target: self.display_target,
236 display_level: self.display_level,
237 display_thread_id: self.display_thread_id,
238 display_thread_name: self.display_thread_name,
239 }
240 }
241
f035d41b
XL
242 /// Use the full JSON format.
243 ///
244 /// The full format includes fields from all entered spans.
245 ///
246 /// # Example Output
247 ///
248 /// ```ignore,json
249 /// {"timestamp":"Feb 20 11:28:15.096","level":"INFO","target":"mycrate","fields":{"message":"some message", "key": "value"}}
250 /// ```
251 ///
252 /// # Options
253 ///
254 /// - [`Format::flatten_event`] can be used to enable flattening event fields into the root
255 /// object.
256 ///
257 /// [`Format::flatten_event`]: #method.flatten_event
258 #[cfg(feature = "json")]
259 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
260 pub fn json(self) -> Format<Json, T> {
261 Format {
262 format: Json::default(),
263 timer: self.timer,
264 ansi: self.ansi,
265 display_target: self.display_target,
266 display_level: self.display_level,
3dfed10e
XL
267 display_thread_id: self.display_thread_id,
268 display_thread_name: self.display_thread_name,
f035d41b
XL
269 }
270 }
271
272 /// Use the given [`timer`] for log message timestamps.
273 ///
274 /// See [`time`] for the provided timer implementations.
275 ///
276 /// Note that using the `chrono` feature flag enables the
277 /// additional time formatters [`ChronoUtc`] and [`ChronoLocal`].
278 ///
279 /// [`time`]: ./time/index.html
280 /// [`timer`]: ./time/trait.FormatTime.html
281 /// [`ChronoUtc`]: ./time/struct.ChronoUtc.html
282 /// [`ChronoLocal`]: ./time/struct.ChronoLocal.html
283 pub fn with_timer<T2>(self, timer: T2) -> Format<F, T2> {
284 Format {
285 format: self.format,
286 timer,
287 ansi: self.ansi,
288 display_target: self.display_target,
289 display_level: self.display_level,
3dfed10e
XL
290 display_thread_id: self.display_thread_id,
291 display_thread_name: self.display_thread_name,
f035d41b
XL
292 }
293 }
294
295 /// Do not emit timestamps with log messages.
296 pub fn without_time(self) -> Format<F, ()> {
297 Format {
298 format: self.format,
299 timer: (),
300 ansi: self.ansi,
301 display_target: self.display_target,
302 display_level: self.display_level,
3dfed10e
XL
303 display_thread_id: self.display_thread_id,
304 display_thread_name: self.display_thread_name,
f035d41b
XL
305 }
306 }
307
308 /// Enable ANSI terminal colors for formatted output.
309 pub fn with_ansi(self, ansi: bool) -> Format<F, T> {
310 Format { ansi, ..self }
311 }
312
313 /// Sets whether or not an event's target is displayed.
314 pub fn with_target(self, display_target: bool) -> Format<F, T> {
315 Format {
316 display_target,
317 ..self
318 }
319 }
320
321 /// Sets whether or not an event's level is displayed.
322 pub fn with_level(self, display_level: bool) -> Format<F, T> {
323 Format {
324 display_level,
325 ..self
326 }
327 }
3dfed10e
XL
328
329 /// Sets whether or not the [thread ID] of the current thread is displayed
330 /// when formatting events
331 ///
332 /// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html
333 pub fn with_thread_ids(self, display_thread_id: bool) -> Format<F, T> {
334 Format {
335 display_thread_id,
336 ..self
337 }
338 }
339
340 /// Sets whether or not the [name] of the current thread is displayed
341 /// when formatting events
342 ///
343 /// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads
344 pub fn with_thread_names(self, display_thread_name: bool) -> Format<F, T> {
345 Format {
346 display_thread_name,
347 ..self
348 }
349 }
f035d41b
XL
350}
351
352#[cfg(feature = "json")]
353#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
354impl<T> Format<Json, T> {
355 /// Use the full JSON format with the event's event fields flattened.
356 ///
357 /// # Example Output
358 ///
359 /// ```ignore,json
360 /// {"timestamp":"Feb 20 11:28:15.096","level":"INFO","target":"mycrate", "message":"some message", "key": "value"}
361 /// ```
362 /// See [`Json`](../format/struct.Json.html).
363 #[cfg(feature = "json")]
364 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
365 pub fn flatten_event(mut self, flatten_event: bool) -> Format<Json, T> {
366 self.format.flatten_event(flatten_event);
367 self
368 }
3dfed10e
XL
369
370 /// Sets whether or not the formatter will include the current span in
371 /// formatted events.
372 ///
373 /// See [`format::Json`](../fmt/format/struct.Json.html)
374 #[cfg(feature = "json")]
375 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
376 pub fn with_current_span(mut self, display_current_span: bool) -> Format<Json, T> {
377 self.format.with_current_span(display_current_span);
378 self
379 }
380
381 /// Sets whether or not the formatter will include a list (from root to
382 /// leaf) of all currently entered spans in formatted events.
383 ///
384 /// See [`format::Json`](../fmt/format/struct.Json.html)
385 #[cfg(feature = "json")]
386 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
387 pub fn with_span_list(mut self, display_span_list: bool) -> Format<Json, T> {
388 self.format.with_span_list(display_span_list);
389 self
390 }
f035d41b
XL
391}
392
393impl<S, N, T> FormatEvent<S, N> for Format<Full, T>
394where
395 S: Subscriber + for<'a> LookupSpan<'a>,
396 N: for<'a> FormatFields<'a> + 'static,
397 T: FormatTime,
398{
399 fn format_event(
400 &self,
401 ctx: &FmtContext<'_, S, N>,
402 writer: &mut dyn fmt::Write,
403 event: &Event<'_>,
404 ) -> fmt::Result {
405 #[cfg(feature = "tracing-log")]
406 let normalized_meta = event.normalized_metadata();
407 #[cfg(feature = "tracing-log")]
408 let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
409 #[cfg(not(feature = "tracing-log"))]
410 let meta = event.metadata();
411 #[cfg(feature = "ansi")]
412 time::write(&self.timer, writer, self.ansi)?;
413 #[cfg(not(feature = "ansi"))]
414 time::write(&self.timer, writer)?;
415
416 if self.display_level {
417 let fmt_level = {
418 #[cfg(feature = "ansi")]
419 {
420 FmtLevel::new(meta.level(), self.ansi)
421 }
422 #[cfg(not(feature = "ansi"))]
423 {
424 FmtLevel::new(meta.level())
425 }
426 };
427 write!(writer, "{} ", fmt_level)?;
428 }
429
3dfed10e
XL
430 if self.display_thread_name {
431 let current_thread = std::thread::current();
432 match current_thread.name() {
433 Some(name) => {
434 write!(writer, "{} ", FmtThreadName::new(name))?;
435 }
436 // fall-back to thread id when name is absent and ids are not enabled
437 None if !self.display_thread_id => {
438 write!(writer, "{:0>2?} ", current_thread.id())?;
439 }
440 _ => {}
441 }
442 }
443
444 if self.display_thread_id {
445 write!(writer, "{:0>2?} ", std::thread::current().id())?;
446 }
447
f035d41b
XL
448 let full_ctx = {
449 #[cfg(feature = "ansi")]
450 {
451 FullCtx::new(ctx, event.parent(), self.ansi)
452 }
453 #[cfg(not(feature = "ansi"))]
454 {
455 FullCtx::new(ctx, event.parent())
456 }
457 };
458
459 write!(writer, "{}", full_ctx)?;
460 if self.display_target {
461 write!(writer, "{}: ", meta.target())?;
462 }
463 ctx.format_fields(writer, event)?;
464 writeln!(writer)
465 }
466}
467
468impl<S, N, T> FormatEvent<S, N> for Format<Compact, T>
469where
470 S: Subscriber + for<'a> LookupSpan<'a>,
471 N: for<'a> FormatFields<'a> + 'static,
472 T: FormatTime,
473{
474 fn format_event(
475 &self,
476 ctx: &FmtContext<'_, S, N>,
477 writer: &mut dyn fmt::Write,
478 event: &Event<'_>,
479 ) -> fmt::Result {
480 #[cfg(feature = "tracing-log")]
481 let normalized_meta = event.normalized_metadata();
482 #[cfg(feature = "tracing-log")]
483 let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
484 #[cfg(not(feature = "tracing-log"))]
485 let meta = event.metadata();
486 #[cfg(feature = "ansi")]
487 time::write(&self.timer, writer, self.ansi)?;
488 #[cfg(not(feature = "ansi"))]
489 time::write(&self.timer, writer)?;
490
491 if self.display_level {
492 let fmt_level = {
493 #[cfg(feature = "ansi")]
494 {
495 FmtLevel::new(meta.level(), self.ansi)
496 }
497 #[cfg(not(feature = "ansi"))]
498 {
499 FmtLevel::new(meta.level())
500 }
501 };
502 write!(writer, "{} ", fmt_level)?;
503 }
504
3dfed10e
XL
505 if self.display_thread_name {
506 let current_thread = std::thread::current();
507 match current_thread.name() {
508 Some(name) => {
509 write!(writer, "{} ", FmtThreadName::new(name))?;
510 }
511 // fall-back to thread id when name is absent and ids are not enabled
512 None if !self.display_thread_id => {
513 write!(writer, "{:0>2?} ", current_thread.id())?;
514 }
515 _ => {}
516 }
517 }
518
519 if self.display_thread_id {
520 write!(writer, "{:0>2?} ", std::thread::current().id())?;
521 }
522
f035d41b
XL
523 let fmt_ctx = {
524 #[cfg(feature = "ansi")]
525 {
526 FmtCtx::new(&ctx, event.parent(), self.ansi)
527 }
528 #[cfg(not(feature = "ansi"))]
529 {
530 FmtCtx::new(&ctx, event.parent())
531 }
532 };
533 write!(writer, "{}", fmt_ctx)?;
534 if self.display_target {
535 write!(writer, "{}:", meta.target())?;
536 }
537 ctx.format_fields(writer, event)?;
538 let span = ctx.ctx.current_span();
539 if let Some(id) = span.id() {
540 if let Some(span) = ctx.ctx.metadata(id) {
541 write!(writer, "{}", span.fields()).unwrap_or(());
542 }
543 }
544 writeln!(writer)
545 }
546}
547
548// === impl FormatFields ===
5869c6ff 549
f035d41b
XL
550impl<'writer, M> FormatFields<'writer> for M
551where
552 M: MakeOutput<&'writer mut dyn fmt::Write, fmt::Result>,
553 M::Visitor: VisitFmt + VisitOutput<fmt::Result>,
554{
555 fn format_fields<R: RecordFields>(
556 &self,
557 writer: &'writer mut dyn fmt::Write,
558 fields: R,
559 ) -> fmt::Result {
560 let mut v = self.make_visitor(writer);
561 fields.record(&mut v);
562 v.finish()
563 }
564}
565/// The default [`FormatFields`] implementation.
566///
567/// [`FormatFields`]: trait.FormatFields.html
568#[derive(Debug)]
569pub struct DefaultFields {
570 // reserve the ability to add fields to this without causing a breaking
571 // change in the future.
572 _private: (),
573}
574
575/// The [visitor] produced by [`DefaultFields`]'s [`MakeVisitor`] implementation.
576///
577/// [visitor]: ../../field/trait.Visit.html
578/// [`DefaultFields`]: struct.DefaultFields.html
579/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html
580pub struct DefaultVisitor<'a> {
581 writer: &'a mut dyn Write,
582 is_empty: bool,
583 result: fmt::Result,
584}
585
586impl DefaultFields {
587 /// Returns a new default [`FormatFields`] implementation.
588 ///
589 /// [`FormatFields`]: trait.FormatFields.html
590 pub fn new() -> Self {
591 Self { _private: () }
592 }
593}
594
595impl Default for DefaultFields {
596 fn default() -> Self {
597 Self::new()
598 }
599}
600
601impl<'a> MakeVisitor<&'a mut dyn Write> for DefaultFields {
602 type Visitor = DefaultVisitor<'a>;
603
604 #[inline]
605 fn make_visitor(&self, target: &'a mut dyn Write) -> Self::Visitor {
606 DefaultVisitor::new(target, true)
607 }
608}
609
610// === impl DefaultVisitor ===
611
612impl<'a> DefaultVisitor<'a> {
613 /// Returns a new default visitor that formats to the provided `writer`.
614 ///
615 /// # Arguments
616 /// - `writer`: the writer to format to.
617 /// - `is_empty`: whether or not any fields have been previously written to
618 /// that writer.
619 pub fn new(writer: &'a mut dyn Write, is_empty: bool) -> Self {
620 Self {
621 writer,
622 is_empty,
623 result: Ok(()),
624 }
625 }
626
627 fn maybe_pad(&mut self) {
628 if self.is_empty {
629 self.is_empty = false;
630 } else {
631 self.result = write!(self.writer, " ");
632 }
633 }
634}
635
636impl<'a> field::Visit for DefaultVisitor<'a> {
637 fn record_str(&mut self, field: &Field, value: &str) {
638 if self.result.is_err() {
639 return;
640 }
641
642 if field.name() == "message" {
643 self.record_debug(field, &format_args!("{}", value))
644 } else {
645 self.record_debug(field, &value)
646 }
647 }
648
649 fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
650 if let Some(source) = value.source() {
5869c6ff 651 self.record_debug(field, &format_args!("{}, {}: {}", value, field, source))
f035d41b
XL
652 } else {
653 self.record_debug(field, &format_args!("{}", value))
654 }
655 }
656
657 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
658 if self.result.is_err() {
659 return;
660 }
661
662 self.maybe_pad();
663 self.result = match field.name() {
664 "message" => write!(self.writer, "{:?}", value),
665 // Skip fields that are actually log metadata that have already been handled
666 #[cfg(feature = "tracing-log")]
667 name if name.starts_with("log.") => Ok(()),
668 name if name.starts_with("r#") => write!(self.writer, "{}={:?}", &name[2..], value),
669 name => write!(self.writer, "{}={:?}", name, value),
670 };
671 }
672}
673
674impl<'a> crate::field::VisitOutput<fmt::Result> for DefaultVisitor<'a> {
675 fn finish(self) -> fmt::Result {
676 self.result
677 }
678}
679
680impl<'a> crate::field::VisitFmt for DefaultVisitor<'a> {
681 fn writer(&mut self) -> &mut dyn fmt::Write {
682 self.writer
683 }
684}
685
686impl<'a> fmt::Debug for DefaultVisitor<'a> {
687 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
688 f.debug_struct("DefaultVisitor")
689 .field("writer", &format_args!("<dyn fmt::Write>"))
690 .field("is_empty", &self.is_empty)
691 .field("result", &self.result)
692 .finish()
693 }
694}
695
696struct FmtCtx<'a, S, N> {
697 ctx: &'a FmtContext<'a, S, N>,
698 span: Option<&'a span::Id>,
699 #[cfg(feature = "ansi")]
700 ansi: bool,
701}
702
703impl<'a, S, N: 'a> FmtCtx<'a, S, N>
704where
705 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
706 N: for<'writer> FormatFields<'writer> + 'static,
707{
708 #[cfg(feature = "ansi")]
709 pub(crate) fn new(
710 ctx: &'a FmtContext<'_, S, N>,
711 span: Option<&'a span::Id>,
712 ansi: bool,
713 ) -> Self {
714 Self { ctx, ansi, span }
715 }
716
717 #[cfg(not(feature = "ansi"))]
718 pub(crate) fn new(ctx: &'a FmtContext<'_, S, N>, span: Option<&'a span::Id>) -> Self {
719 Self { ctx, span }
720 }
721
722 fn bold(&self) -> Style {
723 #[cfg(feature = "ansi")]
724 {
725 if self.ansi {
726 return Style::new().bold();
727 }
728 }
729
730 Style::new()
731 }
732}
733
734impl<'a, S, N: 'a> fmt::Display for FmtCtx<'a, S, N>
735where
736 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
737 N: for<'writer> FormatFields<'writer> + 'static,
738{
739 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
740 let bold = self.bold();
741 let mut seen = false;
742
743 let span = self
744 .span
745 .and_then(|id| self.ctx.ctx.span(&id))
746 .or_else(|| self.ctx.ctx.lookup_current());
747
748 let scope = span
749 .into_iter()
750 .flat_map(|span| span.from_root().chain(iter::once(span)));
751
752 for span in scope {
753 seen = true;
754 write!(f, "{}:", bold.paint(span.metadata().name()))?;
755 }
756
757 if seen {
758 f.write_char(' ')?;
759 }
760 Ok(())
761 }
762}
763
764struct FullCtx<'a, S, N>
765where
766 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
767 N: for<'writer> FormatFields<'writer> + 'static,
768{
769 ctx: &'a FmtContext<'a, S, N>,
770 span: Option<&'a span::Id>,
771 #[cfg(feature = "ansi")]
772 ansi: bool,
773}
774
775impl<'a, S, N: 'a> FullCtx<'a, S, N>
776where
777 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
778 N: for<'writer> FormatFields<'writer> + 'static,
779{
780 #[cfg(feature = "ansi")]
781 pub(crate) fn new(
782 ctx: &'a FmtContext<'a, S, N>,
783 span: Option<&'a span::Id>,
784 ansi: bool,
785 ) -> Self {
786 Self { ctx, span, ansi }
787 }
788
789 #[cfg(not(feature = "ansi"))]
790 pub(crate) fn new(ctx: &'a FmtContext<'a, S, N>, span: Option<&'a span::Id>) -> Self {
791 Self { ctx, span }
792 }
793
794 fn bold(&self) -> Style {
795 #[cfg(feature = "ansi")]
796 {
797 if self.ansi {
798 return Style::new().bold();
799 }
800 }
801
802 Style::new()
803 }
804}
805
806impl<'a, S, N> fmt::Display for FullCtx<'a, S, N>
807where
808 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
809 N: for<'writer> FormatFields<'writer> + 'static,
810{
811 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
812 let bold = self.bold();
813 let mut seen = false;
814
815 let span = self
816 .span
817 .and_then(|id| self.ctx.ctx.span(&id))
818 .or_else(|| self.ctx.ctx.lookup_current());
819
820 let scope = span
821 .into_iter()
822 .flat_map(|span| span.from_root().chain(iter::once(span)));
823
824 for span in scope {
825 write!(f, "{}", bold.paint(span.metadata().name()))?;
826 seen = true;
827
828 let ext = span.extensions();
829 let fields = &ext
830 .get::<FormattedFields<N>>()
831 .expect("Unable to find FormattedFields in extensions; this is a bug");
832 if !fields.is_empty() {
833 write!(f, "{}{}{}", bold.paint("{"), fields, bold.paint("}"))?;
834 }
835 f.write_char(':')?;
836 }
837
838 if seen {
839 f.write_char(' ')?;
840 }
841 Ok(())
842 }
843}
844
845#[cfg(not(feature = "ansi"))]
846struct Style;
847
848#[cfg(not(feature = "ansi"))]
849impl Style {
850 fn new() -> Self {
851 Style
852 }
853 fn paint(&self, d: impl fmt::Display) -> impl fmt::Display {
854 d
855 }
856}
857
3dfed10e
XL
858struct FmtThreadName<'a> {
859 name: &'a str,
860}
861
862impl<'a> FmtThreadName<'a> {
863 pub(crate) fn new(name: &'a str) -> Self {
864 Self { name }
865 }
866}
867
868impl<'a> fmt::Display for FmtThreadName<'a> {
869 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
870 use std::sync::atomic::{
871 AtomicUsize,
872 Ordering::{AcqRel, Acquire, Relaxed},
873 };
874
875 // Track the longest thread name length we've seen so far in an atomic,
876 // so that it can be updated by any thread.
877 static MAX_LEN: AtomicUsize = AtomicUsize::new(0);
878 let len = self.name.len();
879 // Snapshot the current max thread name length.
880 let mut max_len = MAX_LEN.load(Relaxed);
881
882 while len > max_len {
883 // Try to set a new max length, if it is still the value we took a
884 // snapshot of.
885 match MAX_LEN.compare_exchange(max_len, len, AcqRel, Acquire) {
886 // We successfully set the new max value
887 Ok(_) => break,
888 // Another thread set a new max value since we last observed
889 // it! It's possible that the new length is actually longer than
890 // ours, so we'll loop again and check whether our length is
891 // still the longest. If not, we'll just use the newer value.
892 Err(actual) => max_len = actual,
893 }
894 }
895
896 // pad thread name using `max_len`
897 write!(f, "{:>width$}", self.name, width = max_len)
898 }
899}
900
f035d41b
XL
901struct FmtLevel<'a> {
902 level: &'a Level,
903 #[cfg(feature = "ansi")]
904 ansi: bool,
905}
906
907impl<'a> FmtLevel<'a> {
908 #[cfg(feature = "ansi")]
909 pub(crate) fn new(level: &'a Level, ansi: bool) -> Self {
910 Self { level, ansi }
911 }
912
913 #[cfg(not(feature = "ansi"))]
914 pub(crate) fn new(level: &'a Level) -> Self {
915 Self { level }
916 }
917}
918
919const TRACE_STR: &str = "TRACE";
920const DEBUG_STR: &str = "DEBUG";
921const INFO_STR: &str = " INFO";
922const WARN_STR: &str = " WARN";
923const ERROR_STR: &str = "ERROR";
924
925#[cfg(not(feature = "ansi"))]
926impl<'a> fmt::Display for FmtLevel<'a> {
927 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
928 match *self.level {
929 Level::TRACE => f.pad(TRACE_STR),
930 Level::DEBUG => f.pad(DEBUG_STR),
931 Level::INFO => f.pad(INFO_STR),
932 Level::WARN => f.pad(WARN_STR),
933 Level::ERROR => f.pad(ERROR_STR),
934 }
935 }
936}
937
938#[cfg(feature = "ansi")]
939impl<'a> fmt::Display for FmtLevel<'a> {
940 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
941 if self.ansi {
942 match *self.level {
943 Level::TRACE => write!(f, "{}", Colour::Purple.paint(TRACE_STR)),
944 Level::DEBUG => write!(f, "{}", Colour::Blue.paint(DEBUG_STR)),
945 Level::INFO => write!(f, "{}", Colour::Green.paint(INFO_STR)),
946 Level::WARN => write!(f, "{}", Colour::Yellow.paint(WARN_STR)),
947 Level::ERROR => write!(f, "{}", Colour::Red.paint(ERROR_STR)),
948 }
949 } else {
950 match *self.level {
951 Level::TRACE => f.pad(TRACE_STR),
952 Level::DEBUG => f.pad(DEBUG_STR),
953 Level::INFO => f.pad(INFO_STR),
954 Level::WARN => f.pad(WARN_STR),
955 Level::ERROR => f.pad(ERROR_STR),
956 }
957 }
958 }
959}
960
961// === impl FieldFn ===
962
963impl<'a, F> MakeVisitor<&'a mut dyn fmt::Write> for FieldFn<F>
964where
965 F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result + Clone,
966{
967 type Visitor = FieldFnVisitor<'a, F>;
968
969 fn make_visitor(&self, writer: &'a mut dyn fmt::Write) -> Self::Visitor {
970 FieldFnVisitor {
971 writer,
972 f: self.0.clone(),
973 result: Ok(()),
974 }
975 }
976}
977
978impl<'a, F> Visit for FieldFnVisitor<'a, F>
979where
980 F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result,
981{
982 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
983 if self.result.is_ok() {
984 self.result = (self.f)(&mut self.writer, field, value)
985 }
986 }
987}
988
989impl<'a, F> VisitOutput<fmt::Result> for FieldFnVisitor<'a, F>
990where
991 F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result,
992{
993 fn finish(self) -> fmt::Result {
994 self.result
995 }
996}
997
998impl<'a, F> VisitFmt for FieldFnVisitor<'a, F>
999where
1000 F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result,
1001{
1002 fn writer(&mut self) -> &mut dyn fmt::Write {
1003 &mut *self.writer
1004 }
1005}
1006
1007impl<'a, F> fmt::Debug for FieldFnVisitor<'a, F> {
1008 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1009 f.debug_struct("FieldFnVisitor")
1010 .field("f", &format_args!("<Fn>"))
1011 .field("writer", &format_args!("<dyn fmt::Write>"))
1012 .field("result", &self.result)
1013 .finish()
1014 }
1015}
1016
1017// === printing synthetic Span events ===
1018
1019/// Configures what points in the span lifecycle are logged as events.
1020///
1021/// See also [`with_span_events`](../struct.SubscriberBuilder.html#method.with_span_events).
1022#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
1023pub struct FmtSpan(FmtSpanInner);
1024
1025impl FmtSpan {
1026 /// spans are ignored (this is the default)
1027 pub const NONE: FmtSpan = FmtSpan(FmtSpanInner::None);
1028 /// one event per enter/exit of a span
1029 pub const ACTIVE: FmtSpan = FmtSpan(FmtSpanInner::Active);
1030 /// one event when the span is dropped
1031 pub const CLOSE: FmtSpan = FmtSpan(FmtSpanInner::Close);
1032 /// events at all points (new, enter, exit, drop)
1033 pub const FULL: FmtSpan = FmtSpan(FmtSpanInner::Full);
1034}
1035
1036impl Debug for FmtSpan {
1037 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1038 match self.0 {
1039 FmtSpanInner::None => f.write_str("FmtSpan::NONE"),
1040 FmtSpanInner::Active => f.write_str("FmtSpan::ACTIVE"),
1041 FmtSpanInner::Close => f.write_str("FmtSpan::CLOSE"),
1042 FmtSpanInner::Full => f.write_str("FmtSpan::FULL"),
1043 }
1044 }
1045}
1046
1047#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
1048enum FmtSpanInner {
1049 /// spans are ignored (this is the default)
1050 None,
1051 /// one event per enter/exit of a span
1052 Active,
1053 /// one event when the span is dropped
1054 Close,
1055 /// events at all points (new, enter, exit, drop)
1056 Full,
1057}
1058
1059pub(super) struct FmtSpanConfig {
1060 pub(super) kind: FmtSpan,
1061 pub(super) fmt_timing: bool,
1062}
1063
1064impl FmtSpanConfig {
1065 pub(super) fn without_time(self) -> Self {
1066 Self {
1067 kind: self.kind,
1068 fmt_timing: false,
1069 }
1070 }
1071 pub(super) fn with_kind(self, kind: FmtSpan) -> Self {
1072 Self {
1073 kind,
1074 fmt_timing: self.fmt_timing,
1075 }
1076 }
1077 pub(super) fn trace_new(&self) -> bool {
29967ef6 1078 matches!(self.kind, FmtSpan::FULL)
f035d41b
XL
1079 }
1080 pub(super) fn trace_active(&self) -> bool {
29967ef6 1081 matches!(self.kind, FmtSpan::ACTIVE | FmtSpan::FULL)
f035d41b
XL
1082 }
1083 pub(super) fn trace_close(&self) -> bool {
29967ef6 1084 matches!(self.kind, FmtSpan::CLOSE | FmtSpan::FULL)
f035d41b
XL
1085 }
1086}
1087
1088impl Debug for FmtSpanConfig {
1089 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1090 self.kind.fmt(f)
1091 }
1092}
1093
1094impl Default for FmtSpanConfig {
1095 fn default() -> Self {
1096 Self {
1097 kind: FmtSpan::NONE,
1098 fmt_timing: true,
1099 }
1100 }
1101}
1102
1103#[repr(transparent)]
1104pub(super) struct TimingDisplay(pub(super) u64);
1105impl Display for TimingDisplay {
1106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1107 let mut t = self.0 as f64;
1108 for unit in ["ns", "µs", "ms", "s"].iter() {
1109 if t < 10.0 {
1110 return write!(f, "{:.2}{}", t, unit);
1111 } else if t < 100.0 {
1112 return write!(f, "{:.1}{}", t, unit);
1113 } else if t < 1000.0 {
1114 return write!(f, "{:.0}{}", t, unit);
1115 }
1116 t /= 1000.0;
1117 }
1118 write!(f, "{:.0}s", t * 1000.0)
1119 }
1120}
1121
1122#[cfg(test)]
1123pub(super) mod test {
1124
1125 use crate::fmt::{test::MockWriter, time::FormatTime};
1126 use lazy_static::lazy_static;
1127 use tracing::{self, subscriber::with_default};
1128
1129 use super::TimingDisplay;
1130 use std::{fmt, sync::Mutex};
1131
1132 pub(crate) struct MockTime;
1133 impl FormatTime for MockTime {
1134 fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result {
1135 write!(w, "fake time")
1136 }
1137 }
1138
1139 #[cfg(feature = "ansi")]
1140 #[test]
1141 fn with_ansi_true() {
1142 lazy_static! {
1143 static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
1144 }
1145
1146 let make_writer = || MockWriter::new(&BUF);
1147 let expected = "\u{1b}[2mfake time\u{1b}[0m \u{1b}[32m INFO\u{1b}[0m tracing_subscriber::fmt::format::test: some ansi test\n";
1148 test_ansi(make_writer, expected, true, &BUF);
1149 }
1150
1151 #[cfg(feature = "ansi")]
1152 #[test]
1153 fn with_ansi_false() {
1154 lazy_static! {
1155 static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
1156 }
1157
1158 let make_writer = || MockWriter::new(&BUF);
1159 let expected = "fake time INFO tracing_subscriber::fmt::format::test: some ansi test\n";
1160
1161 test_ansi(make_writer, expected, false, &BUF);
1162 }
1163
1164 #[cfg(not(feature = "ansi"))]
1165 #[test]
1166 fn without_ansi() {
1167 lazy_static! {
1168 static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
1169 }
1170
1171 let make_writer = || MockWriter::new(&BUF);
1172 let expected = "fake time INFO tracing_subscriber::fmt::format::test: some ansi test\n";
1173 let subscriber = crate::fmt::Subscriber::builder()
1174 .with_writer(make_writer)
1175 .with_timer(MockTime)
1176 .finish();
1177
1178 with_default(subscriber, || {
1179 tracing::info!("some ansi test");
1180 });
1181
1182 let actual = String::from_utf8(BUF.try_lock().unwrap().to_vec()).unwrap();
1183 assert_eq!(expected, actual.as_str());
1184 }
1185
1186 #[cfg(feature = "ansi")]
1187 fn test_ansi<T>(make_writer: T, expected: &str, is_ansi: bool, buf: &Mutex<Vec<u8>>)
1188 where
1189 T: crate::fmt::MakeWriter + Send + Sync + 'static,
1190 {
1191 let subscriber = crate::fmt::Subscriber::builder()
1192 .with_writer(make_writer)
1193 .with_ansi(is_ansi)
1194 .with_timer(MockTime)
1195 .finish();
1196
1197 with_default(subscriber, || {
1198 tracing::info!("some ansi test");
1199 });
1200
1201 let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
1202 assert_eq!(expected, actual.as_str());
1203 }
1204
1205 #[test]
1206 fn without_level() {
1207 lazy_static! {
1208 static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
1209 }
1210
1211 let make_writer = || MockWriter::new(&BUF);
1212 let subscriber = crate::fmt::Subscriber::builder()
1213 .with_writer(make_writer)
1214 .with_level(false)
1215 .with_ansi(false)
1216 .with_timer(MockTime)
1217 .finish();
1218
1219 with_default(subscriber, || {
1220 tracing::info!("hello");
1221 });
1222 let actual = String::from_utf8(BUF.try_lock().unwrap().to_vec()).unwrap();
1223 assert_eq!(
1224 "fake time tracing_subscriber::fmt::format::test: hello\n",
1225 actual.as_str()
1226 );
1227 }
1228
1229 #[test]
1230 fn overridden_parents() {
1231 lazy_static! {
1232 static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
1233 }
1234
1235 let make_writer = || MockWriter::new(&BUF);
1236 let subscriber = crate::fmt::Subscriber::builder()
1237 .with_writer(make_writer)
1238 .with_level(false)
1239 .with_ansi(false)
1240 .with_timer(MockTime)
1241 .finish();
1242
1243 with_default(subscriber, || {
1244 let span1 = tracing::info_span!("span1");
1245 let span2 = tracing::info_span!(parent: &span1, "span2");
1246 tracing::info!(parent: &span2, "hello");
1247 });
1248 let actual = String::from_utf8(BUF.try_lock().unwrap().to_vec()).unwrap();
1249 assert_eq!(
1250 "fake time span1:span2: tracing_subscriber::fmt::format::test: hello\n",
1251 actual.as_str()
1252 );
1253 }
1254
1255 #[test]
1256 fn overridden_parents_in_scope() {
1257 lazy_static! {
1258 static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
1259 }
1260
1261 let make_writer = || MockWriter::new(&BUF);
1262 let subscriber = crate::fmt::Subscriber::builder()
1263 .with_writer(make_writer)
1264 .with_level(false)
1265 .with_ansi(false)
1266 .with_timer(MockTime)
1267 .finish();
1268
1269 let actual = || {
1270 let mut buf = BUF.try_lock().unwrap();
1271 let val = String::from_utf8(buf.to_vec()).unwrap();
1272 buf.clear();
1273 val
1274 };
1275
1276 with_default(subscriber, || {
1277 let span1 = tracing::info_span!("span1");
1278 let span2 = tracing::info_span!(parent: &span1, "span2");
1279 let span3 = tracing::info_span!("span3");
1280 let _e3 = span3.enter();
1281
1282 tracing::info!("hello");
1283 assert_eq!(
1284 "fake time span3: tracing_subscriber::fmt::format::test: hello\n",
1285 actual().as_str()
1286 );
1287
1288 tracing::info!(parent: &span2, "hello");
1289 assert_eq!(
1290 "fake time span1:span2: tracing_subscriber::fmt::format::test: hello\n",
1291 actual().as_str()
1292 );
1293 });
1294 }
1295
1296 #[test]
1297 fn format_nanos() {
1298 fn fmt(t: u64) -> String {
1299 TimingDisplay(t).to_string()
1300 }
1301
1302 assert_eq!(fmt(1), "1.00ns");
1303 assert_eq!(fmt(12), "12.0ns");
1304 assert_eq!(fmt(123), "123ns");
1305 assert_eq!(fmt(1234), "1.23µs");
1306 assert_eq!(fmt(12345), "12.3µs");
1307 assert_eq!(fmt(123456), "123µs");
1308 assert_eq!(fmt(1234567), "1.23ms");
1309 assert_eq!(fmt(12345678), "12.3ms");
1310 assert_eq!(fmt(123456789), "123ms");
1311 assert_eq!(fmt(1234567890), "1.23s");
1312 assert_eq!(fmt(12345678901), "12.3s");
1313 assert_eq!(fmt(123456789012), "123s");
1314 assert_eq!(fmt(1234567890123), "1235s");
1315 }
1316}