]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
1 | //! A `Subscriber` for formatting and logging `tracing` data. |
2 | //! | |
a2a8927a | 3 | //! # Overview |
f035d41b XL |
4 | //! |
5 | //! [`tracing`] is a framework for instrumenting Rust programs with context-aware, | |
6 | //! structured, event-based diagnostic information. This crate provides an | |
7 | //! implementation of the [`Subscriber`] trait that records `tracing`'s `Event`s | |
8 | //! and `Span`s by formatting them as text and logging them to stdout. | |
9 | //! | |
a2a8927a | 10 | //! # Usage |
f035d41b XL |
11 | //! |
12 | //! First, add this to your `Cargo.toml` file: | |
13 | //! | |
14 | //! ```toml | |
15 | //! [dependencies] | |
5099ac24 | 16 | //! tracing-subscriber = "0.3" |
f035d41b XL |
17 | //! ``` |
18 | //! | |
5e7ed085 | 19 | //! *Compiler support: [requires `rustc` 1.49+][msrv]* |
5099ac24 FG |
20 | //! |
21 | //! [msrv]: ../index.html#supported-rust-versions | |
f035d41b XL |
22 | //! |
23 | //! Add the following to your executable to initialize the default subscriber: | |
24 | //! ```rust | |
25 | //! use tracing_subscriber; | |
26 | //! | |
27 | //! tracing_subscriber::fmt::init(); | |
28 | //! ``` | |
29 | //! | |
30 | //! ## Filtering Events with Environment Variables | |
31 | //! | |
c295e0f8 | 32 | //! The default subscriber installed by `init` enables you to filter events |
f035d41b XL |
33 | //! at runtime using environment variables (using the [`EnvFilter`]). |
34 | //! | |
35 | //! The filter syntax is a superset of the [`env_logger`] syntax. | |
36 | //! | |
37 | //! For example: | |
38 | //! - Setting `RUST_LOG=debug` enables all `Span`s and `Event`s | |
39 | //! set to the log level `DEBUG` or higher | |
40 | //! - Setting `RUST_LOG=my_crate=trace` enables `Span`s and `Event`s | |
41 | //! in `my_crate` at all log levels | |
42 | //! | |
43 | //! **Note**: This should **not** be called by libraries. Libraries should use | |
44 | //! [`tracing`] to publish `tracing` `Event`s. | |
45 | //! | |
a2a8927a | 46 | //! # Configuration |
f035d41b XL |
47 | //! |
48 | //! You can configure a subscriber instead of using the defaults with | |
49 | //! the following functions: | |
50 | //! | |
51 | //! ### Subscriber | |
52 | //! | |
53 | //! The [`FmtSubscriber`] formats and records `tracing` events as line-oriented logs. | |
54 | //! You can create one by calling: | |
55 | //! | |
56 | //! ```rust | |
c295e0f8 | 57 | //! let subscriber = tracing_subscriber::fmt() |
f035d41b XL |
58 | //! // ... add configuration |
59 | //! .finish(); | |
60 | //! ``` | |
61 | //! | |
5869c6ff XL |
62 | //! You can find the configuration methods for [`FmtSubscriber`] in |
63 | //! [`SubscriberBuilder`]. | |
64 | //! | |
a2a8927a | 65 | //! ## Formatters |
5869c6ff XL |
66 | //! |
67 | //! The output format used by the layer and subscriber in this module is | |
68 | //! represented by implementing the [`FormatEvent`] trait, and can be | |
69 | //! customized. This module provides a number of formatter implementations: | |
70 | //! | |
71 | //! * [`format::Full`]: The default formatter. This emits human-readable, | |
72 | //! single-line logs for each event that occurs, with the current span context | |
5e7ed085 FG |
73 | //! displayed before the formatted representation of the event. See |
74 | //! [here](format::Full#example-output) for sample output. | |
75 | //! | |
76 | //! * [`format::Compact`]: A variant of the default formatter, optimized for | |
77 | //! short line lengths. Fields from the current span context are appended to | |
78 | //! the fields of the formatted event. See | |
79 | //! [here](format::Compact#example-output) for sample output. | |
5869c6ff XL |
80 | //! |
81 | //! * [`format::Pretty`]: Emits excessively pretty, multi-line logs, optimized | |
82 | //! for human readability. This is primarily intended to be used in local | |
83 | //! development and debugging, or for command-line applications, where | |
84 | //! automated analysis and compact storage of logs is less of a priority than | |
5e7ed085 FG |
85 | //! readability and visual appeal. See [here](format::Pretty#example-output) |
86 | //! for sample output. | |
5869c6ff XL |
87 | //! |
88 | //! * [`format::Json`]: Outputs newline-delimited JSON logs. This is intended | |
89 | //! for production use with systems where structured logs are consumed as JSON | |
5e7ed085 FG |
90 | //! by analysis and viewing tools. The JSON output is not optimized for human |
91 | //! readability. See [here](format::Json#example-output) for sample output. | |
f035d41b | 92 | //! |
a2a8927a XL |
93 | //! ### Customizing Formatters |
94 | //! | |
95 | //! The formatting of log lines for spans and events is controlled by two | |
96 | //! traits, [`FormatEvent`] and [`FormatFields`]. The [`FormatEvent`] trait | |
97 | //! determines the overall formatting of the log line, such as what information | |
98 | //! from the event's metadata and span context is included and in what order. | |
99 | //! The [`FormatFields`] trait determines how fields — both the event's | |
100 | //! fields and fields on spans — are formatted. | |
101 | //! | |
102 | //! The [`fmt::format`] module provides several types which implement these traits, | |
103 | //! many of which expose additional configuration options to customize their | |
104 | //! output. The [`format::Format`] type implements common configuration used by | |
105 | //! all the formatters provided in this crate, and can be used as a builder to | |
106 | //! set specific formatting settings. For example: | |
107 | //! | |
108 | //! ``` | |
109 | //! use tracing_subscriber::fmt; | |
110 | //! | |
111 | //! // Configure a custom event formatter | |
112 | //! let format = fmt::format() | |
113 | //! .with_level(false) // don't include levels in formatted output | |
114 | //! .with_target(false) // don't include targets | |
115 | //! .with_thread_ids(true) // include the thread ID of the current thread | |
116 | //! .with_thread_names(true) // include the name of the current thread | |
117 | //! .compact(); // use the `Compact` formatting style. | |
118 | //! | |
5099ac24 | 119 | //! // Create a `fmt` subscriber that uses our custom event format, and set it |
a2a8927a XL |
120 | //! // as the default. |
121 | //! tracing_subscriber::fmt() | |
122 | //! .event_format(format) | |
123 | //! .init(); | |
124 | //! ``` | |
125 | //! | |
126 | //! However, if a specific output format is needed, other crates can | |
127 | //! also implement [`FormatEvent`] and [`FormatFields`]. See those traits' | |
128 | //! documentation for details on how to implement them. | |
129 | //! | |
130 | //! ## Filters | |
f035d41b XL |
131 | //! |
132 | //! If you want to filter the `tracing` `Events` based on environment | |
133 | //! variables, you can use the [`EnvFilter`] as follows: | |
134 | //! | |
135 | //! ```rust | |
136 | //! use tracing_subscriber::EnvFilter; | |
137 | //! | |
138 | //! let filter = EnvFilter::from_default_env(); | |
139 | //! ``` | |
140 | //! | |
141 | //! As mentioned above, the [`EnvFilter`] allows `Span`s and `Event`s to | |
142 | //! be filtered at runtime by setting the `RUST_LOG` environment variable. | |
143 | //! | |
144 | //! You can find the other available [`filter`]s in the documentation. | |
145 | //! | |
146 | //! ### Using Your Subscriber | |
147 | //! | |
148 | //! Finally, once you have configured your `Subscriber`, you need to | |
149 | //! configure your executable to use it. | |
150 | //! | |
151 | //! A subscriber can be installed globally using: | |
152 | //! ```rust | |
153 | //! use tracing; | |
154 | //! use tracing_subscriber::FmtSubscriber; | |
155 | //! | |
156 | //! let subscriber = FmtSubscriber::new(); | |
157 | //! | |
158 | //! tracing::subscriber::set_global_default(subscriber) | |
159 | //! .map_err(|_err| eprintln!("Unable to set global default subscriber")); | |
160 | //! // Note this will only fail if you try to set the global default | |
161 | //! // subscriber multiple times | |
162 | //! ``` | |
163 | //! | |
164 | //! ### Composing Layers | |
165 | //! | |
166 | //! Composing an [`EnvFilter`] `Layer` and a [format `Layer`](../fmt/struct.Layer.html): | |
167 | //! | |
168 | //! ```rust | |
169 | //! use tracing_subscriber::{fmt, EnvFilter}; | |
170 | //! use tracing_subscriber::prelude::*; | |
171 | //! | |
172 | //! let fmt_layer = fmt::layer() | |
173 | //! .with_target(false); | |
174 | //! let filter_layer = EnvFilter::try_from_default_env() | |
175 | //! .or_else(|_| EnvFilter::try_new("info")) | |
176 | //! .unwrap(); | |
177 | //! | |
178 | //! tracing_subscriber::registry() | |
179 | //! .with(filter_layer) | |
180 | //! .with(fmt_layer) | |
181 | //! .init(); | |
182 | //! ``` | |
183 | //! | |
184 | //! [`EnvFilter`]: ../filter/struct.EnvFilter.html | |
185 | //! [`env_logger`]: https://docs.rs/env_logger/ | |
186 | //! [`filter`]: ../filter/index.html | |
5869c6ff | 187 | //! [`SubscriberBuilder`]: ./struct.SubscriberBuilder.html |
f035d41b XL |
188 | //! [`FmtSubscriber`]: ./struct.Subscriber.html |
189 | //! [`Subscriber`]: | |
190 | //! https://docs.rs/tracing/latest/tracing/trait.Subscriber.html | |
191 | //! [`tracing`]: https://crates.io/crates/tracing | |
a2a8927a | 192 | //! [`fmt::format`]: mod@crate::fmt::format |
f035d41b XL |
193 | use std::{any::TypeId, error::Error, io}; |
194 | use tracing_core::{span, subscriber::Interest, Event, Metadata}; | |
195 | ||
196 | mod fmt_layer; | |
a2a8927a | 197 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] |
f035d41b | 198 | pub mod format; |
a2a8927a | 199 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] |
f035d41b | 200 | pub mod time; |
a2a8927a | 201 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] |
f035d41b | 202 | pub mod writer; |
a2a8927a | 203 | |
f035d41b XL |
204 | pub use fmt_layer::{FmtContext, FormattedFields, Layer}; |
205 | ||
206 | use crate::layer::Layer as _; | |
5099ac24 | 207 | use crate::util::SubscriberInitExt; |
f035d41b XL |
208 | use crate::{ |
209 | filter::LevelFilter, | |
210 | layer, | |
211 | registry::{LookupSpan, Registry}, | |
212 | }; | |
213 | ||
214 | #[doc(inline)] | |
215 | pub use self::{ | |
216 | format::{format, FormatEvent, FormatFields}, | |
217 | time::time, | |
29967ef6 | 218 | writer::{MakeWriter, TestWriter}, |
f035d41b XL |
219 | }; |
220 | ||
221 | /// A `Subscriber` that logs formatted representations of `tracing` events. | |
222 | /// | |
223 | /// This consists of an inner `Formatter` wrapped in a layer that performs filtering. | |
a2a8927a | 224 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] |
f035d41b XL |
225 | #[derive(Debug)] |
226 | pub struct Subscriber< | |
227 | N = format::DefaultFields, | |
228 | E = format::Format<format::Full>, | |
229 | F = LevelFilter, | |
230 | W = fn() -> io::Stdout, | |
231 | > { | |
232 | inner: layer::Layered<F, Formatter<N, E, W>>, | |
233 | } | |
234 | ||
235 | /// A `Subscriber` that logs formatted representations of `tracing` events. | |
236 | /// This type only logs formatted events; it does not perform any filtering. | |
a2a8927a | 237 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] |
f035d41b XL |
238 | pub type Formatter< |
239 | N = format::DefaultFields, | |
240 | E = format::Format<format::Full>, | |
241 | W = fn() -> io::Stdout, | |
242 | > = layer::Layered<fmt_layer::Layer<Registry, N, E, W>, Registry>; | |
243 | ||
244 | /// Configures and constructs `Subscriber`s. | |
a2a8927a | 245 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] |
f035d41b XL |
246 | #[derive(Debug)] |
247 | pub struct SubscriberBuilder< | |
248 | N = format::DefaultFields, | |
249 | E = format::Format<format::Full>, | |
250 | F = LevelFilter, | |
251 | W = fn() -> io::Stdout, | |
252 | > { | |
253 | filter: F, | |
254 | inner: Layer<Registry, N, E, W>, | |
255 | } | |
256 | ||
257 | /// Returns a new [`SubscriberBuilder`] for configuring a [formatting subscriber]. | |
258 | /// | |
259 | /// This is essentially shorthand for [`SubscriberBuilder::default()]`. | |
260 | /// | |
261 | /// # Examples | |
262 | /// | |
263 | /// Using [`init`] to set the default subscriber: | |
264 | /// | |
265 | /// ```rust | |
266 | /// tracing_subscriber::fmt().init(); | |
267 | /// ``` | |
268 | /// | |
269 | /// Configuring the output format: | |
270 | /// | |
271 | /// ```rust | |
272 | /// | |
273 | /// tracing_subscriber::fmt() | |
274 | /// // Configure formatting settings. | |
275 | /// .with_target(false) | |
276 | /// .with_timer(tracing_subscriber::fmt::time::uptime()) | |
277 | /// .with_level(true) | |
c295e0f8 | 278 | /// // Set the subscriber as the default. |
f035d41b XL |
279 | /// .init(); |
280 | /// ``` | |
281 | /// | |
282 | /// [`try_init`] returns an error if the default subscriber could not be set: | |
283 | /// | |
284 | /// ```rust | |
285 | /// use std::error::Error; | |
286 | /// | |
287 | /// fn init_subscriber() -> Result<(), Box<dyn Error + Send + Sync + 'static>> { | |
288 | /// tracing_subscriber::fmt() | |
c295e0f8 | 289 | /// // Configure the subscriber to emit logs in JSON format. |
f035d41b | 290 | /// .json() |
c295e0f8 | 291 | /// // Configure the subscriber to flatten event fields in the output JSON objects. |
f035d41b | 292 | /// .flatten_event(true) |
c295e0f8 | 293 | /// // Set the subscriber as the default, returning an error if this fails. |
f035d41b XL |
294 | /// .try_init()?; |
295 | /// | |
296 | /// Ok(()) | |
297 | /// } | |
298 | /// ``` | |
299 | /// | |
300 | /// Rather than setting the subscriber as the default, [`finish`] _returns_ the | |
301 | /// constructed subscriber, which may then be passed to other functions: | |
302 | /// | |
303 | /// ```rust | |
304 | /// let subscriber = tracing_subscriber::fmt() | |
305 | /// .with_max_level(tracing::Level::DEBUG) | |
306 | /// .compact() | |
307 | /// .finish(); | |
308 | /// | |
309 | /// tracing::subscriber::with_default(subscriber, || { | |
310 | /// // the subscriber will only be set as the default | |
311 | /// // inside this closure... | |
312 | /// }) | |
313 | /// ``` | |
314 | /// | |
a2a8927a | 315 | /// [formatting subscriber]: Subscriber |
5099ac24 | 316 | /// [`SubscriberBuilder::default()`]: struct.SubscriberBuilder.html#method.default |
a2a8927a XL |
317 | /// [`init`]: SubscriberBuilder::init() |
318 | /// [`try_init`]: SubscriberBuilder::try_init() | |
319 | /// [`finish`]: SubscriberBuilder::finish() | |
320 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] | |
f035d41b XL |
321 | pub fn fmt() -> SubscriberBuilder { |
322 | SubscriberBuilder::default() | |
323 | } | |
324 | ||
325 | /// Returns a new [formatting layer] that can be [composed] with other layers to | |
326 | /// construct a [`Subscriber`]. | |
327 | /// | |
5099ac24 | 328 | /// This is a shorthand for the equivalent [`Layer::default()`] function. |
f035d41b | 329 | /// |
a2a8927a XL |
330 | /// [formatting layer]: Layer |
331 | /// [composed]: crate::layer | |
5099ac24 | 332 | /// [`Layer::default()`]: struct.Layer.html#method.default |
a2a8927a | 333 | #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] |
f035d41b XL |
334 | pub fn layer<S>() -> Layer<S> { |
335 | Layer::default() | |
336 | } | |
337 | ||
338 | impl Subscriber { | |
339 | /// The maximum [verbosity level] that is enabled by a `Subscriber` by | |
340 | /// default. | |
341 | /// | |
342 | /// This can be overridden with the [`SubscriberBuilder::with_max_level`] method. | |
343 | /// | |
344 | /// [verbosity level]: https://docs.rs/tracing-core/0.1.5/tracing_core/struct.Level.html | |
345 | /// [`SubscriberBuilder::with_max_level`]: struct.SubscriberBuilder.html#method.with_max_level | |
346 | pub const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::INFO; | |
347 | ||
348 | /// Returns a new `SubscriberBuilder` for configuring a format subscriber. | |
349 | pub fn builder() -> SubscriberBuilder { | |
350 | SubscriberBuilder::default() | |
351 | } | |
352 | ||
353 | /// Returns a new format subscriber with the default configuration. | |
354 | pub fn new() -> Self { | |
355 | Default::default() | |
356 | } | |
357 | } | |
358 | ||
359 | impl Default for Subscriber { | |
360 | fn default() -> Self { | |
361 | SubscriberBuilder::default().finish() | |
362 | } | |
363 | } | |
364 | ||
365 | // === impl Subscriber === | |
366 | ||
367 | impl<N, E, F, W> tracing_core::Subscriber for Subscriber<N, E, F, W> | |
368 | where | |
369 | N: for<'writer> FormatFields<'writer> + 'static, | |
370 | E: FormatEvent<Registry, N> + 'static, | |
371 | F: layer::Layer<Formatter<N, E, W>> + 'static, | |
a2a8927a | 372 | W: for<'writer> MakeWriter<'writer> + 'static, |
f035d41b XL |
373 | layer::Layered<F, Formatter<N, E, W>>: tracing_core::Subscriber, |
374 | fmt_layer::Layer<Registry, N, E, W>: layer::Layer<Registry>, | |
375 | { | |
376 | #[inline] | |
377 | fn register_callsite(&self, meta: &'static Metadata<'static>) -> Interest { | |
378 | self.inner.register_callsite(meta) | |
379 | } | |
380 | ||
381 | #[inline] | |
382 | fn enabled(&self, meta: &Metadata<'_>) -> bool { | |
383 | self.inner.enabled(meta) | |
384 | } | |
385 | ||
386 | #[inline] | |
387 | fn new_span(&self, attrs: &span::Attributes<'_>) -> span::Id { | |
388 | self.inner.new_span(attrs) | |
389 | } | |
390 | ||
391 | #[inline] | |
392 | fn record(&self, span: &span::Id, values: &span::Record<'_>) { | |
393 | self.inner.record(span, values) | |
394 | } | |
395 | ||
396 | #[inline] | |
397 | fn record_follows_from(&self, span: &span::Id, follows: &span::Id) { | |
398 | self.inner.record_follows_from(span, follows) | |
399 | } | |
400 | ||
401 | #[inline] | |
402 | fn event(&self, event: &Event<'_>) { | |
403 | self.inner.event(event); | |
404 | } | |
405 | ||
406 | #[inline] | |
407 | fn enter(&self, id: &span::Id) { | |
408 | // TODO: add on_enter hook | |
409 | self.inner.enter(id); | |
410 | } | |
411 | ||
412 | #[inline] | |
413 | fn exit(&self, id: &span::Id) { | |
414 | self.inner.exit(id); | |
415 | } | |
416 | ||
417 | #[inline] | |
418 | fn current_span(&self) -> span::Current { | |
419 | self.inner.current_span() | |
420 | } | |
421 | ||
422 | #[inline] | |
423 | fn clone_span(&self, id: &span::Id) -> span::Id { | |
424 | self.inner.clone_span(id) | |
425 | } | |
426 | ||
427 | #[inline] | |
428 | fn try_close(&self, id: span::Id) -> bool { | |
429 | self.inner.try_close(id) | |
430 | } | |
431 | ||
6a06907d XL |
432 | #[inline] |
433 | fn max_level_hint(&self) -> Option<tracing_core::LevelFilter> { | |
434 | self.inner.max_level_hint() | |
435 | } | |
436 | ||
f035d41b XL |
437 | unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> { |
438 | if id == TypeId::of::<Self>() { | |
439 | Some(self as *const Self as *const ()) | |
440 | } else { | |
441 | self.inner.downcast_raw(id) | |
442 | } | |
443 | } | |
444 | } | |
445 | ||
446 | impl<'a, N, E, F, W> LookupSpan<'a> for Subscriber<N, E, F, W> | |
447 | where | |
448 | layer::Layered<F, Formatter<N, E, W>>: LookupSpan<'a>, | |
449 | { | |
450 | type Data = <layer::Layered<F, Formatter<N, E, W>> as LookupSpan<'a>>::Data; | |
451 | ||
452 | fn span_data(&'a self, id: &span::Id) -> Option<Self::Data> { | |
453 | self.inner.span_data(id) | |
454 | } | |
455 | } | |
456 | ||
457 | // ===== impl SubscriberBuilder ===== | |
458 | ||
459 | impl Default for SubscriberBuilder { | |
460 | fn default() -> Self { | |
461 | SubscriberBuilder { | |
462 | filter: Subscriber::DEFAULT_MAX_LEVEL, | |
463 | inner: Default::default(), | |
464 | } | |
465 | } | |
466 | } | |
467 | ||
468 | impl<N, E, F, W> SubscriberBuilder<N, E, F, W> | |
469 | where | |
470 | N: for<'writer> FormatFields<'writer> + 'static, | |
471 | E: FormatEvent<Registry, N> + 'static, | |
a2a8927a | 472 | W: for<'writer> MakeWriter<'writer> + 'static, |
f035d41b XL |
473 | F: layer::Layer<Formatter<N, E, W>> + Send + Sync + 'static, |
474 | fmt_layer::Layer<Registry, N, E, W>: layer::Layer<Registry> + Send + Sync + 'static, | |
475 | { | |
476 | /// Finish the builder, returning a new `FmtSubscriber`. | |
477 | pub fn finish(self) -> Subscriber<N, E, F, W> { | |
478 | let subscriber = self.inner.with_subscriber(Registry::default()); | |
479 | Subscriber { | |
480 | inner: self.filter.with_subscriber(subscriber), | |
481 | } | |
482 | } | |
483 | ||
484 | /// Install this Subscriber as the global default if one is | |
485 | /// not already set. | |
486 | /// | |
487 | /// If the `tracing-log` feature is enabled, this will also install | |
488 | /// the LogTracer to convert `Log` records into `tracing` `Event`s. | |
489 | /// | |
490 | /// # Errors | |
491 | /// Returns an Error if the initialization was unsuccessful, likely | |
492 | /// because a global subscriber was already installed by another | |
493 | /// call to `try_init`. | |
494 | pub fn try_init(self) -> Result<(), Box<dyn Error + Send + Sync + 'static>> { | |
6a06907d XL |
495 | use crate::util::SubscriberInitExt; |
496 | self.finish().try_init()?; | |
f035d41b | 497 | |
f035d41b XL |
498 | Ok(()) |
499 | } | |
500 | ||
501 | /// Install this Subscriber as the global default. | |
502 | /// | |
503 | /// If the `tracing-log` feature is enabled, this will also install | |
504 | /// the LogTracer to convert `Log` records into `tracing` `Event`s. | |
505 | /// | |
506 | /// # Panics | |
507 | /// Panics if the initialization was unsuccessful, likely because a | |
508 | /// global subscriber was already installed by another call to `try_init`. | |
509 | pub fn init(self) { | |
510 | self.try_init() | |
511 | .expect("Unable to install global subscriber") | |
512 | } | |
513 | } | |
514 | ||
17df50a5 | 515 | impl<N, E, F, W> From<SubscriberBuilder<N, E, F, W>> for tracing_core::Dispatch |
f035d41b XL |
516 | where |
517 | N: for<'writer> FormatFields<'writer> + 'static, | |
518 | E: FormatEvent<Registry, N> + 'static, | |
a2a8927a | 519 | W: for<'writer> MakeWriter<'writer> + 'static, |
f035d41b XL |
520 | F: layer::Layer<Formatter<N, E, W>> + Send + Sync + 'static, |
521 | fmt_layer::Layer<Registry, N, E, W>: layer::Layer<Registry> + Send + Sync + 'static, | |
522 | { | |
17df50a5 XL |
523 | fn from(builder: SubscriberBuilder<N, E, F, W>) -> tracing_core::Dispatch { |
524 | tracing_core::Dispatch::new(builder.finish()) | |
f035d41b XL |
525 | } |
526 | } | |
527 | ||
528 | impl<N, L, T, F, W> SubscriberBuilder<N, format::Format<L, T>, F, W> | |
529 | where | |
530 | N: for<'writer> FormatFields<'writer> + 'static, | |
531 | { | |
532 | /// Use the given [`timer`] for log message timestamps. | |
533 | /// | |
a2a8927a | 534 | /// See the [`time` module] for the provided timer implementations. |
f035d41b | 535 | /// |
a2a8927a XL |
536 | /// Note that using the `"time`"" feature flag enables the |
537 | /// additional time formatters [`UtcTime`] and [`LocalTime`], which use the | |
538 | /// [`time` crate] to provide more sophisticated timestamp formatting | |
539 | /// options. | |
f035d41b | 540 | /// |
a2a8927a XL |
541 | /// [`timer`]: time::FormatTime |
542 | /// [`time` module]: mod@time | |
543 | /// [`UtcTime`]: time::UtcTime | |
544 | /// [`LocalTime`]: time::LocalTime | |
545 | /// [`time` crate]: https://docs.rs/time/0.3 | |
f035d41b XL |
546 | pub fn with_timer<T2>(self, timer: T2) -> SubscriberBuilder<N, format::Format<L, T2>, F, W> { |
547 | SubscriberBuilder { | |
548 | filter: self.filter, | |
549 | inner: self.inner.with_timer(timer), | |
550 | } | |
551 | } | |
552 | ||
553 | /// Do not emit timestamps with log messages. | |
554 | pub fn without_time(self) -> SubscriberBuilder<N, format::Format<L, ()>, F, W> { | |
555 | SubscriberBuilder { | |
556 | filter: self.filter, | |
557 | inner: self.inner.without_time(), | |
558 | } | |
559 | } | |
560 | ||
561 | /// Configures how synthesized events are emitted at points in the [span | |
562 | /// lifecycle][lifecycle]. | |
563 | /// | |
564 | /// The following options are available: | |
565 | /// | |
566 | /// - `FmtSpan::NONE`: No events will be synthesized when spans are | |
567 | /// created, entered, exited, or closed. Data from spans will still be | |
568 | /// included as the context for formatted events. This is the default. | |
cdc7bbd5 XL |
569 | /// - `FmtSpan::NEW`: An event will be synthesized when spans are created. |
570 | /// - `FmtSpan::ENTER`: An event will be synthesized when spans are entered. | |
571 | /// - `FmtSpan::EXIT`: An event will be synthesized when spans are exited. | |
f035d41b XL |
572 | /// - `FmtSpan::CLOSE`: An event will be synthesized when a span closes. If |
573 | /// [timestamps are enabled][time] for this formatter, the generated | |
574 | /// event will contain fields with the span's _busy time_ (the total | |
575 | /// time for which it was entered) and _idle time_ (the total time that | |
576 | /// the span existed but was not entered). | |
cdc7bbd5 XL |
577 | /// - `FmtSpan::ACTIVE`: An event will be synthesized when spans are entered |
578 | /// or exited. | |
f035d41b XL |
579 | /// - `FmtSpan::FULL`: Events will be synthesized whenever a span is |
580 | /// created, entered, exited, or closed. If timestamps are enabled, the | |
581 | /// close event will contain the span's busy and idle time, as | |
582 | /// described above. | |
583 | /// | |
cdc7bbd5 XL |
584 | /// The options can be enabled in any combination. For instance, the following |
585 | /// will synthesize events whenever spans are created and closed: | |
586 | /// | |
587 | /// ```rust | |
588 | /// use tracing_subscriber::fmt::format::FmtSpan; | |
589 | /// use tracing_subscriber::fmt; | |
590 | /// | |
591 | /// let subscriber = fmt() | |
592 | /// .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) | |
593 | /// .finish(); | |
594 | /// ``` | |
595 | /// | |
f035d41b XL |
596 | /// Note that the generated events will only be part of the log output by |
597 | /// this formatter; they will not be recorded by other `Subscriber`s or by | |
598 | /// `Layer`s added to this subscriber. | |
599 | /// | |
600 | /// [lifecycle]: https://docs.rs/tracing/latest/tracing/span/index.html#the-span-lifecycle | |
601 | /// [time]: #method.without_time | |
602 | pub fn with_span_events(self, kind: format::FmtSpan) -> Self { | |
603 | SubscriberBuilder { | |
f035d41b | 604 | inner: self.inner.with_span_events(kind), |
cdc7bbd5 | 605 | ..self |
f035d41b XL |
606 | } |
607 | } | |
608 | ||
609 | /// Enable ANSI encoding for formatted events. | |
610 | #[cfg(feature = "ansi")] | |
611 | #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))] | |
612 | pub fn with_ansi(self, ansi: bool) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { | |
613 | SubscriberBuilder { | |
f035d41b | 614 | inner: self.inner.with_ansi(ansi), |
cdc7bbd5 | 615 | ..self |
f035d41b XL |
616 | } |
617 | } | |
618 | ||
619 | /// Sets whether or not an event's target is displayed. | |
620 | pub fn with_target( | |
621 | self, | |
622 | display_target: bool, | |
623 | ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { | |
624 | SubscriberBuilder { | |
f035d41b | 625 | inner: self.inner.with_target(display_target), |
cdc7bbd5 | 626 | ..self |
f035d41b XL |
627 | } |
628 | } | |
629 | ||
5099ac24 FG |
630 | /// Sets whether or not an event's [source code file path][file] is |
631 | /// displayed. | |
632 | /// | |
633 | /// [file]: tracing_core::Metadata::file | |
634 | pub fn with_file( | |
635 | self, | |
636 | display_filename: bool, | |
637 | ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { | |
638 | SubscriberBuilder { | |
639 | inner: self.inner.with_file(display_filename), | |
640 | ..self | |
641 | } | |
642 | } | |
643 | ||
644 | /// Sets whether or not an event's [source code line number][line] is | |
645 | /// displayed. | |
646 | /// | |
647 | /// [line]: tracing_core::Metadata::line | |
648 | pub fn with_line_number( | |
649 | self, | |
650 | display_line_number: bool, | |
651 | ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { | |
652 | SubscriberBuilder { | |
653 | inner: self.inner.with_line_number(display_line_number), | |
654 | ..self | |
655 | } | |
656 | } | |
657 | ||
f035d41b XL |
658 | /// Sets whether or not an event's level is displayed. |
659 | pub fn with_level( | |
660 | self, | |
661 | display_level: bool, | |
662 | ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { | |
663 | SubscriberBuilder { | |
f035d41b | 664 | inner: self.inner.with_level(display_level), |
cdc7bbd5 | 665 | ..self |
f035d41b XL |
666 | } |
667 | } | |
668 | ||
3dfed10e XL |
669 | /// Sets whether or not the [name] of the current thread is displayed |
670 | /// when formatting events | |
671 | /// | |
672 | /// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads | |
673 | pub fn with_thread_names( | |
674 | self, | |
675 | display_thread_names: bool, | |
676 | ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { | |
677 | SubscriberBuilder { | |
3dfed10e | 678 | inner: self.inner.with_thread_names(display_thread_names), |
cdc7bbd5 | 679 | ..self |
3dfed10e XL |
680 | } |
681 | } | |
682 | ||
683 | /// Sets whether or not the [thread ID] of the current thread is displayed | |
684 | /// when formatting events | |
685 | /// | |
686 | /// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html | |
687 | pub fn with_thread_ids( | |
688 | self, | |
689 | display_thread_ids: bool, | |
690 | ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { | |
691 | SubscriberBuilder { | |
3dfed10e | 692 | inner: self.inner.with_thread_ids(display_thread_ids), |
cdc7bbd5 | 693 | ..self |
3dfed10e XL |
694 | } |
695 | } | |
696 | ||
f035d41b XL |
697 | /// Sets the subscriber being built to use a less verbose formatter. |
698 | /// | |
5869c6ff | 699 | /// See [`format::Compact`]. |
f035d41b XL |
700 | pub fn compact(self) -> SubscriberBuilder<N, format::Format<format::Compact, T>, F, W> |
701 | where | |
702 | N: for<'writer> FormatFields<'writer> + 'static, | |
703 | { | |
704 | SubscriberBuilder { | |
705 | filter: self.filter, | |
706 | inner: self.inner.compact(), | |
707 | } | |
708 | } | |
709 | ||
5869c6ff XL |
710 | /// Sets the subscriber being built to use an [excessively pretty, human-readable formatter](crate::fmt::format::Pretty). |
711 | #[cfg(feature = "ansi")] | |
712 | #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))] | |
713 | pub fn pretty( | |
714 | self, | |
715 | ) -> SubscriberBuilder<format::Pretty, format::Format<format::Pretty, T>, F, W> { | |
716 | SubscriberBuilder { | |
717 | filter: self.filter, | |
718 | inner: self.inner.pretty(), | |
719 | } | |
720 | } | |
721 | ||
f035d41b XL |
722 | /// Sets the subscriber being built to use a JSON formatter. |
723 | /// | |
724 | /// See [`format::Json`](../fmt/format/struct.Json.html) | |
725 | #[cfg(feature = "json")] | |
726 | #[cfg_attr(docsrs, doc(cfg(feature = "json")))] | |
727 | pub fn json( | |
728 | self, | |
729 | ) -> SubscriberBuilder<format::JsonFields, format::Format<format::Json, T>, F, W> | |
730 | where | |
731 | N: for<'writer> FormatFields<'writer> + 'static, | |
732 | { | |
733 | SubscriberBuilder { | |
734 | filter: self.filter, | |
735 | inner: self.inner.json(), | |
736 | } | |
737 | } | |
738 | } | |
739 | ||
740 | #[cfg(feature = "json")] | |
741 | #[cfg_attr(docsrs, doc(cfg(feature = "json")))] | |
742 | impl<T, F, W> SubscriberBuilder<format::JsonFields, format::Format<format::Json, T>, F, W> { | |
743 | /// Sets the json subscriber being built to flatten event metadata. | |
744 | /// | |
745 | /// See [`format::Json`](../fmt/format/struct.Json.html) | |
746 | pub fn flatten_event( | |
747 | self, | |
748 | flatten_event: bool, | |
749 | ) -> SubscriberBuilder<format::JsonFields, format::Format<format::Json, T>, F, W> { | |
750 | SubscriberBuilder { | |
751 | filter: self.filter, | |
752 | inner: self.inner.flatten_event(flatten_event), | |
753 | } | |
754 | } | |
3dfed10e | 755 | |
5869c6ff | 756 | /// Sets whether or not the JSON subscriber being built will include the current span |
3dfed10e XL |
757 | /// in formatted events. |
758 | /// | |
759 | /// See [`format::Json`](../fmt/format/struct.Json.html) | |
760 | pub fn with_current_span( | |
761 | self, | |
762 | display_current_span: bool, | |
763 | ) -> SubscriberBuilder<format::JsonFields, format::Format<format::Json, T>, F, W> { | |
764 | SubscriberBuilder { | |
765 | filter: self.filter, | |
766 | inner: self.inner.with_current_span(display_current_span), | |
767 | } | |
768 | } | |
769 | ||
5869c6ff | 770 | /// Sets whether or not the JSON subscriber being built will include a list (from |
3dfed10e XL |
771 | /// root to leaf) of all currently entered spans in formatted events. |
772 | /// | |
773 | /// See [`format::Json`](../fmt/format/struct.Json.html) | |
774 | pub fn with_span_list( | |
775 | self, | |
776 | display_span_list: bool, | |
777 | ) -> SubscriberBuilder<format::JsonFields, format::Format<format::Json, T>, F, W> { | |
778 | SubscriberBuilder { | |
779 | filter: self.filter, | |
780 | inner: self.inner.with_span_list(display_span_list), | |
781 | } | |
782 | } | |
f035d41b XL |
783 | } |
784 | ||
785 | #[cfg(feature = "env-filter")] | |
786 | #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] | |
787 | impl<N, E, W> SubscriberBuilder<N, E, crate::EnvFilter, W> | |
788 | where | |
789 | Formatter<N, E, W>: tracing_core::Subscriber + 'static, | |
790 | { | |
791 | /// Configures the subscriber being built to allow filter reloading at | |
792 | /// runtime. | |
793 | pub fn with_filter_reloading( | |
794 | self, | |
795 | ) -> SubscriberBuilder<N, E, crate::reload::Layer<crate::EnvFilter, Formatter<N, E, W>>, W> | |
796 | { | |
797 | let (filter, _) = crate::reload::Layer::new(self.filter); | |
798 | SubscriberBuilder { | |
799 | filter, | |
800 | inner: self.inner, | |
801 | } | |
802 | } | |
803 | } | |
804 | ||
805 | #[cfg(feature = "env-filter")] | |
806 | #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] | |
807 | impl<N, E, W> SubscriberBuilder<N, E, crate::reload::Layer<crate::EnvFilter, Formatter<N, E, W>>, W> | |
808 | where | |
809 | Formatter<N, E, W>: tracing_core::Subscriber + 'static, | |
810 | { | |
811 | /// Returns a `Handle` that may be used to reload the constructed subscriber's | |
812 | /// filter. | |
813 | pub fn reload_handle(&self) -> crate::reload::Handle<crate::EnvFilter, Formatter<N, E, W>> { | |
814 | self.filter.handle() | |
815 | } | |
816 | } | |
817 | ||
818 | impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { | |
5099ac24 | 819 | /// Sets the field formatter that the subscriber being built will use to record |
f035d41b XL |
820 | /// fields. |
821 | /// | |
822 | /// For example: | |
823 | /// ```rust | |
824 | /// use tracing_subscriber::fmt::format; | |
825 | /// use tracing_subscriber::prelude::*; | |
826 | /// | |
827 | /// let formatter = | |
828 | /// // Construct a custom formatter for `Debug` fields | |
829 | /// format::debug_fn(|writer, field, value| write!(writer, "{}: {:?}", field, value)) | |
830 | /// // Use the `tracing_subscriber::MakeFmtExt` trait to wrap the | |
831 | /// // formatter so that a delimiter is added between fields. | |
832 | /// .delimited(", "); | |
833 | /// | |
834 | /// let subscriber = tracing_subscriber::fmt() | |
835 | /// .fmt_fields(formatter) | |
836 | /// .finish(); | |
837 | /// # drop(subscriber) | |
838 | /// ``` | |
839 | pub fn fmt_fields<N2>(self, fmt_fields: N2) -> SubscriberBuilder<N2, E, F, W> | |
840 | where | |
841 | N2: for<'writer> FormatFields<'writer> + 'static, | |
842 | { | |
843 | SubscriberBuilder { | |
844 | filter: self.filter, | |
845 | inner: self.inner.fmt_fields(fmt_fields), | |
846 | } | |
847 | } | |
848 | ||
849 | /// Sets the [`EnvFilter`] that the subscriber will use to determine if | |
850 | /// a span or event is enabled. | |
851 | /// | |
852 | /// Note that this method requires the "env-filter" feature flag to be enabled. | |
853 | /// | |
854 | /// If a filter was previously set, or a maximum level was set by the | |
855 | /// [`with_max_level`] method, that value is replaced by the new filter. | |
856 | /// | |
857 | /// # Examples | |
858 | /// | |
859 | /// Setting a filter based on the value of the `RUST_LOG` environment | |
860 | /// variable: | |
861 | /// ```rust | |
862 | /// use tracing_subscriber::{fmt, EnvFilter}; | |
863 | /// | |
864 | /// fmt() | |
865 | /// .with_env_filter(EnvFilter::from_default_env()) | |
866 | /// .init(); | |
867 | /// ``` | |
868 | /// | |
869 | /// Setting a filter based on a pre-set filter directive string: | |
870 | /// ```rust | |
871 | /// use tracing_subscriber::fmt; | |
872 | /// | |
873 | /// fmt() | |
874 | /// .with_env_filter("my_crate=info,my_crate::my_mod=debug,[my_span]=trace") | |
875 | /// .init(); | |
876 | /// ``` | |
877 | /// | |
878 | /// Adding additional directives to a filter constructed from an env var: | |
879 | /// ```rust | |
880 | /// use tracing_subscriber::{fmt, filter::{EnvFilter, LevelFilter}}; | |
881 | /// | |
882 | /// # fn filter() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> { | |
883 | /// let filter = EnvFilter::try_from_env("MY_CUSTOM_FILTER_ENV_VAR")? | |
884 | /// // Set the base level when not matched by other directives to WARN. | |
885 | /// .add_directive(LevelFilter::WARN.into()) | |
886 | /// // Set the max level for `my_crate::my_mod` to DEBUG, overriding | |
887 | /// // any directives parsed from the env variable. | |
888 | /// .add_directive("my_crate::my_mod=debug".parse()?); | |
889 | /// | |
890 | /// fmt() | |
891 | /// .with_env_filter(filter) | |
892 | /// .try_init()?; | |
893 | /// # Ok(())} | |
894 | /// ``` | |
895 | /// [`EnvFilter`]: ../filter/struct.EnvFilter.html | |
896 | /// [`with_max_level`]: #method.with_max_level | |
897 | #[cfg(feature = "env-filter")] | |
898 | #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] | |
899 | pub fn with_env_filter( | |
900 | self, | |
901 | filter: impl Into<crate::EnvFilter>, | |
902 | ) -> SubscriberBuilder<N, E, crate::EnvFilter, W> | |
903 | where | |
904 | Formatter<N, E, W>: tracing_core::Subscriber + 'static, | |
905 | { | |
906 | let filter = filter.into(); | |
907 | SubscriberBuilder { | |
908 | filter, | |
909 | inner: self.inner, | |
910 | } | |
911 | } | |
912 | ||
913 | /// Sets the maximum [verbosity level] that will be enabled by the | |
914 | /// subscriber. | |
915 | /// | |
916 | /// If the max level has already been set, or a [`EnvFilter`] was added by | |
5099ac24 | 917 | /// [`with_env_filter`], this replaces that configuration with the new |
f035d41b XL |
918 | /// maximum level. |
919 | /// | |
920 | /// # Examples | |
921 | /// | |
922 | /// Enable up to the `DEBUG` verbosity level: | |
923 | /// ```rust | |
924 | /// use tracing_subscriber::fmt; | |
925 | /// use tracing::Level; | |
926 | /// | |
927 | /// fmt() | |
928 | /// .with_max_level(Level::DEBUG) | |
929 | /// .init(); | |
930 | /// ``` | |
931 | /// This subscriber won't record any spans or events! | |
932 | /// ```rust | |
933 | /// use tracing_subscriber::{fmt, filter::LevelFilter}; | |
934 | /// | |
935 | /// let subscriber = fmt() | |
936 | /// .with_max_level(LevelFilter::OFF) | |
937 | /// .finish(); | |
938 | /// ``` | |
939 | /// [verbosity level]: https://docs.rs/tracing-core/0.1.5/tracing_core/struct.Level.html | |
5099ac24 FG |
940 | /// [`EnvFilter`]: struct@crate::filter::EnvFilter |
941 | /// [`with_env_filter`]: fn@Self::with_env_filter | |
f035d41b XL |
942 | pub fn with_max_level( |
943 | self, | |
944 | filter: impl Into<LevelFilter>, | |
945 | ) -> SubscriberBuilder<N, E, LevelFilter, W> { | |
946 | let filter = filter.into(); | |
947 | SubscriberBuilder { | |
948 | filter, | |
949 | inner: self.inner, | |
950 | } | |
951 | } | |
952 | ||
5099ac24 FG |
953 | /// Sets the [event formatter][`FormatEvent`] that the subscriber being built |
954 | /// will use to format events that occur. | |
955 | /// | |
956 | /// The event formatter may be any type implementing the [`FormatEvent`] | |
957 | /// trait, which is implemented for all functions taking a [`FmtContext`], a | |
958 | /// [`Writer`], and an [`Event`]. | |
959 | /// | |
960 | /// # Examples | |
961 | /// | |
962 | /// Setting a type implementing [`FormatEvent`] as the formatter: | |
963 | /// | |
964 | /// ```rust | |
965 | /// use tracing_subscriber::fmt::format; | |
966 | /// | |
967 | /// let subscriber = tracing_subscriber::fmt() | |
968 | /// .event_format(format().compact()) | |
969 | /// .finish(); | |
970 | /// ``` | |
971 | /// | |
972 | /// [`Writer`]: struct@self::format::Writer | |
f035d41b XL |
973 | pub fn event_format<E2>(self, fmt_event: E2) -> SubscriberBuilder<N, E2, F, W> |
974 | where | |
975 | E2: FormatEvent<Registry, N> + 'static, | |
976 | N: for<'writer> FormatFields<'writer> + 'static, | |
a2a8927a | 977 | W: for<'writer> MakeWriter<'writer> + 'static, |
f035d41b XL |
978 | { |
979 | SubscriberBuilder { | |
980 | filter: self.filter, | |
981 | inner: self.inner.event_format(fmt_event), | |
982 | } | |
983 | } | |
984 | ||
f035d41b XL |
985 | /// Sets the [`MakeWriter`] that the subscriber being built will use to write events. |
986 | /// | |
987 | /// # Examples | |
988 | /// | |
989 | /// Using `stderr` rather than `stdout`: | |
990 | /// | |
991 | /// ```rust | |
992 | /// use tracing_subscriber::fmt; | |
993 | /// use std::io; | |
994 | /// | |
995 | /// fmt() | |
996 | /// .with_writer(io::stderr) | |
997 | /// .init(); | |
998 | /// ``` | |
f035d41b XL |
999 | pub fn with_writer<W2>(self, make_writer: W2) -> SubscriberBuilder<N, E, F, W2> |
1000 | where | |
a2a8927a | 1001 | W2: for<'writer> MakeWriter<'writer> + 'static, |
f035d41b XL |
1002 | { |
1003 | SubscriberBuilder { | |
1004 | filter: self.filter, | |
1005 | inner: self.inner.with_writer(make_writer), | |
1006 | } | |
1007 | } | |
29967ef6 XL |
1008 | |
1009 | /// Configures the subscriber to support [`libtest`'s output capturing][capturing] when used in | |
1010 | /// unit tests. | |
1011 | /// | |
1012 | /// See [`TestWriter`] for additional details. | |
1013 | /// | |
1014 | /// # Examples | |
1015 | /// | |
1016 | /// Using [`TestWriter`] to let `cargo test` capture test output. Note that we do not install it | |
1017 | /// globally as it may cause conflicts. | |
1018 | /// | |
1019 | /// ```rust | |
1020 | /// use tracing_subscriber::fmt; | |
1021 | /// use tracing::subscriber; | |
1022 | /// | |
1023 | /// subscriber::set_default( | |
1024 | /// fmt() | |
1025 | /// .with_test_writer() | |
1026 | /// .finish() | |
1027 | /// ); | |
1028 | /// ``` | |
1029 | /// | |
1030 | /// [capturing]: | |
1031 | /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output | |
1032 | /// [`TestWriter`]: writer/struct.TestWriter.html | |
1033 | pub fn with_test_writer(self) -> SubscriberBuilder<N, E, F, TestWriter> { | |
1034 | SubscriberBuilder { | |
1035 | filter: self.filter, | |
1036 | inner: self.inner.with_writer(TestWriter::default()), | |
1037 | } | |
1038 | } | |
5099ac24 FG |
1039 | |
1040 | /// Updates the event formatter by applying a function to the existing event formatter. | |
1041 | /// | |
1042 | /// This sets the event formatter that the subscriber being built will use to record fields. | |
1043 | /// | |
1044 | /// # Examples | |
1045 | /// | |
1046 | /// Updating an event formatter: | |
1047 | /// | |
1048 | /// ```rust | |
1049 | /// let subscriber = tracing_subscriber::fmt() | |
1050 | /// .map_event_format(|e| e.compact()) | |
1051 | /// .finish(); | |
1052 | /// ``` | |
1053 | pub fn map_event_format<E2>(self, f: impl FnOnce(E) -> E2) -> SubscriberBuilder<N, E2, F, W> | |
1054 | where | |
1055 | E2: FormatEvent<Registry, N> + 'static, | |
1056 | N: for<'writer> FormatFields<'writer> + 'static, | |
1057 | W: for<'writer> MakeWriter<'writer> + 'static, | |
1058 | { | |
1059 | SubscriberBuilder { | |
1060 | filter: self.filter, | |
1061 | inner: self.inner.map_event_format(f), | |
1062 | } | |
1063 | } | |
1064 | ||
1065 | /// Updates the field formatter by applying a function to the existing field formatter. | |
1066 | /// | |
1067 | /// This sets the field formatter that the subscriber being built will use to record fields. | |
1068 | /// | |
1069 | /// # Examples | |
1070 | /// | |
1071 | /// Updating a field formatter: | |
1072 | /// | |
1073 | /// ```rust | |
1074 | /// use tracing_subscriber::field::MakeExt; | |
1075 | /// let subscriber = tracing_subscriber::fmt() | |
1076 | /// .map_fmt_fields(|f| f.debug_alt()) | |
1077 | /// .finish(); | |
1078 | /// ``` | |
1079 | pub fn map_fmt_fields<N2>(self, f: impl FnOnce(N) -> N2) -> SubscriberBuilder<N2, E, F, W> | |
1080 | where | |
1081 | N2: for<'writer> FormatFields<'writer> + 'static, | |
1082 | { | |
1083 | SubscriberBuilder { | |
1084 | filter: self.filter, | |
1085 | inner: self.inner.map_fmt_fields(f), | |
1086 | } | |
1087 | } | |
1088 | ||
1089 | /// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`]. | |
1090 | /// | |
1091 | /// This sets the [`MakeWriter`] that the subscriber being built will use to write events. | |
1092 | /// | |
1093 | /// # Examples | |
1094 | /// | |
1095 | /// Redirect output to stderr if level is <= WARN: | |
1096 | /// | |
1097 | /// ```rust | |
1098 | /// use tracing::Level; | |
1099 | /// use tracing_subscriber::fmt::{self, writer::MakeWriterExt}; | |
1100 | /// | |
1101 | /// let stderr = std::io::stderr.with_max_level(Level::WARN); | |
1102 | /// let layer = tracing_subscriber::fmt() | |
1103 | /// .map_writer(move |w| stderr.or_else(w)) | |
1104 | /// .finish(); | |
1105 | /// ``` | |
1106 | pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> SubscriberBuilder<N, E, F, W2> | |
1107 | where | |
1108 | W2: for<'writer> MakeWriter<'writer> + 'static, | |
1109 | { | |
1110 | SubscriberBuilder { | |
1111 | filter: self.filter, | |
1112 | inner: self.inner.map_writer(f), | |
1113 | } | |
1114 | } | |
f035d41b XL |
1115 | } |
1116 | ||
1117 | /// Install a global tracing subscriber that listens for events and | |
1118 | /// filters based on the value of the [`RUST_LOG` environment variable], | |
1119 | /// if one is not already set. | |
1120 | /// | |
1121 | /// If the `tracing-log` feature is enabled, this will also install | |
1122 | /// the [`LogTracer`] to convert `log` records into `tracing` `Event`s. | |
1123 | /// | |
1124 | /// This is shorthand for | |
1125 | /// | |
1126 | /// ```rust | |
1127 | /// # fn doc() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> { | |
1128 | /// tracing_subscriber::fmt().try_init() | |
1129 | /// # } | |
1130 | /// ``` | |
1131 | /// | |
1132 | /// | |
1133 | /// # Errors | |
1134 | /// | |
1135 | /// Returns an Error if the initialization was unsuccessful, | |
1136 | /// likely because a global subscriber was already installed by another | |
1137 | /// call to `try_init`. | |
1138 | /// | |
1139 | /// [`LogTracer`]: | |
1140 | /// https://docs.rs/tracing-log/0.1.0/tracing_log/struct.LogTracer.html | |
1141 | /// [`RUST_LOG` environment variable]: | |
1142 | /// ../filter/struct.EnvFilter.html#associatedconstant.DEFAULT_ENV | |
1143 | pub fn try_init() -> Result<(), Box<dyn Error + Send + Sync + 'static>> { | |
1144 | let builder = Subscriber::builder(); | |
1145 | ||
1146 | #[cfg(feature = "env-filter")] | |
1147 | let builder = builder.with_env_filter(crate::EnvFilter::from_default_env()); | |
1148 | ||
5099ac24 FG |
1149 | // If `env-filter` is disabled, remove the default max level filter from the |
1150 | // subscriber; it will be added to the `Targets` filter instead if no filter | |
1151 | // is set in `RUST_LOG`. | |
1152 | // Replacing the default `LevelFilter` with an `EnvFilter` would imply this, | |
1153 | // but we can't replace the builder's filter with a `Targets` filter yet. | |
1154 | #[cfg(not(feature = "env-filter"))] | |
1155 | let builder = builder.with_max_level(LevelFilter::TRACE); | |
1156 | ||
1157 | let subscriber = builder.finish(); | |
1158 | #[cfg(not(feature = "env-filter"))] | |
1159 | let subscriber = { | |
1160 | use crate::{filter::Targets, layer::SubscriberExt}; | |
1161 | use std::{env, str::FromStr}; | |
1162 | let targets = match env::var("RUST_LOG") { | |
1163 | Ok(var) => Targets::from_str(&var) | |
1164 | .map_err(|e| { | |
1165 | eprintln!("Ignoring `RUST_LOG={:?}`: {}", var, e); | |
1166 | }) | |
1167 | .unwrap_or_default(), | |
1168 | Err(env::VarError::NotPresent) => { | |
1169 | Targets::new().with_default(Subscriber::DEFAULT_MAX_LEVEL) | |
1170 | } | |
1171 | Err(e) => { | |
1172 | eprintln!("Ignoring `RUST_LOG`: {}", e); | |
1173 | Targets::new().with_default(Subscriber::DEFAULT_MAX_LEVEL) | |
1174 | } | |
1175 | }; | |
1176 | subscriber.with(targets) | |
1177 | }; | |
1178 | ||
1179 | subscriber.try_init().map_err(Into::into) | |
f035d41b XL |
1180 | } |
1181 | ||
1182 | /// Install a global tracing subscriber that listens for events and | |
1183 | /// filters based on the value of the [`RUST_LOG` environment variable]. | |
1184 | /// | |
1185 | /// If the `tracing-log` feature is enabled, this will also install | |
1186 | /// the LogTracer to convert `Log` records into `tracing` `Event`s. | |
1187 | /// | |
1188 | /// This is shorthand for | |
1189 | /// | |
1190 | /// ```rust | |
1191 | /// tracing_subscriber::fmt().init() | |
1192 | /// ``` | |
1193 | /// | |
1194 | /// # Panics | |
1195 | /// Panics if the initialization was unsuccessful, likely because a | |
1196 | /// global subscriber was already installed by another call to `try_init`. | |
1197 | /// | |
1198 | /// [`RUST_LOG` environment variable]: | |
1199 | /// ../filter/struct.EnvFilter.html#associatedconstant.DEFAULT_ENV | |
1200 | pub fn init() { | |
1201 | try_init().expect("Unable to install global subscriber") | |
1202 | } | |
1203 | ||
1204 | #[cfg(test)] | |
1205 | mod test { | |
1206 | use crate::{ | |
1207 | filter::LevelFilter, | |
1208 | fmt::{ | |
1209 | format::{self, Format}, | |
1210 | time, | |
1211 | writer::MakeWriter, | |
1212 | Subscriber, | |
1213 | }, | |
1214 | }; | |
1215 | use std::{ | |
1216 | io, | |
a2a8927a | 1217 | sync::{Arc, Mutex, MutexGuard, TryLockError}, |
f035d41b XL |
1218 | }; |
1219 | use tracing_core::dispatcher::Dispatch; | |
1220 | ||
a2a8927a XL |
1221 | pub(crate) struct MockWriter { |
1222 | buf: Arc<Mutex<Vec<u8>>>, | |
f035d41b XL |
1223 | } |
1224 | ||
a2a8927a XL |
1225 | impl MockWriter { |
1226 | pub(crate) fn new(buf: Arc<Mutex<Vec<u8>>>) -> Self { | |
f035d41b XL |
1227 | Self { buf } |
1228 | } | |
1229 | ||
1230 | pub(crate) fn map_error<Guard>(err: TryLockError<Guard>) -> io::Error { | |
1231 | match err { | |
1232 | TryLockError::WouldBlock => io::Error::from(io::ErrorKind::WouldBlock), | |
1233 | TryLockError::Poisoned(_) => io::Error::from(io::ErrorKind::Other), | |
1234 | } | |
1235 | } | |
1236 | ||
a2a8927a | 1237 | pub(crate) fn buf(&self) -> io::Result<MutexGuard<'_, Vec<u8>>> { |
f035d41b XL |
1238 | self.buf.try_lock().map_err(Self::map_error) |
1239 | } | |
1240 | } | |
1241 | ||
a2a8927a | 1242 | impl io::Write for MockWriter { |
f035d41b XL |
1243 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
1244 | self.buf()?.write(buf) | |
1245 | } | |
1246 | ||
1247 | fn flush(&mut self) -> io::Result<()> { | |
1248 | self.buf()?.flush() | |
1249 | } | |
1250 | } | |
1251 | ||
a2a8927a XL |
1252 | #[derive(Clone, Default)] |
1253 | pub(crate) struct MockMakeWriter { | |
1254 | buf: Arc<Mutex<Vec<u8>>>, | |
f035d41b XL |
1255 | } |
1256 | ||
a2a8927a XL |
1257 | impl MockMakeWriter { |
1258 | pub(crate) fn new(buf: Arc<Mutex<Vec<u8>>>) -> Self { | |
f035d41b XL |
1259 | Self { buf } |
1260 | } | |
17df50a5 | 1261 | |
a2a8927a XL |
1262 | #[cfg(feature = "json")] |
1263 | pub(crate) fn buf(&self) -> MutexGuard<'_, Vec<u8>> { | |
17df50a5 XL |
1264 | self.buf.lock().unwrap() |
1265 | } | |
136023e0 XL |
1266 | |
1267 | pub(crate) fn get_string(&self) -> String { | |
a2a8927a XL |
1268 | let mut buf = self.buf.lock().expect("lock shouldn't be poisoned"); |
1269 | let string = std::str::from_utf8(&buf[..]) | |
1270 | .expect("formatter should not have produced invalid utf-8") | |
1271 | .to_owned(); | |
1272 | buf.clear(); | |
1273 | string | |
136023e0 | 1274 | } |
f035d41b XL |
1275 | } |
1276 | ||
a2a8927a XL |
1277 | impl<'a> MakeWriter<'a> for MockMakeWriter { |
1278 | type Writer = MockWriter; | |
f035d41b | 1279 | |
a2a8927a XL |
1280 | fn make_writer(&'a self) -> Self::Writer { |
1281 | MockWriter::new(self.buf.clone()) | |
f035d41b XL |
1282 | } |
1283 | } | |
1284 | ||
1285 | #[test] | |
1286 | fn impls() { | |
1287 | let f = Format::default().with_timer(time::Uptime::default()); | |
1288 | let subscriber = Subscriber::builder().event_format(f).finish(); | |
1289 | let _dispatch = Dispatch::new(subscriber); | |
1290 | ||
1291 | let f = format::Format::default(); | |
1292 | let subscriber = Subscriber::builder().event_format(f).finish(); | |
1293 | let _dispatch = Dispatch::new(subscriber); | |
1294 | ||
1295 | let f = format::Format::default().compact(); | |
1296 | let subscriber = Subscriber::builder().event_format(f).finish(); | |
1297 | let _dispatch = Dispatch::new(subscriber); | |
1298 | } | |
1299 | ||
1300 | #[test] | |
1301 | fn subscriber_downcasts() { | |
1302 | let subscriber = Subscriber::builder().finish(); | |
1303 | let dispatch = Dispatch::new(subscriber); | |
1304 | assert!(dispatch.downcast_ref::<Subscriber>().is_some()); | |
1305 | } | |
1306 | ||
1307 | #[test] | |
1308 | fn subscriber_downcasts_to_parts() { | |
1309 | let subscriber = Subscriber::new(); | |
1310 | let dispatch = Dispatch::new(subscriber); | |
1311 | assert!(dispatch.downcast_ref::<format::DefaultFields>().is_some()); | |
1312 | assert!(dispatch.downcast_ref::<LevelFilter>().is_some()); | |
1313 | assert!(dispatch.downcast_ref::<format::Format>().is_some()) | |
1314 | } | |
1315 | ||
1316 | #[test] | |
1317 | fn is_lookup_span() { | |
1318 | fn assert_lookup_span<T: for<'a> crate::registry::LookupSpan<'a>>(_: T) {} | |
1319 | let subscriber = Subscriber::new(); | |
1320 | assert_lookup_span(subscriber) | |
1321 | } | |
1322 | } |