🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

tracing_subscriber/fmt/
fmt_subscriber.rs

1use crate::{
2    field::RecordFields,
3    fmt::{format, FormatEvent, FormatFields, MakeWriter, TestWriter},
4    registry::{self, LookupSpan, SpanRef},
5    subscribe::{self, Context},
6};
7use format::{FmtSpan, TimingDisplay};
8use std::{
9    any::TypeId, cell::RefCell, env, fmt, io, marker::PhantomData, ops::Deref, ptr::NonNull,
10    time::Instant,
11};
12use tracing_core::{
13    field,
14    span::{Attributes, Current, Id, Record},
15    Collect, Event, Metadata,
16};
17
18/// A [`Subscriber`] that logs formatted representations of `tracing` events.
19///
20/// ## Examples
21///
22/// Constructing a subscriber with the default configuration:
23///
24/// ```rust
25/// use tracing_subscriber::{fmt, Registry};
26/// use tracing_subscriber::subscribe::CollectExt;
27///
28/// let collector = Registry::default()
29///     .with(fmt::Subscriber::default());
30///
31/// tracing::collect::set_global_default(collector).unwrap();
32/// ```
33///
34/// Overriding the subscriber's behavior:
35///
36/// ```rust
37/// use tracing_subscriber::{fmt, Registry};
38/// use tracing_subscriber::subscribe::CollectExt;
39///
40/// let fmt_subscriber = fmt::subscriber()
41///    .with_target(false) // don't include event targets when logging
42///    .with_level(false); // don't include event levels when logging
43///
44/// let collector = Registry::default().with(fmt_subscriber);
45/// # tracing::collect::set_global_default(collector).unwrap();
46/// ```
47///
48/// Setting a custom event formatter:
49///
50/// ```rust
51/// use tracing_subscriber::fmt::{self, format, time};
52/// use tracing_subscriber::Subscribe;
53///
54/// let fmt = format().with_timer(time::Uptime::default());
55/// let fmt_subscriber = fmt::subscriber()
56///     .event_format(fmt)
57///     .with_target(false);
58/// # let subscriber = fmt_subscriber.with_collector(tracing_subscriber::registry::Registry::default());
59/// # tracing::collect::set_global_default(subscriber).unwrap();
60/// ```
61///
62/// [`Subscriber`]: subscribe::Subscribe
63#[derive(Debug)]
64#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
65pub struct Subscriber<C, N = format::DefaultFields, E = format::Format, W = fn() -> io::Stdout> {
66    make_writer: W,
67    fmt_fields: N,
68    fmt_event: E,
69    fmt_span: format::FmtSpanConfig,
70    is_ansi: bool,
71    log_internal_errors: bool,
72    _inner: PhantomData<fn(C)>,
73}
74
75impl<C> Subscriber<C> {
76    /// Returns a new [`Subscriber`] with the default configuration.
77    pub fn new() -> Self {
78        Self::default()
79    }
80}
81
82// This needs to be a separate impl block because they place different bounds on the type parameters.
83impl<C, N, E, W> Subscriber<C, N, E, W>
84where
85    C: Collect + for<'a> LookupSpan<'a>,
86    N: for<'writer> FormatFields<'writer> + 'static,
87    W: for<'writer> MakeWriter<'writer> + 'static,
88{
89    /// Sets the [event formatter][`FormatEvent`] that the subscriber will use to
90    /// format events.
91    ///
92    /// The event formatter may be any type implementing the [`FormatEvent`]
93    /// trait, which is implemented for all functions taking a [`FmtContext`], a
94    /// [`Writer`], and an [`Event`].
95    ///
96    /// # Examples
97    ///
98    /// Setting a type implementing [`FormatEvent`] as the formatter:
99    /// ```rust
100    /// use tracing_subscriber::fmt::{self, format};
101    ///
102    /// let fmt_subscriber = fmt::subscriber()
103    ///     .event_format(format().compact());
104    /// # // this is necessary for type inference.
105    /// # use tracing_subscriber::Subscribe as _;
106    /// # let _ = fmt_subscriber.with_collector(tracing_subscriber::registry::Registry::default());
107    /// ```
108    /// [`FormatEvent`]: format::FormatEvent
109    /// [`Event`]: tracing::Event
110    /// [`Writer`]: format::Writer
111    pub fn event_format<E2>(self, e: E2) -> Subscriber<C, N, E2, W>
112    where
113        E2: FormatEvent<C, N> + 'static,
114    {
115        Subscriber {
116            fmt_fields: self.fmt_fields,
117            fmt_event: e,
118            fmt_span: self.fmt_span,
119            make_writer: self.make_writer,
120            is_ansi: self.is_ansi,
121            log_internal_errors: self.log_internal_errors,
122            _inner: self._inner,
123        }
124    }
125
126    /// Updates the event formatter by applying a function to the existing event formatter.
127    ///
128    /// This sets the event formatter that the subscriber being built will use to record fields.
129    ///
130    /// # Examples
131    ///
132    /// Updating an event formatter:
133    ///
134    /// ```rust
135    /// let subscriber = tracing_subscriber::fmt::subscriber()
136    ///     .map_event_format(|e| e.compact());
137    /// # // this is necessary for type inference.
138    /// # use tracing_subscriber::Subscribe as _;
139    /// # let _ = subscriber.with_collector(tracing_subscriber::registry::Registry::default());
140    /// ```
141    pub fn map_event_format<E2>(self, f: impl FnOnce(E) -> E2) -> Subscriber<C, N, E2, W>
142    where
143        E2: FormatEvent<C, N> + 'static,
144    {
145        Subscriber {
146            fmt_fields: self.fmt_fields,
147            fmt_event: f(self.fmt_event),
148            fmt_span: self.fmt_span,
149            make_writer: self.make_writer,
150            is_ansi: self.is_ansi,
151            log_internal_errors: self.log_internal_errors,
152            _inner: self._inner,
153        }
154    }
155}
156
157// This needs to be a separate impl block because they place different bounds on the type parameters.
158impl<C, N, E, W> Subscriber<C, N, E, W> {
159    /// Sets the [`MakeWriter`] that the [`Subscriber`] being built will use to write events.
160    ///
161    /// # Examples
162    ///
163    /// Using `stderr` rather than `stdout`:
164    ///
165    /// ```rust
166    /// use std::io;
167    /// use tracing_subscriber::fmt;
168    ///
169    /// let fmt_subscriber = fmt::subscriber()
170    ///     .with_writer(io::stderr);
171    /// # // this is necessary for type inference.
172    /// # use tracing_subscriber::Subscribe as _;
173    /// # let _ = fmt_subscriber.with_collector(tracing_subscriber::registry::Registry::default());
174    /// ```
175    ///
176    /// [`MakeWriter`]: super::writer::MakeWriter
177    /// [`Subscriber`]: super::Subscriber
178    pub fn with_writer<W2>(self, make_writer: W2) -> Subscriber<C, N, E, W2>
179    where
180        W2: for<'writer> MakeWriter<'writer> + 'static,
181    {
182        Subscriber {
183            fmt_fields: self.fmt_fields,
184            fmt_event: self.fmt_event,
185            fmt_span: self.fmt_span,
186            is_ansi: self.is_ansi,
187            log_internal_errors: self.log_internal_errors,
188            make_writer,
189            _inner: self._inner,
190        }
191    }
192
193    /// Borrows the [writer] for this subscriber.
194    ///
195    /// [writer]: MakeWriter
196    pub fn writer(&self) -> &W {
197        &self.make_writer
198    }
199
200    /// Mutably borrows the [writer] for this subscriber.
201    ///
202    /// This method is primarily expected to be used with the
203    /// [`reload::Handle::modify`](crate::reload::Handle::modify) method.
204    ///
205    /// # Examples
206    ///
207    /// ```
208    /// # use tracing::info;
209    /// # use tracing_subscriber::{fmt,reload,Registry,prelude::*};
210    /// # fn non_blocking<T: std::io::Write>(writer: T) -> (fn() -> std::io::Stdout) {
211    /// #   std::io::stdout
212    /// # }
213    /// # fn main() {
214    /// let subscriber = fmt::subscriber().with_writer(non_blocking(std::io::stderr()));
215    /// let (subscriber, reload_handle) = reload::Subscriber::new(subscriber);
216    /// #
217    /// # // specifying the Registry type is required
218    /// # let _: &reload::Handle<fmt::Subscriber<Registry, _, _, _>> = &reload_handle;
219    /// #
220    /// info!("This will be logged to stderr");
221    /// reload_handle.modify(|subscriber| *subscriber.writer_mut() = non_blocking(std::io::stdout()));
222    /// info!("This will be logged to stdout");
223    /// # }
224    /// ```
225    ///
226    /// [writer]: MakeWriter
227    pub fn writer_mut(&mut self) -> &mut W {
228        &mut self.make_writer
229    }
230
231    /// Sets whether this subscriber should use ANSI terminal formatting
232    /// escape codes (such as colors).
233    ///
234    /// This method is primarily expected to be used with the
235    /// [`reload::Handle::modify`](crate::reload::Handle::modify) method when changing
236    /// the writer.
237    #[cfg(feature = "ansi")]
238    #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
239    pub fn set_ansi(&mut self, ansi: bool) {
240        self.is_ansi = ansi;
241    }
242
243    /// Modifies how synthesized events are emitted at points in the [span
244    /// lifecycle][lifecycle].
245    ///
246    /// See [`Self::with_span_events`] for documentation on the [`FmtSpan`]
247    ///
248    /// This method is primarily expected to be used with the
249    /// [`reload::Handle::modify`](crate::reload::Handle::modify) method
250    ///
251    /// Note that using this method modifies the span configuration instantly and does not take into
252    /// account any current spans. If the previous configuration was set to capture
253    /// `FmtSpan::ALL`, for example, using this method to change to `FmtSpan::NONE` will cause an
254    /// exit event for currently entered events not to be formatted
255    ///
256    /// [lifecycle]: mod@tracing::span#the-span-lifecycle
257    pub fn set_span_events(&mut self, kind: FmtSpan) {
258        self.fmt_span = format::FmtSpanConfig {
259            kind,
260            fmt_timing: self.fmt_span.fmt_timing,
261        }
262    }
263
264    /// Configures the subscriber to support [`libtest`'s output capturing][capturing] when used in
265    /// unit tests.
266    ///
267    /// See [`TestWriter`] for additional details.
268    ///
269    /// # Examples
270    ///
271    /// Using [`TestWriter`] to let `cargo test` capture test output:
272    ///
273    /// ```rust
274    /// use std::io;
275    /// use tracing_subscriber::fmt;
276    ///
277    /// let fmt_subscriber = fmt::subscriber()
278    ///     .with_test_writer();
279    /// # // this is necessary for type inference.
280    /// # use tracing_subscriber::Subscribe as _;
281    /// # let _ = fmt_subscriber.with_collector(tracing_subscriber::registry::Registry::default());
282    /// ```
283    /// [capturing]:
284    /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output
285    /// [`TestWriter`]: super::writer::TestWriter
286    pub fn with_test_writer(self) -> Subscriber<C, N, E, TestWriter> {
287        Subscriber {
288            fmt_fields: self.fmt_fields,
289            fmt_event: self.fmt_event,
290            fmt_span: self.fmt_span,
291            is_ansi: self.is_ansi,
292            log_internal_errors: self.log_internal_errors,
293            make_writer: TestWriter::default(),
294            _inner: self._inner,
295        }
296    }
297
298    /// Sets whether or not the formatter emits ANSI terminal escape codes
299    /// for colors and other text formatting.
300    ///
301    /// When the "ansi" crate feature flag is enabled, ANSI colors are enabled
302    /// by default unless the [`NO_COLOR`] environment variable is set to
303    /// a non-empty value.  If the [`NO_COLOR`] environment variable is set to
304    /// any non-empty value, then ANSI colors will be suppressed by default.
305    /// The [`with_ansi`] and [`set_ansi`] methods can be used to forcibly
306    /// enable ANSI colors, overriding any [`NO_COLOR`] environment variable.
307    ///
308    /// [`NO_COLOR`]: https://no-color.org/
309    ///
310    /// Enabling ANSI escapes (calling `with_ansi(true)`) requires the "ansi"
311    /// crate feature flag. Calling `with_ansi(true)` without the "ansi"
312    /// feature flag enabled will panic if debug assertions are enabled, or
313    /// print a warning otherwise.
314    ///
315    /// This method itself is still available without the feature flag. This
316    /// is to allow ANSI escape codes to be explicitly *disabled* without
317    /// having to opt-in to the dependencies required to emit ANSI formatting.
318    /// This way, code which constructs a formatter that should never emit
319    /// ANSI escape codes can ensure that they are not used, regardless of
320    /// whether or not other crates in the dependency graph enable the "ansi"
321    /// feature flag.
322    ///
323    /// [`with_ansi`]: Subscriber::with_ansi
324    /// [`set_ansi`]: Subscriber::set_ansi
325    pub fn with_ansi(self, ansi: bool) -> Self {
326        #[cfg(not(feature = "ansi"))]
327        if ansi {
328            const ERROR: &str =
329                "tracing-subscriber: the `ansi` crate feature is required to enable ANSI terminal colors";
330            #[cfg(debug_assertions)]
331            panic!("{}", ERROR);
332            #[cfg(not(debug_assertions))]
333            eprintln!("{}", ERROR);
334        }
335
336        Subscriber {
337            is_ansi: ansi,
338            ..self
339        }
340    }
341
342    /// Sets whether to write errors from [`FormatEvent`] to the writer.
343    /// Defaults to true.
344    ///
345    /// By default, `fmt::Subscriber` will write any `FormatEvent`-internal errors to
346    /// the writer. These errors are unlikely and will only occur if there is a
347    /// bug in the `FormatEvent` implementation or its dependencies.
348    ///
349    /// If writing to the writer fails, the error message is printed to stderr
350    /// as a fallback.
351    ///
352    /// [`FormatEvent`]: crate::fmt::FormatEvent
353    pub fn log_internal_errors(self, log_internal_errors: bool) -> Self {
354        Self {
355            log_internal_errors,
356            ..self
357        }
358    }
359
360    /// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`].
361    ///
362    /// This sets the [`MakeWriter`] that the subscriber being built will use to write events.
363    ///
364    /// # Examples
365    ///
366    /// Redirect output to stderr if level is <= WARN:
367    ///
368    /// ```rust
369    /// use tracing::Level;
370    /// use tracing_subscriber::fmt::{self, writer::MakeWriterExt};
371    ///
372    /// let stderr = std::io::stderr.with_max_level(Level::WARN);
373    /// let subscriber = fmt::subscriber()
374    ///     .map_writer(move |w| stderr.or_else(w));
375    /// # // this is necessary for type inference.
376    /// # use tracing_subscriber::Subscribe as _;
377    /// # let _ = subscriber.with_collector(tracing_subscriber::registry::Registry::default());
378    /// ```
379    pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> Subscriber<C, N, E, W2>
380    where
381        W2: for<'writer> MakeWriter<'writer> + 'static,
382    {
383        Subscriber {
384            fmt_fields: self.fmt_fields,
385            fmt_event: self.fmt_event,
386            fmt_span: self.fmt_span,
387            is_ansi: self.is_ansi,
388            log_internal_errors: self.log_internal_errors,
389            make_writer: f(self.make_writer),
390            _inner: self._inner,
391        }
392    }
393}
394
395impl<C, N, L, T, W> Subscriber<C, N, format::Format<L, T>, W>
396where
397    N: for<'writer> FormatFields<'writer> + 'static,
398{
399    /// Use the given [`timer`] for span and event timestamps.
400    ///
401    /// See the [`time` module] for the provided timer implementations.
402    ///
403    /// Note that using the `"time`"" feature flag enables the
404    /// additional time formatters [`UtcTime`] and [`LocalTime`], which use the
405    /// [`time` crate] to provide more sophisticated timestamp formatting
406    /// options.
407    ///
408    /// [`timer`]: super::time::FormatTime
409    /// [`time` module]: mod@super::time
410    /// [`UtcTime`]: super::time::UtcTime
411    /// [`LocalTime`]: super::time::LocalTime
412    /// [`time` crate]: https://docs.rs/time/0.3
413    pub fn with_timer<T2>(self, timer: T2) -> Subscriber<C, N, format::Format<L, T2>, W> {
414        Subscriber {
415            fmt_event: self.fmt_event.with_timer(timer),
416            fmt_fields: self.fmt_fields,
417            fmt_span: self.fmt_span,
418            make_writer: self.make_writer,
419            is_ansi: self.is_ansi,
420            log_internal_errors: self.log_internal_errors,
421            _inner: self._inner,
422        }
423    }
424
425    /// Do not emit timestamps with spans and event.
426    pub fn without_time(self) -> Subscriber<C, N, format::Format<L, ()>, W> {
427        Subscriber {
428            fmt_event: self.fmt_event.without_time(),
429            fmt_fields: self.fmt_fields,
430            fmt_span: self.fmt_span.without_time(),
431            make_writer: self.make_writer,
432            is_ansi: self.is_ansi,
433            log_internal_errors: self.log_internal_errors,
434            _inner: self._inner,
435        }
436    }
437
438    /// Configures how synthesized events are emitted at points in the [span
439    /// lifecycle][lifecycle].
440    ///
441    /// The following options are available:
442    ///
443    /// - `FmtSpan::NONE`: No events will be synthesized when spans are
444    ///   created, entered, exited, or closed. Data from spans will still be
445    ///   included as the context for formatted events. This is the default.
446    /// - `FmtSpan::NEW`: An event will be synthesized when spans are created.
447    /// - `FmtSpan::ENTER`: An event will be synthesized when spans are entered.
448    /// - `FmtSpan::EXIT`: An event will be synthesized when spans are exited.
449    /// - `FmtSpan::CLOSE`: An event will be synthesized when a span closes. If
450    ///   [timestamps are enabled][time] for this formatter, the generated
451    ///   event will contain fields with the span's _busy time_ (the total
452    ///   time for which it was entered) and _idle time_ (the total time that
453    ///   the span existed but was not entered).
454    /// - `FmtSpan::ACTIVE`: Events will be synthesized when spans are entered
455    ///   or exited.
456    /// - `FmtSpan::FULL`: Events will be synthesized whenever a span is
457    ///   created, entered, exited, or closed. If timestamps are enabled, the
458    ///   close event will contain the span's busy and idle time, as
459    ///   described above.
460    ///
461    /// The options can be enabled in any combination. For instance, the following
462    /// will synthesize events whenever spans are created and closed:
463    ///
464    /// ```rust
465    /// use tracing_subscriber::fmt;
466    /// use tracing_subscriber::fmt::format::FmtSpan;
467    ///
468    /// let subscriber = fmt()
469    ///     .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
470    ///     .finish();
471    /// ```
472    ///
473    /// Note that the generated events will only be part of the log output by
474    /// this formatter; they will not be recorded by other `Collector`s or by
475    /// `Subscriber`s added to this subscriber.
476    ///
477    /// [lifecycle]: mod@tracing::span#the-span-lifecycle
478    /// [time]: Subscriber::without_time()
479    pub fn with_span_events(self, kind: FmtSpan) -> Self {
480        Subscriber {
481            fmt_span: self.fmt_span.with_kind(kind),
482            ..self
483        }
484    }
485
486    /// Sets whether or not an event's target is displayed.
487    pub fn with_target(self, display_target: bool) -> Subscriber<C, N, format::Format<L, T>, W> {
488        Subscriber {
489            fmt_event: self.fmt_event.with_target(display_target),
490            ..self
491        }
492    }
493    /// Sets whether or not an event's [source code file path][file] is
494    /// displayed.
495    ///
496    /// [file]: tracing_core::Metadata::file
497    pub fn with_file(self, display_filename: bool) -> Subscriber<C, N, format::Format<L, T>, W> {
498        Subscriber {
499            fmt_event: self.fmt_event.with_file(display_filename),
500            ..self
501        }
502    }
503
504    /// Sets whether or not an event's [source code line number][line] is
505    /// displayed.
506    ///
507    /// [line]: tracing_core::Metadata::line
508    pub fn with_line_number(
509        self,
510        display_line_number: bool,
511    ) -> Subscriber<C, N, format::Format<L, T>, W> {
512        Subscriber {
513            fmt_event: self.fmt_event.with_line_number(display_line_number),
514            ..self
515        }
516    }
517
518    /// Sets whether or not an event's level is displayed.
519    pub fn with_level(self, display_level: bool) -> Subscriber<C, N, format::Format<L, T>, W> {
520        Subscriber {
521            fmt_event: self.fmt_event.with_level(display_level),
522            ..self
523        }
524    }
525
526    /// Sets whether or not the [thread ID] of the current thread is displayed
527    /// when formatting events.
528    ///
529    /// [thread ID]: std::thread::ThreadId
530    pub fn with_thread_ids(
531        self,
532        display_thread_ids: bool,
533    ) -> Subscriber<C, N, format::Format<L, T>, W> {
534        Subscriber {
535            fmt_event: self.fmt_event.with_thread_ids(display_thread_ids),
536            ..self
537        }
538    }
539
540    /// Sets whether or not the [name] of the current thread is displayed
541    /// when formatting events.
542    ///
543    /// [name]: std::thread#naming-threads
544    pub fn with_thread_names(
545        self,
546        display_thread_names: bool,
547    ) -> Subscriber<C, N, format::Format<L, T>, W> {
548        Subscriber {
549            fmt_event: self.fmt_event.with_thread_names(display_thread_names),
550            ..self
551        }
552    }
553
554    /// Sets the subscriber being built to use a [less verbose formatter](format::Compact).
555    pub fn compact(self) -> Subscriber<C, N, format::Format<format::Compact, T>, W>
556    where
557        N: for<'writer> FormatFields<'writer> + 'static,
558    {
559        Subscriber {
560            fmt_event: self.fmt_event.compact(),
561            fmt_fields: self.fmt_fields,
562            fmt_span: self.fmt_span,
563            make_writer: self.make_writer,
564            is_ansi: self.is_ansi,
565            log_internal_errors: self.log_internal_errors,
566            _inner: self._inner,
567        }
568    }
569
570    /// Sets the subscriber being built to use an [excessively pretty, human-readable formatter](crate::fmt::format::Pretty).
571    #[cfg(feature = "ansi")]
572    #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
573    pub fn pretty(self) -> Subscriber<C, format::Pretty, format::Format<format::Pretty, T>, W> {
574        Subscriber {
575            fmt_event: self.fmt_event.pretty(),
576            fmt_fields: format::Pretty::default(),
577            fmt_span: self.fmt_span,
578            make_writer: self.make_writer,
579            is_ansi: self.is_ansi,
580            log_internal_errors: self.log_internal_errors,
581            _inner: self._inner,
582        }
583    }
584
585    /// Sets the subscriber being built to use a [JSON formatter](format::Json).
586    ///
587    /// The full format includes fields from all entered spans.
588    ///
589    /// # Example Output
590    ///
591    /// ```ignore,json
592    /// {"timestamp":"Feb 20 11:28:15.096","level":"INFO","target":"mycrate","fields":{"message":"some message", "key": "value"}}
593    /// ```
594    ///
595    /// # Options
596    ///
597    /// - [`Subscriber::flatten_event`] can be used to enable flattening event fields into the root
598    ///   object.
599    ///
600    #[cfg(feature = "json")]
601    #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
602    pub fn json(self) -> Subscriber<C, format::JsonFields, format::Format<format::Json, T>, W> {
603        Subscriber {
604            fmt_event: self.fmt_event.json(),
605            fmt_fields: format::JsonFields::new(),
606            fmt_span: self.fmt_span,
607            make_writer: self.make_writer,
608            // always disable ANSI escapes in JSON mode!
609            is_ansi: false,
610            log_internal_errors: self.log_internal_errors,
611            _inner: self._inner,
612        }
613    }
614}
615
616#[cfg(feature = "json")]
617#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
618impl<C, T, W> Subscriber<C, format::JsonFields, format::Format<format::Json, T>, W> {
619    /// Sets the JSON subscriber being built to flatten event metadata.
620    ///
621    /// See [`format::Json`]
622    pub fn flatten_event(
623        self,
624        flatten_event: bool,
625    ) -> Subscriber<C, format::JsonFields, format::Format<format::Json, T>, W> {
626        Subscriber {
627            fmt_event: self.fmt_event.flatten_event(flatten_event),
628            fmt_fields: format::JsonFields::new(),
629            ..self
630        }
631    }
632
633    /// Sets whether or not the formatter will include the current span in
634    /// formatted events.
635    ///
636    /// See [`format::Json`]
637    pub fn with_current_span(
638        self,
639        display_current_span: bool,
640    ) -> Subscriber<C, format::JsonFields, format::Format<format::Json, T>, W> {
641        Subscriber {
642            fmt_event: self.fmt_event.with_current_span(display_current_span),
643            fmt_fields: format::JsonFields::new(),
644            ..self
645        }
646    }
647
648    /// Sets whether or not the formatter will include a list (from root to leaf)
649    /// of all currently entered spans in formatted events.
650    ///
651    /// See [`format::Json`]
652    pub fn with_span_list(
653        self,
654        display_span_list: bool,
655    ) -> Subscriber<C, format::JsonFields, format::Format<format::Json, T>, W> {
656        Subscriber {
657            fmt_event: self.fmt_event.with_span_list(display_span_list),
658            fmt_fields: format::JsonFields::new(),
659            ..self
660        }
661    }
662}
663
664impl<C, N, E, W> Subscriber<C, N, E, W> {
665    /// Sets the field formatter that the subscriber being built will use to record
666    /// fields.
667    pub fn fmt_fields<N2>(self, fmt_fields: N2) -> Subscriber<C, N2, E, W>
668    where
669        N2: for<'writer> FormatFields<'writer> + 'static,
670    {
671        Subscriber {
672            fmt_event: self.fmt_event,
673            fmt_fields,
674            fmt_span: self.fmt_span,
675            make_writer: self.make_writer,
676            is_ansi: self.is_ansi,
677            log_internal_errors: self.log_internal_errors,
678            _inner: self._inner,
679        }
680    }
681
682    /// Updates the field formatter by applying a function to the existing field formatter.
683    ///
684    /// This sets the field formatter that the subscriber being built will use to record fields.
685    ///
686    /// # Examples
687    ///
688    /// Updating a field formatter:
689    ///
690    /// ```rust
691    /// use tracing_subscriber::field::MakeExt;
692    /// let subscriber = tracing_subscriber::fmt::subscriber()
693    ///     .map_fmt_fields(|f| f.debug_alt());
694    /// # // this is necessary for type inference.
695    /// # use tracing_subscriber::Subscribe as _;
696    /// # let _ = subscriber.with_collector(tracing_subscriber::registry::Registry::default());
697    /// ```
698    pub fn map_fmt_fields<N2>(self, f: impl FnOnce(N) -> N2) -> Subscriber<C, N2, E, W>
699    where
700        N2: for<'writer> FormatFields<'writer> + 'static,
701    {
702        Subscriber {
703            fmt_event: self.fmt_event,
704            fmt_fields: f(self.fmt_fields),
705            fmt_span: self.fmt_span,
706            make_writer: self.make_writer,
707            is_ansi: self.is_ansi,
708            log_internal_errors: self.log_internal_errors,
709            _inner: self._inner,
710        }
711    }
712}
713
714impl<C> Default for Subscriber<C> {
715    fn default() -> Self {
716        // only enable ANSI when the feature is enabled, and the NO_COLOR
717        // environment variable is unset or empty.
718        let ansi = cfg!(feature = "ansi") && env::var("NO_COLOR").map_or(true, |v| v.is_empty());
719
720        Subscriber {
721            fmt_fields: format::DefaultFields::default(),
722            fmt_event: format::Format::default(),
723            fmt_span: format::FmtSpanConfig::default(),
724            make_writer: io::stdout,
725            is_ansi: ansi,
726            log_internal_errors: false,
727            _inner: PhantomData,
728        }
729    }
730}
731
732impl<C, N, E, W> Subscriber<C, N, E, W>
733where
734    C: Collect + for<'a> LookupSpan<'a>,
735    N: for<'writer> FormatFields<'writer> + 'static,
736    E: FormatEvent<C, N> + 'static,
737    W: for<'writer> MakeWriter<'writer> + 'static,
738{
739    #[inline]
740    fn make_ctx<'a>(&'a self, ctx: Context<'a, C>, event: &'a Event<'a>) -> FmtContext<'a, C, N> {
741        FmtContext {
742            ctx,
743            fmt_fields: &self.fmt_fields,
744            event,
745        }
746    }
747}
748
749/// A formatted representation of a span's fields stored in its [extensions].
750///
751/// Because `FormattedFields` is generic over the type of the formatter that
752/// produced it, multiple versions of a span's formatted fields can be stored in
753/// the [`Extensions`][extensions] type-map. This means that when multiple
754/// formatters are in use, each can store its own formatted representation
755/// without conflicting.
756///
757/// [extensions]: crate::registry::Extensions
758#[derive(Default)]
759pub struct FormattedFields<E: ?Sized> {
760    _format_fields: PhantomData<fn(E)>,
761    was_ansi: bool,
762    /// The formatted fields of a span.
763    pub fields: String,
764}
765
766impl<E: ?Sized> FormattedFields<E> {
767    /// Returns a new `FormattedFields`.
768    pub fn new(fields: String) -> Self {
769        Self {
770            fields,
771            was_ansi: false,
772            _format_fields: PhantomData,
773        }
774    }
775
776    /// Returns a new [`format::Writer`] for writing to this `FormattedFields`.
777    ///
778    /// The returned [`format::Writer`] can be used with the
779    /// [`FormatFields::format_fields`] method.
780    pub fn as_writer(&mut self) -> format::Writer<'_> {
781        format::Writer::new(&mut self.fields).with_ansi(self.was_ansi)
782    }
783}
784
785impl<E: ?Sized> fmt::Debug for FormattedFields<E> {
786    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
787        f.debug_struct("FormattedFields")
788            .field("fields", &self.fields)
789            .field("formatter", &format_args!("{}", std::any::type_name::<E>()))
790            .field("was_ansi", &self.was_ansi)
791            .finish()
792    }
793}
794
795impl<E: ?Sized> fmt::Display for FormattedFields<E> {
796    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
797        fmt::Display::fmt(&self.fields, f)
798    }
799}
800
801impl<E: ?Sized> Deref for FormattedFields<E> {
802    type Target = String;
803    fn deref(&self) -> &Self::Target {
804        &self.fields
805    }
806}
807
808// === impl FmtSubscriber ===
809
810macro_rules! with_event_from_span {
811    ($id:ident, $span:ident, $($field:literal = $value:expr),*, |$event:ident| $code:block) => {
812        let meta = $span.metadata();
813        let cs = meta.callsite();
814        let fs = field::FieldSet::new(&[$($field),*], cs);
815        #[allow(unused)]
816        let mut iter = fs.iter();
817        let v = [$(
818            (&iter.next().unwrap(), ::core::option::Option::Some(&$value as &dyn field::Value)),
819        )*];
820        let vs = fs.value_set(&v);
821        let $event = Event::new_child_of($id, meta, &vs);
822        $code
823    };
824}
825
826impl<C, N, E, W> subscribe::Subscribe<C> for Subscriber<C, N, E, W>
827where
828    C: Collect + for<'a> LookupSpan<'a>,
829    N: for<'writer> FormatFields<'writer> + 'static,
830    E: FormatEvent<C, N> + 'static,
831    W: for<'writer> MakeWriter<'writer> + 'static,
832{
833    fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, C>) {
834        let span = ctx.span(id).expect("Span not found, this is a bug");
835        let mut extensions = span.extensions_mut();
836
837        if extensions.get_mut::<FormattedFields<N>>().is_none() {
838            let mut fields = FormattedFields::<N>::new(String::new());
839            if self
840                .fmt_fields
841                .format_fields(fields.as_writer().with_ansi(self.is_ansi), attrs)
842                .is_ok()
843            {
844                fields.was_ansi = self.is_ansi;
845                extensions.insert(fields);
846            } else {
847                eprintln!(
848                    "[tracing-subscriber] Unable to format the following event, ignoring: {:?}",
849                    attrs
850                );
851            }
852        }
853
854        if self.fmt_span.fmt_timing
855            && self.fmt_span.trace_close()
856            && extensions.get_mut::<Timings>().is_none()
857        {
858            extensions.insert(Timings::new());
859        }
860
861        if self.fmt_span.trace_new() {
862            with_event_from_span!(id, span, "message" = "new", |event| {
863                drop(extensions);
864                drop(span);
865                self.on_event(&event, ctx);
866            });
867        }
868    }
869
870    fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, C>) {
871        let span = ctx.span(id).expect("Span not found, this is a bug");
872        let mut extensions = span.extensions_mut();
873        if let Some(fields) = extensions.get_mut::<FormattedFields<N>>() {
874            let _ = self.fmt_fields.add_fields(fields, values);
875            return;
876        }
877
878        let mut fields = FormattedFields::<N>::new(String::new());
879        if self
880            .fmt_fields
881            .format_fields(fields.as_writer().with_ansi(self.is_ansi), values)
882            .is_ok()
883        {
884            fields.was_ansi = self.is_ansi;
885            extensions.insert(fields);
886        }
887    }
888
889    fn on_enter(&self, id: &Id, ctx: Context<'_, C>) {
890        if self.fmt_span.trace_enter() || self.fmt_span.trace_close() && self.fmt_span.fmt_timing {
891            let span = ctx.span(id).expect("Span not found, this is a bug");
892            let mut extensions = span.extensions_mut();
893            if let Some(timings) = extensions.get_mut::<Timings>() {
894                let now = Instant::now();
895                timings.idle += (now - timings.last).as_nanos() as u64;
896                timings.last = now;
897            }
898
899            if self.fmt_span.trace_enter() {
900                with_event_from_span!(id, span, "message" = "enter", |event| {
901                    drop(extensions);
902                    drop(span);
903                    self.on_event(&event, ctx);
904                });
905            }
906        }
907    }
908
909    fn on_exit(&self, id: &Id, ctx: Context<'_, C>) {
910        if self.fmt_span.trace_exit() || self.fmt_span.trace_close() && self.fmt_span.fmt_timing {
911            let span = ctx.span(id).expect("Span not found, this is a bug");
912            let mut extensions = span.extensions_mut();
913            if let Some(timings) = extensions.get_mut::<Timings>() {
914                let now = Instant::now();
915                timings.busy += (now - timings.last).as_nanos() as u64;
916                timings.last = now;
917            }
918
919            if self.fmt_span.trace_exit() {
920                with_event_from_span!(id, span, "message" = "exit", |event| {
921                    drop(extensions);
922                    drop(span);
923                    self.on_event(&event, ctx);
924                });
925            }
926        }
927    }
928
929    fn on_close(&self, id: Id, ctx: Context<'_, C>) {
930        if self.fmt_span.trace_close() {
931            let span = ctx.span(&id).expect("Span not found, this is a bug");
932            let extensions = span.extensions();
933            if let Some(timing) = extensions.get::<Timings>() {
934                let Timings {
935                    busy,
936                    mut idle,
937                    last,
938                } = *timing;
939                idle += (Instant::now() - last).as_nanos() as u64;
940
941                let t_idle = field::display(TimingDisplay(idle));
942                let t_busy = field::display(TimingDisplay(busy));
943
944                with_event_from_span!(
945                    id,
946                    span,
947                    "message" = "close",
948                    "time.busy" = t_busy,
949                    "time.idle" = t_idle,
950                    |event| {
951                        drop(extensions);
952                        drop(span);
953                        self.on_event(&event, ctx);
954                    }
955                );
956            } else {
957                with_event_from_span!(id, span, "message" = "close", |event| {
958                    drop(extensions);
959                    drop(span);
960                    self.on_event(&event, ctx);
961                });
962            }
963        }
964    }
965
966    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, C>) {
967        thread_local! {
968            static BUF: RefCell<String> = const { RefCell::new(String::new()) };
969        }
970
971        BUF.with(|buf| {
972            let borrow = buf.try_borrow_mut();
973            let mut a;
974            let mut b;
975            let mut buf = match borrow {
976                Ok(buf) => {
977                    a = buf;
978                    &mut *a
979                }
980                _ => {
981                    b = String::new();
982                    &mut b
983                }
984            };
985
986            let ctx = self.make_ctx(ctx, event);
987            if self
988                .fmt_event
989                .format_event(
990                    &ctx,
991                    format::Writer::new(&mut buf).with_ansi(self.is_ansi),
992                    event,
993                )
994                .is_ok()
995            {
996                let mut writer = self.make_writer.make_writer_for(event.metadata());
997                let res = io::Write::write_all(&mut writer, buf.as_bytes());
998                if self.log_internal_errors {
999                    if let Err(e) = res {
1000                        eprintln!("[tracing-subscriber] Unable to write an event to the Writer for this Subscriber! Error: {}\n", e);
1001                    }
1002                }
1003            } else if self.log_internal_errors {
1004                let err_msg = format!("Unable to format the following event. Name: {}; Fields: {:?}\n",
1005                    event.metadata().name(), event.fields());
1006                let mut writer = self.make_writer.make_writer_for(event.metadata());
1007                let res = io::Write::write_all(&mut writer, err_msg.as_bytes());
1008                if let Err(e) = res {
1009                    eprintln!("[tracing-subscriber] Unable to write an \"event formatting error\" to the Writer for this Subscriber! Error: {}\n", e);
1010                }
1011            }
1012
1013            buf.clear();
1014        });
1015    }
1016
1017    unsafe fn downcast_raw(&self, id: TypeId) -> Option<NonNull<()>> {
1018        // This `downcast_raw` impl allows downcasting a `fmt` subscriber to any of
1019        // its components (event formatter, field formatter, and `MakeWriter`)
1020        // as well as to the subscriber's type itself. The potential use-cases for
1021        // this *may* be somewhat niche, though...
1022        match () {
1023            _ if id == TypeId::of::<Self>() => Some(NonNull::from(self).cast()),
1024            _ if id == TypeId::of::<E>() => Some(NonNull::from(&self.fmt_event).cast()),
1025            _ if id == TypeId::of::<N>() => Some(NonNull::from(&self.fmt_fields).cast()),
1026            _ if id == TypeId::of::<W>() => Some(NonNull::from(&self.make_writer).cast()),
1027            _ => None,
1028        }
1029    }
1030}
1031
1032/// Provides the current span context to a formatter.
1033pub struct FmtContext<'a, C, N> {
1034    pub(crate) ctx: Context<'a, C>,
1035    pub(crate) fmt_fields: &'a N,
1036    pub(crate) event: &'a Event<'a>,
1037}
1038
1039impl<C, N> fmt::Debug for FmtContext<'_, C, N> {
1040    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1041        f.debug_struct("FmtContext").finish()
1042    }
1043}
1044
1045impl<'writer, C, N> FormatFields<'writer> for FmtContext<'_, C, N>
1046where
1047    C: Collect + for<'lookup> LookupSpan<'lookup>,
1048    N: FormatFields<'writer> + 'static,
1049{
1050    fn format_fields<R: RecordFields>(
1051        &self,
1052        writer: format::Writer<'writer>,
1053        fields: R,
1054    ) -> fmt::Result {
1055        self.fmt_fields.format_fields(writer, fields)
1056    }
1057}
1058
1059impl<C, N> FmtContext<'_, C, N>
1060where
1061    C: Collect + for<'lookup> LookupSpan<'lookup>,
1062    N: for<'writer> FormatFields<'writer> + 'static,
1063{
1064    /// Visits every span in the current context with a closure.
1065    ///
1066    /// The provided closure will be called first with the current span,
1067    /// and then with that span's parent, and then that span's parent,
1068    /// and so on until a root span is reached.
1069    pub fn visit_spans<E, F>(&self, mut f: F) -> Result<(), E>
1070    where
1071        F: FnMut(&SpanRef<'_, C>) -> Result<(), E>,
1072    {
1073        // visit all the current spans
1074        if let Some(scope) = self.event_scope() {
1075            for span in scope.from_root() {
1076                f(&span)?;
1077            }
1078        }
1079        Ok(())
1080    }
1081
1082    /// Returns metadata for the span with the given `id`, if it exists.
1083    ///
1084    /// If this returns `None`, then no span exists for that ID (either it has
1085    /// closed or the ID is invalid).
1086    #[inline]
1087    pub fn metadata(&self, id: &Id) -> Option<&'static Metadata<'static>>
1088    where
1089        C: for<'lookup> LookupSpan<'lookup>,
1090    {
1091        self.ctx.metadata(id)
1092    }
1093
1094    /// Returns [stored data] for the span with the given `id`, if it exists.
1095    ///
1096    /// If this returns `None`, then no span exists for that ID (either it has
1097    /// closed or the ID is invalid).
1098    ///
1099    /// [stored data]: SpanRef
1100    #[inline]
1101    pub fn span(&self, id: &Id) -> Option<SpanRef<'_, C>>
1102    where
1103        C: for<'lookup> LookupSpan<'lookup>,
1104    {
1105        self.ctx.span(id)
1106    }
1107
1108    /// Returns `true` if an active span exists for the given `Id`.
1109    #[inline]
1110    pub fn exists(&self, id: &Id) -> bool
1111    where
1112        C: for<'lookup> LookupSpan<'lookup>,
1113    {
1114        self.ctx.exists(id)
1115    }
1116
1117    /// Returns [stored data] for the span that the wrapped subscriber considers
1118    /// to be the current.
1119    ///
1120    /// If this returns `None`, then we are not currently within a span.
1121    ///
1122    /// [stored data]: SpanRef
1123    #[inline]
1124    pub fn lookup_current(&self) -> Option<SpanRef<'_, C>>
1125    where
1126        C: for<'lookup> LookupSpan<'lookup>,
1127    {
1128        self.ctx.lookup_current()
1129    }
1130
1131    /// Returns the current span for this formatter.
1132    pub fn current_span(&self) -> Current {
1133        self.ctx.current_span()
1134    }
1135
1136    /// Returns [stored data] for the parent span of the event currently being
1137    /// formatted.
1138    ///
1139    /// If the event has a contextual parent, this will return the current span. If
1140    /// the event has an explicit parent span, this will return that span. If
1141    /// the event does not have a parent span, this will return `None`.
1142    ///
1143    /// [stored data]: SpanRef
1144    pub fn parent_span(&self) -> Option<SpanRef<'_, C>> {
1145        self.ctx.event_span(self.event)
1146    }
1147
1148    /// Returns an iterator over the [stored data] for all the spans in the
1149    /// current context, starting with the specified span and ending with the
1150    /// root of the trace tree and ending with the current span.
1151    ///
1152    /// This is equivalent to the [`Context::span_scope`] method.
1153    ///
1154    /// <div class="information">
1155    ///     <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
1156    /// </div>
1157    /// <div class="example-wrap" style="display:inline-block">
1158    /// <pre class="ignore" style="white-space:normal;font:inherit;">
1159    /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this
1160    /// returns the spans in reverse order (from leaf to root). Use
1161    /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
1162    /// in case root-to-leaf ordering is desired.
1163    /// </pre></div>
1164    ///
1165    /// <div class="example-wrap" style="display:inline-block">
1166    /// <pre class="ignore" style="white-space:normal;font:inherit;">
1167    /// <strong>Note</strong>: This requires the wrapped subscriber to implement the
1168    /// <a href="../registry/trait.LookupSpan.html"><code>LookupSpan</code></a> trait.
1169    /// See the documentation on <a href="./struct.Context.html"><code>Context</code>'s
1170    /// declaration</a> for details.
1171    /// </pre></div>
1172    ///
1173    /// [stored data]: crate::registry::SpanRef
1174    pub fn span_scope(&self, id: &Id) -> Option<registry::Scope<'_, C>>
1175    where
1176        C: for<'lookup> LookupSpan<'lookup>,
1177    {
1178        self.ctx.span_scope(id)
1179    }
1180
1181    /// Returns an iterator over the [stored data] for all the spans in the
1182    /// event's span context, starting with its parent span and ending with the
1183    /// root of the trace tree.
1184    ///
1185    /// This is equivalent to calling the [`Context::event_scope`] method and
1186    /// passing the event currently being formatted.
1187    ///
1188    /// <div class="example-wrap" style="display:inline-block">
1189    /// <pre class="ignore" style="white-space:normal;font:inherit;">
1190    /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this
1191    /// returns the spans in reverse order (from leaf to root). Use
1192    /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
1193    /// in case root-to-leaf ordering is desired.
1194    /// </pre></div>
1195    ///
1196    /// <div class="example-wrap" style="display:inline-block">
1197    /// <pre class="ignore" style="white-space:normal;font:inherit;">
1198    /// <strong>Note</strong>: This requires the wrapped subscriber to implement the
1199    /// <a href="../registry/trait.LookupSpan.html"><code>LookupSpan</code></a> trait.
1200    /// See the documentation on <a href="./struct.Context.html"><code>Context</code>'s
1201    /// declaration</a> for details.
1202    /// </pre></div>
1203    ///
1204    /// [stored data]: crate::registry::SpanRef
1205    pub fn event_scope(&self) -> Option<registry::Scope<'_, C>>
1206    where
1207        C: for<'lookup> registry::LookupSpan<'lookup>,
1208    {
1209        self.ctx.event_scope(self.event)
1210    }
1211
1212    /// Returns the [field formatter] configured by the subscriber invoking
1213    /// `format_event`.
1214    ///
1215    /// The event formatter may use the returned field formatter to format the
1216    /// fields of any events it records.
1217    ///
1218    /// [field formatter]: FormatFields
1219    pub fn field_format(&self) -> &N {
1220        self.fmt_fields
1221    }
1222}
1223
1224struct Timings {
1225    idle: u64,
1226    busy: u64,
1227    last: Instant,
1228}
1229
1230impl Timings {
1231    fn new() -> Self {
1232        Self {
1233            idle: 0,
1234            busy: 0,
1235            last: Instant::now(),
1236        }
1237    }
1238}
1239
1240#[cfg(test)]
1241mod test {
1242    use super::*;
1243    use crate::fmt::{
1244        self,
1245        format::{self, test::MockTime, Format},
1246        subscribe::Subscribe as _,
1247        test::{MockMakeWriter, MockWriter},
1248        time,
1249    };
1250    use crate::Registry;
1251    use format::FmtSpan;
1252    use regex::Regex;
1253    use tracing::collect::with_default;
1254    use tracing_core::dispatch::Dispatch;
1255
1256    #[test]
1257    fn impls() {
1258        let f = Format::default().with_timer(time::Uptime::default());
1259        let fmt = fmt::Subscriber::default().event_format(f);
1260        let subscriber = fmt.with_collector(Registry::default());
1261        let _dispatch = Dispatch::new(subscriber);
1262
1263        let f = format::Format::default();
1264        let fmt = fmt::Subscriber::default().event_format(f);
1265        let subscriber = fmt.with_collector(Registry::default());
1266        let _dispatch = Dispatch::new(subscriber);
1267
1268        let f = format::Format::default().compact();
1269        let fmt = fmt::Subscriber::default().event_format(f);
1270        let subscriber = fmt.with_collector(Registry::default());
1271        let _dispatch = Dispatch::new(subscriber);
1272    }
1273
1274    #[test]
1275    fn fmt_subscriber_downcasts() {
1276        let f = format::Format::default();
1277        let fmt = fmt::Subscriber::default().event_format(f);
1278        let subscriber = fmt.with_collector(Registry::default());
1279
1280        let dispatch = Dispatch::new(subscriber);
1281        assert!(dispatch
1282            .downcast_ref::<fmt::Subscriber<Registry>>()
1283            .is_some());
1284    }
1285
1286    #[test]
1287    fn fmt_subscriber_downcasts_to_parts() {
1288        let f = format::Format::default();
1289        let fmt = fmt::Subscriber::default().event_format(f);
1290        let subscriber = fmt.with_collector(Registry::default());
1291        let dispatch = Dispatch::new(subscriber);
1292        assert!(dispatch.downcast_ref::<format::DefaultFields>().is_some());
1293        assert!(dispatch.downcast_ref::<format::Format>().is_some())
1294    }
1295
1296    #[test]
1297    fn is_lookup_span() {
1298        fn assert_lookup_span<T: for<'a> crate::registry::LookupSpan<'a>>(_: T) {}
1299        let fmt = fmt::Subscriber::default();
1300        let subscriber = fmt.with_collector(Registry::default());
1301        assert_lookup_span(subscriber)
1302    }
1303
1304    fn sanitize_timings(s: String) -> String {
1305        let re = Regex::new("time\\.(idle|busy)=([0-9.]+)[mµn]s").unwrap();
1306        re.replace_all(s.as_str(), "timing").to_string()
1307    }
1308
1309    #[test]
1310    fn format_error_print_to_stderr() {
1311        struct AlwaysError;
1312
1313        impl std::fmt::Debug for AlwaysError {
1314            fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1315                Err(std::fmt::Error)
1316            }
1317        }
1318
1319        let make_writer = MockMakeWriter::default();
1320        let subscriber = crate::fmt::Collector::builder()
1321            .with_writer(make_writer.clone())
1322            .with_level(false)
1323            .with_ansi(false)
1324            .with_timer(MockTime)
1325            .finish();
1326
1327        with_default(subscriber, || {
1328            tracing::info!(?AlwaysError);
1329        });
1330        let actual = sanitize_timings(make_writer.get_string());
1331
1332        // Only assert the start because the line number and callsite may change.
1333        let expected = concat!(
1334            "Unable to format the following event. Name: event ",
1335            file!(),
1336            ":"
1337        );
1338        assert!(
1339            actual.as_str().starts_with(expected),
1340            "\nactual = {}\nshould start with expected = {}\n",
1341            actual,
1342            expected
1343        );
1344    }
1345
1346    #[test]
1347    fn format_error_ignore_if_log_internal_errors_is_false() {
1348        struct AlwaysError;
1349
1350        impl std::fmt::Debug for AlwaysError {
1351            fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1352                Err(std::fmt::Error)
1353            }
1354        }
1355
1356        let make_writer = MockMakeWriter::default();
1357        let subscriber = crate::fmt::Collector::builder()
1358            .with_writer(make_writer.clone())
1359            .with_level(false)
1360            .with_ansi(false)
1361            .with_timer(MockTime)
1362            .log_internal_errors(false)
1363            .finish();
1364
1365        with_default(subscriber, || {
1366            tracing::info!(?AlwaysError);
1367        });
1368        let actual = sanitize_timings(make_writer.get_string());
1369        assert_eq!("", actual.as_str());
1370    }
1371
1372    #[test]
1373    fn synthesize_span_none() {
1374        let make_writer = MockMakeWriter::default();
1375        let subscriber = crate::fmt::Collector::builder()
1376            .with_writer(make_writer.clone())
1377            .with_level(false)
1378            .with_ansi(false)
1379            .with_timer(MockTime)
1380            // check that FmtSpan::NONE is the default
1381            .finish();
1382
1383        with_default(subscriber, || {
1384            let span1 = tracing::info_span!("span1", x = 42);
1385            let _e = span1.enter();
1386        });
1387        let actual = sanitize_timings(make_writer.get_string());
1388        assert_eq!("", actual.as_str());
1389    }
1390
1391    #[test]
1392    fn synthesize_span_active() {
1393        let make_writer = MockMakeWriter::default();
1394        let subscriber = crate::fmt::Collector::builder()
1395            .with_writer(make_writer.clone())
1396            .with_level(false)
1397            .with_ansi(false)
1398            .with_timer(MockTime)
1399            .with_span_events(FmtSpan::ACTIVE)
1400            .finish();
1401
1402        with_default(subscriber, || {
1403            let span1 = tracing::info_span!("span1", x = 42);
1404            let _e = span1.enter();
1405        });
1406        let actual = sanitize_timings(make_writer.get_string());
1407        assert_eq!(
1408            "fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: enter\n\
1409             fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: exit\n",
1410            actual.as_str()
1411        );
1412    }
1413
1414    #[test]
1415    fn synthesize_span_close() {
1416        let make_writer = MockMakeWriter::default();
1417        let subscriber = crate::fmt::Collector::builder()
1418            .with_writer(make_writer.clone())
1419            .with_level(false)
1420            .with_ansi(false)
1421            .with_timer(MockTime)
1422            .with_span_events(FmtSpan::CLOSE)
1423            .finish();
1424
1425        with_default(subscriber, || {
1426            let span1 = tracing::info_span!("span1", x = 42);
1427            let _e = span1.enter();
1428        });
1429        let actual = sanitize_timings(make_writer.get_string());
1430        assert_eq!(
1431            "fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: close timing timing\n",
1432            actual.as_str()
1433        );
1434    }
1435
1436    #[test]
1437    fn synthesize_span_close_no_timing() {
1438        let make_writer = MockMakeWriter::default();
1439        let subscriber = crate::fmt::Collector::builder()
1440            .with_writer(make_writer.clone())
1441            .with_level(false)
1442            .with_ansi(false)
1443            .with_timer(MockTime)
1444            .without_time()
1445            .with_span_events(FmtSpan::CLOSE)
1446            .finish();
1447
1448        with_default(subscriber, || {
1449            let span1 = tracing::info_span!("span1", x = 42);
1450            let _e = span1.enter();
1451        });
1452        let actual = sanitize_timings(make_writer.get_string());
1453        assert_eq!(
1454            "span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: close\n",
1455            actual.as_str()
1456        );
1457    }
1458
1459    #[test]
1460    fn synthesize_span_full() {
1461        let make_writer = MockMakeWriter::default();
1462        let subscriber = crate::fmt::Collector::builder()
1463            .with_writer(make_writer.clone())
1464            .with_level(false)
1465            .with_ansi(false)
1466            .with_timer(MockTime)
1467            .with_span_events(FmtSpan::FULL)
1468            .finish();
1469
1470        with_default(subscriber, || {
1471            let span1 = tracing::info_span!("span1", x = 42);
1472            let _e = span1.enter();
1473        });
1474        let actual = sanitize_timings(make_writer.get_string());
1475        assert_eq!(
1476            "fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: new\n\
1477             fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: enter\n\
1478             fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: exit\n\
1479             fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: close timing timing\n",
1480            actual.as_str()
1481        );
1482    }
1483
1484    #[test]
1485    fn make_writer_based_on_meta() {
1486        struct MakeByTarget {
1487            make_writer1: MockMakeWriter,
1488            make_writer2: MockMakeWriter,
1489        }
1490
1491        impl<'a> MakeWriter<'a> for MakeByTarget {
1492            type Writer = MockWriter;
1493
1494            fn make_writer(&'a self) -> Self::Writer {
1495                self.make_writer1.make_writer()
1496            }
1497
1498            fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1499                if meta.target() == "writer2" {
1500                    return self.make_writer2.make_writer();
1501                }
1502                self.make_writer()
1503            }
1504        }
1505
1506        let make_writer1 = MockMakeWriter::default();
1507        let make_writer2 = MockMakeWriter::default();
1508
1509        let make_writer = MakeByTarget {
1510            make_writer1: make_writer1.clone(),
1511            make_writer2: make_writer2.clone(),
1512        };
1513
1514        let subscriber = crate::fmt::Collector::builder()
1515            .with_writer(make_writer)
1516            .with_level(false)
1517            .with_target(false)
1518            .with_ansi(false)
1519            .with_timer(MockTime)
1520            .with_span_events(FmtSpan::CLOSE)
1521            .finish();
1522
1523        with_default(subscriber, || {
1524            let span1 = tracing::info_span!("writer1_span", x = 42);
1525            let _e = span1.enter();
1526            tracing::info!(target: "writer2", "hello writer2!");
1527            let span2 = tracing::info_span!(target: "writer2", "writer2_span");
1528            let _e = span2.enter();
1529            tracing::warn!(target: "writer1", "hello writer1!");
1530        });
1531
1532        let actual = sanitize_timings(make_writer1.get_string());
1533        assert_eq!(
1534            "fake time writer1_span{x=42}:writer2_span: hello writer1!\n\
1535             fake time writer1_span{x=42}: close timing timing\n",
1536            actual.as_str()
1537        );
1538        let actual = sanitize_timings(make_writer2.get_string());
1539        assert_eq!(
1540            "fake time writer1_span{x=42}: hello writer2!\n\
1541             fake time writer1_span{x=42}:writer2_span: close timing timing\n",
1542            actual.as_str()
1543        );
1544    }
1545
1546    // Because we need to modify an environment variable for these test cases,
1547    // we do them all in a single test.
1548    #[cfg(feature = "ansi")]
1549    #[test]
1550    fn subscriber_no_color() {
1551        const NO_COLOR: &str = "NO_COLOR";
1552
1553        // Restores the previous value of the `NO_COLOR` env variable when
1554        // dropped.
1555        //
1556        // This is done in a `Drop` implementation, rather than just resetting
1557        // the value at the end of the test, so that the previous value is
1558        // restored even if the test panics.
1559        struct RestoreEnvVar(Result<String, env::VarError>);
1560        impl Drop for RestoreEnvVar {
1561            fn drop(&mut self) {
1562                match self.0 {
1563                    Ok(ref var) => env::set_var(NO_COLOR, var),
1564                    Err(_) => env::remove_var(NO_COLOR),
1565                }
1566            }
1567        }
1568
1569        let _saved_no_color = RestoreEnvVar(env::var(NO_COLOR));
1570
1571        let cases: Vec<(Option<&str>, bool)> = vec![
1572            (Some("0"), false),   // any non-empty value disables ansi
1573            (Some("off"), false), // any non-empty value disables ansi
1574            (Some("1"), false),
1575            (Some(""), true), // empty value does not disable ansi
1576            (None, true),
1577        ];
1578
1579        for (var, ansi) in cases {
1580            if let Some(value) = var {
1581                env::set_var(NO_COLOR, value);
1582            } else {
1583                env::remove_var(NO_COLOR);
1584            }
1585
1586            let subscriber: Subscriber<()> = fmt::Subscriber::default();
1587            assert_eq!(
1588                subscriber.is_ansi, ansi,
1589                "NO_COLOR={:?}; Subscriber::default().is_ansi should be {}",
1590                var, ansi
1591            );
1592
1593            // with_ansi should override any `NO_COLOR` value
1594            let subscriber: Subscriber<()> = fmt::Subscriber::default().with_ansi(true);
1595            assert!(
1596                subscriber.is_ansi,
1597                "NO_COLOR={:?}; Subscriber::default().with_ansi(true).is_ansi should be true",
1598                var
1599            );
1600
1601            // set_ansi should override any `NO_COLOR` value
1602            let mut subscriber: Subscriber<()> = fmt::Subscriber::default();
1603            subscriber.set_ansi(true);
1604            assert!(
1605                subscriber.is_ansi,
1606                "NO_COLOR={:?}; subscriber.set_ansi(true); subscriber.is_ansi should be true",
1607                var
1608            );
1609        }
1610
1611        // dropping `_saved_no_color` will restore the previous value of
1612        // `NO_COLOR`.
1613    }
1614
1615    // Validates that span event configuration can be modified with a reload handle
1616    #[test]
1617    fn modify_span_events() {
1618        let make_writer = MockMakeWriter::default();
1619
1620        let inner_subscriber = fmt::Subscriber::default()
1621            .with_writer(make_writer.clone())
1622            .with_level(false)
1623            .with_ansi(false)
1624            .with_timer(MockTime)
1625            .with_span_events(FmtSpan::ACTIVE);
1626
1627        let (reloadable_subscriber, reload_handle) =
1628            crate::reload::Subscriber::new(inner_subscriber);
1629        let reload = reloadable_subscriber.with_collector(Registry::default());
1630
1631        with_default(reload, || {
1632            {
1633                let span1 = tracing::info_span!("span1", x = 42);
1634                let _e = span1.enter();
1635            }
1636
1637            let _ = reload_handle.modify(|s| s.set_span_events(FmtSpan::NONE));
1638
1639            // this span should not be logged at all!
1640            {
1641                let span2 = tracing::info_span!("span2", x = 100);
1642                let _e = span2.enter();
1643            }
1644
1645            {
1646                let span3 = tracing::info_span!("span3", x = 42);
1647                let _e = span3.enter();
1648
1649                // The span config was modified after span3 was already entered.
1650                // We should only see an exit
1651                let _ = reload_handle.modify(|s| s.set_span_events(FmtSpan::ACTIVE));
1652            }
1653        });
1654        let actual = sanitize_timings(make_writer.get_string());
1655        assert_eq!(
1656            "fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: enter\n\
1657             fake time span1{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: exit\n\
1658             fake time span3{x=42}: tracing_subscriber::fmt::fmt_subscriber::test: exit\n",
1659            actual.as_str()
1660        );
1661    }
1662}