]> git.proxmox.com Git - rustc.git/blame - vendor/tracing-subscriber/src/fmt/time/time_crate.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / vendor / tracing-subscriber / src / fmt / time / time_crate.rs
CommitLineData
9ffffee4
FG
1use crate::fmt::{format::Writer, time::FormatTime, writer::WriteAdaptor};
2use std::fmt;
3use time::{format_description::well_known, formatting::Formattable, OffsetDateTime, UtcOffset};
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/// Alternatively, [`OffsetTime`] can log with a local offset if it is initialized early.
17///
18/// See the <a href="https://docs.rs/time/0.3.4/time/#feature-flags"><code>time</code>
19/// documentation</a> for more details.
20/// </pre></div>
21///
22/// [local time]: time::OffsetDateTime::now_local
23/// [UTC time]: time::OffsetDateTime::now_utc
24/// [formatter]: time::formatting::Formattable
25/// [`time` crate]: time
26#[derive(Clone, Debug)]
27#[cfg_attr(
28 docsrs,
29 doc(cfg(all(unsound_local_offset, feature = "time", feature = "local-time")))
30)]
31#[cfg(feature = "local-time")]
32pub struct LocalTime<F> {
33 format: F,
34}
35
36/// Formats the current [UTC time] using a [formatter] from the [`time` crate].
37///
38/// To format the current [local time] instead, use the [`LocalTime`] type.
39///
40/// [local time]: time::OffsetDateTime::now_local
41/// [UTC time]: time::OffsetDateTime::now_utc
42/// [formatter]: time::formatting::Formattable
43/// [`time` crate]: time
44#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
45#[derive(Clone, Debug)]
46pub struct UtcTime<F> {
47 format: F,
48}
49
50/// Formats the current time using a fixed offset and a [formatter] from the [`time` crate].
51///
52/// This is typically used as an alternative to [`LocalTime`]. `LocalTime` determines the offset
53/// every time it formats a message, which may be unsound or fail. With `OffsetTime`, the offset is
54/// determined once. This makes it possible to do so while the program is still single-threaded and
55/// handle any errors. However, this also means the offset cannot change while the program is
56/// running (the offset will not change across DST changes).
57///
58/// [formatter]: time::formatting::Formattable
59/// [`time` crate]: time
60#[derive(Clone, Debug)]
61#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
62pub struct OffsetTime<F> {
63 offset: time::UtcOffset,
64 format: F,
65}
66
67// === impl LocalTime ===
68
69#[cfg(feature = "local-time")]
70impl LocalTime<well_known::Rfc3339> {
71 /// Returns a formatter that formats the current [local time] in the
72 /// [RFC 3339] format (a subset of the [ISO 8601] timestamp format).
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// use tracing_subscriber::fmt::{self, time};
78 ///
4b012472 79 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 80 /// .with_timer(time::LocalTime::rfc_3339());
4b012472 81 /// # drop(subscriber);
9ffffee4
FG
82 /// ```
83 ///
84 /// [local time]: time::OffsetDateTime::now_local
85 /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339
86 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
87 pub fn rfc_3339() -> Self {
88 Self::new(well_known::Rfc3339)
89 }
90}
91
92#[cfg(feature = "local-time")]
93impl<F: Formattable> LocalTime<F> {
94 /// Returns a formatter that formats the current [local time] using the
95 /// [`time` crate] with the provided provided format. The format may be any
96 /// type that implements the [`Formattable`] trait.
97 ///
98 ///
99 /// <div class="example-wrap" style="display:inline-block">
100 /// <pre class="compile_fail" style="white-space:normal;font:inherit;">
101 /// <strong>Warning</strong>: The <a href = "https://docs.rs/time/0.3/time/">
102 /// <code>time</code> crate</a> must be compiled with <code>--cfg
103 /// unsound_local_offset</code> in order to use local timestamps. When this
104 /// cfg is not enabled, local timestamps cannot be recorded, and
105 /// events will be logged without timestamps.
106 ///
107 /// See the <a href="https://docs.rs/time/0.3.4/time/#feature-flags">
108 /// <code>time</code> documentation</a> for more details.
109 /// </pre></div>
110 ///
111 /// Typically, the format will be a format description string, or one of the
112 /// `time` crate's [well-known formats].
113 ///
114 /// If the format description is statically known, then the
115 /// [`format_description!`] macro should be used. This is identical to the
116 /// [`time::format_description::parse`] method, but runs at compile-time,
117 /// throwing an error if the format description is invalid. If the desired format
118 /// is not known statically (e.g., a user is providing a format string), then the
119 /// [`time::format_description::parse`] method should be used. Note that this
120 /// method is fallible.
121 ///
122 /// See the [`time` book] for details on the format description syntax.
123 ///
124 /// # Examples
125 ///
126 /// Using the [`format_description!`] macro:
127 ///
128 /// ```
129 /// use tracing_subscriber::fmt::{self, time::LocalTime};
130 /// use time::macros::format_description;
131 ///
132 /// let timer = LocalTime::new(format_description!("[hour]:[minute]:[second]"));
4b012472 133 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 134 /// .with_timer(timer);
4b012472 135 /// # drop(subscriber);
9ffffee4
FG
136 /// ```
137 ///
138 /// Using [`time::format_description::parse`]:
139 ///
140 /// ```
141 /// use tracing_subscriber::fmt::{self, time::LocalTime};
142 ///
143 /// let time_format = time::format_description::parse("[hour]:[minute]:[second]")
144 /// .expect("format string should be valid!");
145 /// let timer = LocalTime::new(time_format);
4b012472 146 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 147 /// .with_timer(timer);
4b012472 148 /// # drop(subscriber);
9ffffee4
FG
149 /// ```
150 ///
151 /// Using the [`format_description!`] macro requires enabling the `time`
152 /// crate's "macros" feature flag.
153 ///
154 /// Using a [well-known format][well-known formats] (this is equivalent to
155 /// [`LocalTime::rfc_3339`]):
156 ///
157 /// ```
158 /// use tracing_subscriber::fmt::{self, time::LocalTime};
159 ///
160 /// let timer = LocalTime::new(time::format_description::well_known::Rfc3339);
4b012472 161 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 162 /// .with_timer(timer);
4b012472 163 /// # drop(subscriber);
9ffffee4
FG
164 /// ```
165 ///
166 /// [local time]: time::OffsetDateTime::now_local()
167 /// [`time` crate]: time
168 /// [`Formattable`]: time::formatting::Formattable
169 /// [well-known formats]: time::format_description::well_known
170 /// [`format_description!`]: time::macros::format_description!
171 /// [`time::format_description::parse`]: time::format_description::parse()
172 /// [`time` book]: https://time-rs.github.io/book/api/format-description.html
173 pub fn new(format: F) -> Self {
174 Self { format }
175 }
176}
177
178#[cfg(feature = "local-time")]
179impl<F> FormatTime for LocalTime<F>
180where
181 F: Formattable,
182{
183 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
184 let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?;
185 format_datetime(now, w, &self.format)
186 }
187}
188
189#[cfg(feature = "local-time")]
190impl<F> Default for LocalTime<F>
191where
192 F: Formattable + Default,
193{
194 fn default() -> Self {
195 Self::new(F::default())
196 }
197}
198
199// === impl UtcTime ===
200
201impl UtcTime<well_known::Rfc3339> {
202 /// Returns a formatter that formats the current [UTC time] in the
203 /// [RFC 3339] format, which is a subset of the [ISO 8601] timestamp format.
204 ///
205 /// # Examples
206 ///
207 /// ```
208 /// use tracing_subscriber::fmt::{self, time};
209 ///
4b012472 210 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 211 /// .with_timer(time::UtcTime::rfc_3339());
4b012472 212 /// # drop(subscriber);
9ffffee4
FG
213 /// ```
214 ///
215 /// [local time]: time::OffsetDateTime::now_utc
216 /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339
217 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
218 pub fn rfc_3339() -> Self {
219 Self::new(well_known::Rfc3339)
220 }
221}
222
223impl<F: Formattable> UtcTime<F> {
224 /// Returns a formatter that formats the current [UTC time] using the
225 /// [`time` crate], with the provided provided format. The format may be any
226 /// type that implements the [`Formattable`] trait.
227 ///
228 /// Typically, the format will be a format description string, or one of the
229 /// `time` crate's [well-known formats].
230 ///
231 /// If the format description is statically known, then the
232 /// [`format_description!`] macro should be used. This is identical to the
233 /// [`time::format_description::parse`] method, but runs at compile-time,
234 /// failing an error if the format description is invalid. If the desired format
235 /// is not known statically (e.g., a user is providing a format string), then the
236 /// [`time::format_description::parse`] method should be used. Note that this
237 /// method is fallible.
238 ///
239 /// See the [`time` book] for details on the format description syntax.
240 ///
241 /// # Examples
242 ///
243 /// Using the [`format_description!`] macro:
244 ///
245 /// ```
246 /// use tracing_subscriber::fmt::{self, time::UtcTime};
247 /// use time::macros::format_description;
248 ///
249 /// let timer = UtcTime::new(format_description!("[hour]:[minute]:[second]"));
4b012472 250 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 251 /// .with_timer(timer);
4b012472 252 /// # drop(subscriber);
9ffffee4
FG
253 /// ```
254 ///
255 /// Using the [`format_description!`] macro requires enabling the `time`
256 /// crate's "macros" feature flag.
257 ///
258 /// Using [`time::format_description::parse`]:
259 ///
260 /// ```
261 /// use tracing_subscriber::fmt::{self, time::UtcTime};
262 ///
263 /// let time_format = time::format_description::parse("[hour]:[minute]:[second]")
264 /// .expect("format string should be valid!");
265 /// let timer = UtcTime::new(time_format);
4b012472 266 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 267 /// .with_timer(timer);
4b012472 268 /// # drop(subscriber);
9ffffee4
FG
269 /// ```
270 ///
271 /// Using a [well-known format][well-known formats] (this is equivalent to
272 /// [`UtcTime::rfc_3339`]):
273 ///
274 /// ```
275 /// use tracing_subscriber::fmt::{self, time::UtcTime};
276 ///
277 /// let timer = UtcTime::new(time::format_description::well_known::Rfc3339);
4b012472 278 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 279 /// .with_timer(timer);
4b012472 280 /// # drop(subscriber);
9ffffee4
FG
281 /// ```
282 ///
283 /// [UTC time]: time::OffsetDateTime::now_utc()
284 /// [`time` crate]: time
285 /// [`Formattable`]: time::formatting::Formattable
286 /// [well-known formats]: time::format_description::well_known
287 /// [`format_description!`]: time::macros::format_description!
288 /// [`time::format_description::parse`]: time::format_description::parse
289 /// [`time` book]: https://time-rs.github.io/book/api/format-description.html
290 pub fn new(format: F) -> Self {
291 Self { format }
292 }
293}
294
295impl<F> FormatTime for UtcTime<F>
296where
297 F: Formattable,
298{
299 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
300 format_datetime(OffsetDateTime::now_utc(), w, &self.format)
301 }
302}
303
304impl<F> Default for UtcTime<F>
305where
306 F: Formattable + Default,
307{
308 fn default() -> Self {
309 Self::new(F::default())
310 }
311}
312
313// === impl OffsetTime ===
314
315#[cfg(feature = "local-time")]
316impl OffsetTime<well_known::Rfc3339> {
317 /// Returns a formatter that formats the current time using the [local time offset] in the [RFC
318 /// 3339] format (a subset of the [ISO 8601] timestamp format).
319 ///
320 /// Returns an error if the local time offset cannot be determined. This typically occurs in
321 /// multithreaded programs. To avoid this problem, initialize `OffsetTime` before forking
322 /// threads. When using Tokio, this means initializing `OffsetTime` before the Tokio runtime.
323 ///
324 /// # Examples
325 ///
326 /// ```
327 /// use tracing_subscriber::fmt::{self, time};
328 ///
4b012472 329 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 330 /// .with_timer(time::OffsetTime::local_rfc_3339().expect("could not get local offset!"));
4b012472 331 /// # drop(subscriber);
9ffffee4
FG
332 /// ```
333 ///
334 /// Using `OffsetTime` with Tokio:
335 ///
336 /// ```
337 /// use tracing_subscriber::fmt::time::OffsetTime;
338 ///
339 /// #[tokio::main]
340 /// async fn run() {
341 /// tracing::info!("runtime initialized");
342 ///
343 /// // At this point the Tokio runtime is initialized, and we can use both Tokio and Tracing
344 /// // normally.
345 /// }
346 ///
347 /// fn main() {
348 /// // Because we need to get the local offset before Tokio spawns any threads, our `main`
349 /// // function cannot use `tokio::main`.
350 /// tracing_subscriber::fmt()
351 /// .with_timer(OffsetTime::local_rfc_3339().expect("could not get local time offset"))
352 /// .init();
353 ///
354 /// // Even though `run` is written as an `async fn`, because we used `tokio::main` on it
355 /// // we can call it as a synchronous function.
356 /// run();
357 /// }
358 /// ```
359 ///
360 /// [local time offset]: time::UtcOffset::current_local_offset
361 /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339
362 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
363 pub fn local_rfc_3339() -> Result<Self, time::error::IndeterminateOffset> {
364 Ok(Self::new(
365 UtcOffset::current_local_offset()?,
366 well_known::Rfc3339,
367 ))
368 }
369}
370
371impl<F: time::formatting::Formattable> OffsetTime<F> {
372 /// Returns a formatter that formats the current time using the [`time` crate] with the provided
373 /// provided format and [timezone offset]. The format may be any type that implements the
374 /// [`Formattable`] trait.
375 ///
376 ///
377 /// Typically, the offset will be the [local offset], and format will be a format description
378 /// string, or one of the `time` crate's [well-known formats].
379 ///
380 /// If the format description is statically known, then the
381 /// [`format_description!`] macro should be used. This is identical to the
382 /// [`time::format_description::parse`] method, but runs at compile-time,
383 /// throwing an error if the format description is invalid. If the desired format
384 /// is not known statically (e.g., a user is providing a format string), then the
385 /// [`time::format_description::parse`] method should be used. Note that this
386 /// method is fallible.
387 ///
388 /// See the [`time` book] for details on the format description syntax.
389 ///
390 /// # Examples
391 ///
392 /// Using the [`format_description!`] macro:
393 ///
394 /// ```
395 /// use tracing_subscriber::fmt::{self, time::OffsetTime};
396 /// use time::macros::format_description;
397 /// use time::UtcOffset;
398 ///
399 /// let offset = UtcOffset::current_local_offset().expect("should get local offset!");
400 /// let timer = OffsetTime::new(offset, format_description!("[hour]:[minute]:[second]"));
4b012472 401 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 402 /// .with_timer(timer);
4b012472 403 /// # drop(subscriber);
9ffffee4
FG
404 /// ```
405 ///
406 /// Using [`time::format_description::parse`]:
407 ///
408 /// ```
409 /// use tracing_subscriber::fmt::{self, time::OffsetTime};
410 /// use time::UtcOffset;
411 ///
412 /// let offset = UtcOffset::current_local_offset().expect("should get local offset!");
413 /// let time_format = time::format_description::parse("[hour]:[minute]:[second]")
414 /// .expect("format string should be valid!");
415 /// let timer = OffsetTime::new(offset, time_format);
4b012472 416 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 417 /// .with_timer(timer);
4b012472 418 /// # drop(subscriber);
9ffffee4
FG
419 /// ```
420 ///
421 /// Using the [`format_description!`] macro requires enabling the `time`
422 /// crate's "macros" feature flag.
423 ///
424 /// Using a [well-known format][well-known formats] (this is equivalent to
425 /// [`OffsetTime::local_rfc_3339`]):
426 ///
427 /// ```
428 /// use tracing_subscriber::fmt::{self, time::OffsetTime};
429 /// use time::UtcOffset;
430 ///
431 /// let offset = UtcOffset::current_local_offset().expect("should get local offset!");
432 /// let timer = OffsetTime::new(offset, time::format_description::well_known::Rfc3339);
4b012472 433 /// let subscriber = tracing_subscriber::fmt()
9ffffee4 434 /// .with_timer(timer);
4b012472 435 /// # drop(subscriber);
9ffffee4
FG
436 /// ```
437 ///
438 /// [`time` crate]: time
439 /// [timezone offset]: time::UtcOffset
440 /// [`Formattable`]: time::formatting::Formattable
441 /// [local offset]: time::UtcOffset::current_local_offset()
442 /// [well-known formats]: time::format_description::well_known
443 /// [`format_description!`]: time::macros::format_description
444 /// [`time::format_description::parse`]: time::format_description::parse
445 /// [`time` book]: https://time-rs.github.io/book/api/format-description.html
446 pub fn new(offset: time::UtcOffset, format: F) -> Self {
447 Self { offset, format }
448 }
449}
450
451impl<F> FormatTime for OffsetTime<F>
452where
453 F: time::formatting::Formattable,
454{
455 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
456 let now = OffsetDateTime::now_utc().to_offset(self.offset);
457 format_datetime(now, w, &self.format)
458 }
459}
460
461fn format_datetime(
462 now: OffsetDateTime,
463 into: &mut Writer<'_>,
464 fmt: &impl Formattable,
465) -> fmt::Result {
466 let mut into = WriteAdaptor::new(into);
467 now.format_into(&mut into, fmt)
468 .map_err(|_| fmt::Error)
469 .map(|_| ())
470}