tracing_subscriber_init/format/
json.rs

1// Copyright (c) 2023 tracing-subscriber-init developers
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use tracing::{Subscriber, metadata::LevelFilter};
10use tracing_subscriber::{
11    Layer,
12    filter::Filtered,
13    fmt::{
14        self,
15        format::{Format, Json, JsonFields},
16    },
17};
18
19use crate::{TracingConfig, utils::get_effective_level};
20
21#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
22/// Create a [`Json`](tracing_subscriber::fmt::format::Json) format layer configured from the given [`TracingConfig`].
23///
24/// # Example
25/// ```rust
26/// # use anyhow::Result;
27/// # use tracing::info;
28/// # use tracing_subscriber::Layer;
29/// # use tracing_subscriber_init::{json, set_default, TestAll, TracingConfig};
30/// #
31/// # pub fn main() -> Result<()> {
32/// let config = TestAll;
33/// let (layer, level_filter) = json(&config);
34/// let layer = layer.with_filter(level_filter);
35/// let _unused = set_default(vec![layer.boxed()]);
36/// info!("info level");
37/// #   Ok(())
38/// # }
39/// ```
40pub fn json<C, S>(config: &C) -> (fmt::Layer<S, JsonFields, Format<Json>>, LevelFilter)
41where
42    C: TracingConfig,
43    S: Subscriber,
44    for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
45{
46    let layer = fmt::layer()
47        .json()
48        .with_ansi(config.with_ansi())
49        .with_file(config.with_file())
50        .with_level(config.with_level())
51        .with_target(config.with_target())
52        .with_thread_ids(config.with_thread_ids())
53        .with_thread_names(config.with_thread_names())
54        .with_line_number(config.with_line_number())
55        .with_current_span(config.with_current_span())
56        .with_span_list(config.with_span_list());
57
58    let layer = if let Some(fmt_span) = config.with_span_events() {
59        layer.with_span_events(fmt_span)
60    } else {
61        layer
62    };
63    let level = get_effective_level(config.quiet(), config.verbose());
64    let level_filter = LevelFilter::from(level);
65    (layer, level_filter)
66}
67
68#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
69/// Create a [`Json`](tracing_subscriber::fmt::format::Json) format filtered layer configured from the given [`TracingConfig`].
70///
71/// # Example
72/// ```rust
73/// # use anyhow::Result;
74/// # use tracing::info;
75/// # use tracing_subscriber::Layer;
76/// # use tracing_subscriber_init::{json_filtered, set_default, TestAll, TracingConfig};
77/// #
78/// # pub fn main() -> Result<()> {
79/// let config = TestAll;
80/// let layer = json_filtered(&config);
81/// let _unused = set_default(vec![layer.boxed()]);
82/// info!("info level");
83/// #   Ok(())
84/// # }
85/// ```
86pub fn filtered<C, S>(
87    config: &C,
88) -> Filtered<fmt::Layer<S, JsonFields, Format<Json>>, LevelFilter, S>
89where
90    C: TracingConfig,
91    S: Subscriber,
92    for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
93{
94    let (layer, level_filter) = json(config);
95    layer.with_filter(level_filter)
96}
97
98#[cfg(test)]
99mod test {
100    use tracing::{Level, debug, error, info, span, trace, warn};
101    use tracing_subscriber::Layer;
102
103    use super::filtered as json_filtered;
104
105    use crate::{TestAll, set_default, utils::test::TestConfig};
106
107    #[test]
108    fn json_filtered_works() {
109        let config = TestConfig;
110        let layer = json_filtered(&config);
111        let _unused = set_default(vec![layer.boxed()]);
112        let span = span!(Level::INFO, "json_filtered_works");
113        let _enter = span.enter();
114        error!("error level");
115        warn!("warn level");
116        info!("info level");
117        debug!("debug level");
118        trace!("trace level");
119    }
120
121    #[test]
122    fn json_filtered_all_works() {
123        let config = TestAll;
124        let layer = json_filtered(&config);
125        let _unused = set_default(vec![layer.boxed()]);
126        let span = span!(Level::TRACE, "json_filtered_all_works");
127        let _enter = span.enter();
128        error!("error level");
129        warn!("warn level");
130        info!("info level");
131        debug!("debug level");
132        trace!("trace level");
133    }
134
135    #[cfg(feature = "tstime")]
136    #[test]
137    fn json_utc_works() {
138        use super::json;
139        use time::format_description::well_known::Iso8601;
140        use tracing_subscriber::fmt::time::UtcTime;
141
142        let config = TestConfig;
143        let (layer, level_filter) = json(&config);
144        let filtered_layer = layer
145            .with_timer(UtcTime::new(Iso8601::DEFAULT))
146            .with_filter(level_filter);
147        let _unused = set_default(vec![filtered_layer.boxed()]);
148        let span = span!(Level::INFO, "json_utc_works");
149        let _enter = span.enter();
150        error!("error level");
151        warn!("warn level");
152        info!("info level");
153        debug!("debug level");
154        trace!("trace level");
155    }
156}