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