tracing_subscriber/fmt/time/time_crate.rs
1use crate::fmt::{format::Writer, time::FormatTime, writer::WriteAdaptor};
2use std::fmt;
3use time::{format_description::well_known, formatting::Formattable, OffsetDateTime};
4
5/// Formats the current [local time] using a [formatter] from the [`time` crate].
6///
7/// To format the current [UTC time] instead, use the [`UtcTime`] type.
8///
9/// <div class="example-wrap" style="display:inline-block">
10/// <pre class="compile_fail" style="white-space:normal;font:inherit;">
11/// <strong>Warning</strong>: The <a href = "https://docs.rs/time/0.3/time/"><code>time</code>
12/// crate</a> must be compiled with <code>--cfg unsound_local_offset</code> in order to use
13/// local timestamps. When this cfg is not enabled, local timestamps cannot be recorded, and
14/// events will be logged without timestamps.
15///
16/// See the <a href="https://docs.rs/time/0.3.4/time/#feature-flags"><code>time</code>
17/// documentation</a> for more details.
18/// </pre></div>
19///
20/// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local
21/// [UTC time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc
22/// [formatter]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
23/// [`time` crate]: https://docs.rs/time/0.3/time/
24#[derive(Clone, Debug)]
25#[cfg_attr(
26 docsrs,
27 doc(cfg(all(unsound_local_offset, feature = "time", feature = "local-time")))
28)]
29#[cfg(feature = "local-time")]
30pub struct LocalTime<F> {
31 format: F,
32}
33
34/// Formats the current [UTC time] using a [formatter] from the [`time` crate].
35///
36/// To format the current [local time] instead, use the [`LocalTime`] type.
37///
38/// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local
39/// [UTC time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc
40/// [formatter]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
41/// [`time` crate]: https://docs.rs/time/0.3/time/
42#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
43#[derive(Clone, Debug)]
44pub struct UtcTime<F> {
45 format: F,
46}
47
48// === impl LocalTime ===
49
50#[cfg(feature = "local-time")]
51impl LocalTime<well_known::Rfc3339> {
52 /// Returns a formatter that formats the current [local time] in the
53 /// [RFC 3339] format (a subset of the [ISO 8601] timestamp format).
54 ///
55 /// # Examples
56 ///
57 /// ```
58 /// use tracing_subscriber::fmt::{self, time};
59 ///
60 /// let collector = tracing_subscriber::fmt()
61 /// .with_timer(time::LocalTime::rfc_3339());
62 /// # drop(collector);
63 /// ```
64 ///
65 /// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local
66 /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339
67 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
68 pub fn rfc_3339() -> Self {
69 Self::new(well_known::Rfc3339)
70 }
71}
72
73#[cfg(feature = "local-time")]
74impl<F: Formattable> LocalTime<F> {
75 /// Returns a formatter that formats the current [local time] using the
76 /// [`time` crate] with the provided provided format. The format may be any
77 /// type that implements the [`Formattable`] trait.
78 ///
79 ///
80 /// <div class="example-wrap" style="display:inline-block">
81 /// <pre class="compile_fail" style="white-space:normal;font:inherit;">
82 /// <strong>Warning</strong>: The <a href = "https://docs.rs/time/0.3/time/">
83 /// <code>time</code> crate</a> must be compiled with <code>--cfg
84 /// unsound_local_offset</code> in order to use local timestamps. When this
85 /// cfg is not enabled, local timestamps cannot be recorded, and
86 /// events will be logged without timestamps.
87 ///
88 /// See the <a href="https://docs.rs/time/0.3.4/time/#feature-flags">
89 /// <code>time</code> documentation</a> for more details.
90 /// </pre></div>
91 ///
92 /// Typically, the format will be a format description string, or one of the
93 /// `time` crate's [well-known formats].
94 ///
95 /// If the format description is statically known, then the
96 /// [`format_description!`] macro should be used. This is identical to the
97 /// [`time::format_description::parse`] method, but runs at compile-time,
98 /// throwing an error if the format description is invalid. If the desired format
99 /// is not known statically (e.g., a user is providing a format string), then the
100 /// [`time::format_description::parse`] method should be used. Note that this
101 /// method is fallible.
102 ///
103 /// See the [`time` book] for details on the format description syntax.
104 ///
105 /// # Examples
106 ///
107 /// Using the [`format_description!`] macro:
108 ///
109 /// ```
110 /// use tracing_subscriber::fmt::{self, time::LocalTime};
111 /// use time::macros::format_description;
112 ///
113 /// let timer = LocalTime::new(format_description!("[hour]:[minute]:[second]"));
114 /// let collector = tracing_subscriber::fmt()
115 /// .with_timer(timer);
116 /// # drop(collector);
117 /// ```
118 ///
119 /// Using [`time::format_description::parse`]:
120 ///
121 /// ```
122 /// use tracing_subscriber::fmt::{self, time::LocalTime};
123 ///
124 /// let time_format = time::format_description::parse("[hour]:[minute]:[second]")
125 /// .expect("format string should be valid!");
126 /// let timer = LocalTime::new(time_format);
127 /// let collector = tracing_subscriber::fmt()
128 /// .with_timer(timer);
129 /// # drop(collector);
130 /// ```
131 ///
132 /// Using the [`format_description!`] macro requires enabling the `time`
133 /// crate's "macros" feature flag.
134 ///
135 /// Using a [well-known format][well-known formats] (this is equivalent to
136 /// [`LocalTime::rfc_3339`]):
137 ///
138 /// ```
139 /// use tracing_subscriber::fmt::{self, time::LocalTime};
140 ///
141 /// let timer = LocalTime::new(time::format_description::well_known::Rfc3339);
142 /// let collector = tracing_subscriber::fmt()
143 /// .with_timer(timer);
144 /// # drop(collector);
145 /// ```
146 ///
147 /// [local time]: https://docs.rs/time/latest/time/struct.OffsetDateTime.html#method.now_local
148 /// [`time` crate]: https://docs.rs/time/0.3/time/
149 /// [`Formattable`]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
150 /// [well-known formats]: https://docs.rs/time/0.3/time/format_description/well_known/index.html
151 /// [`format_description!`]: https://docs.rs/time/0.3/time/macros/macro.format_description.html
152 /// [`time::format_description::parse`]: https://docs.rs/time/0.3/time/format_description/fn.parse.html
153 /// [`time` book]: https://time-rs.github.io/book/api/format-description.html
154 pub fn new(format: F) -> Self {
155 Self { format }
156 }
157}
158
159#[cfg(feature = "local-time")]
160impl<F> FormatTime for LocalTime<F>
161where
162 F: Formattable,
163{
164 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
165 let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?;
166 format_datetime(now, w, &self.format)
167 }
168}
169
170#[cfg(feature = "local-time")]
171impl<F> Default for LocalTime<F>
172where
173 F: Formattable + Default,
174{
175 fn default() -> Self {
176 Self::new(F::default())
177 }
178}
179
180// === impl UtcTime ===
181
182impl UtcTime<well_known::Rfc3339> {
183 /// Returns a formatter that formats the current [UTC time] in the
184 /// [RFC 3339] format, which is a subset of the [ISO 8601] timestamp format.
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// use tracing_subscriber::fmt::{self, time};
190 ///
191 /// let collector = tracing_subscriber::fmt()
192 /// .with_timer(time::UtcTime::rfc_3339());
193 /// # drop(collector);
194 /// ```
195 ///
196 /// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc
197 /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339
198 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
199 pub fn rfc_3339() -> Self {
200 Self::new(well_known::Rfc3339)
201 }
202}
203
204impl<F: Formattable> UtcTime<F> {
205 /// Returns a formatter that formats the current [UTC time] using the
206 /// [`time` crate], with the provided provided format. The format may be any
207 /// type that implements the [`Formattable`] trait.
208 ///
209 /// Typically, the format will be a format description string, or one of the
210 /// `time` crate's [well-known formats].
211 ///
212 /// If the format description is statically known, then the
213 /// [`format_description!`] macro should be used. This is identical to the
214 /// [`time::format_description::parse`] method, but runs at compile-time,
215 /// failing an error if the format description is invalid. If the desired format
216 /// is not known statically (e.g., a user is providing a format string), then the
217 /// [`time::format_description::parse`] method should be used. Note that this
218 /// method is fallible.
219 ///
220 /// See the [`time` book] for details on the format description syntax.
221 ///
222 /// # Examples
223 ///
224 /// Using the [`format_description!`] macro:
225 ///
226 /// ```
227 /// use tracing_subscriber::fmt::{self, time::UtcTime};
228 /// use time::macros::format_description;
229 ///
230 /// let timer = UtcTime::new(format_description!("[hour]:[minute]:[second]"));
231 /// let collector = tracing_subscriber::fmt()
232 /// .with_timer(timer);
233 /// # drop(collector);
234 /// ```
235 ///
236 /// Using the [`format_description!`] macro requires enabling the `time`
237 /// crate's "macros" feature flag.
238 ///
239 /// Using [`time::format_description::parse`]:
240 ///
241 /// ```
242 /// use tracing_subscriber::fmt::{self, time::UtcTime};
243 ///
244 /// let time_format = time::format_description::parse("[hour]:[minute]:[second]")
245 /// .expect("format string should be valid!");
246 /// let timer = UtcTime::new(time_format);
247 /// let collector = tracing_subscriber::fmt()
248 /// .with_timer(timer);
249 /// # drop(collector);
250 /// ```
251 ///
252 /// Using a [well-known format][well-known formats] (this is equivalent to
253 /// [`UtcTime::rfc_3339`]):
254 ///
255 /// ```
256 /// use tracing_subscriber::fmt::{self, time::UtcTime};
257 ///
258 /// let timer = UtcTime::new(time::format_description::well_known::Rfc3339);
259 /// let collector = tracing_subscriber::fmt()
260 /// .with_timer(timer);
261 /// # drop(collector);
262 /// ```
263 ///
264 /// [UTC time]: https://docs.rs/time/latest/time/struct.OffsetDateTime.html#method.now_utc
265 /// [`time` crate]: https://docs.rs/time/0.3/time/
266 /// [`Formattable`]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
267 /// [well-known formats]: https://docs.rs/time/0.3/time/format_description/well_known/index.html
268 /// [`format_description!`]: https://docs.rs/time/0.3/time/macros/macro.format_description.html
269 /// [`time::format_description::parse`]: https://docs.rs/time/0.3/time/format_description/fn.parse.html
270 /// [`time` book]: https://time-rs.github.io/book/api/format-description.html
271 pub fn new(format: F) -> Self {
272 Self { format }
273 }
274}
275
276impl<F> FormatTime for UtcTime<F>
277where
278 F: Formattable,
279{
280 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
281 format_datetime(OffsetDateTime::now_utc(), w, &self.format)
282 }
283}
284
285impl<F> Default for UtcTime<F>
286where
287 F: Formattable + Default,
288{
289 fn default() -> Self {
290 Self::new(F::default())
291 }
292}
293
294fn format_datetime(
295 now: OffsetDateTime,
296 into: &mut Writer<'_>,
297 fmt: &impl Formattable,
298) -> fmt::Result {
299 let mut into = WriteAdaptor::new(into);
300 now.format_into(&mut into, fmt)
301 .map_err(|_| fmt::Error)
302 .map(|_| ())
303}