soil_client/tracing/logging/
fast_local_time.rs1use chrono::{Datelike, Timelike};
8use std::{cell::RefCell, fmt::Write, time::SystemTime};
9use tracing_subscriber::fmt::{format, time::FormatTime};
10
11#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
13pub struct FastLocalTime {
14 pub with_fractional: bool,
22}
23
24const TIMESTAMP_MAXIMUM_LENGTH: usize = 32;
26
27#[derive(Default)]
28struct InlineString {
29 buffer: [u8; TIMESTAMP_MAXIMUM_LENGTH],
30 length: usize,
31}
32
33impl Write for InlineString {
34 fn write_str(&mut self, s: &str) -> std::fmt::Result {
35 let new_length = self.length + s.len();
36 assert!(
37 new_length <= TIMESTAMP_MAXIMUM_LENGTH,
38 "buffer overflow when formatting the current timestamp"
39 );
40
41 self.buffer[self.length..new_length].copy_from_slice(s.as_bytes());
42 self.length = new_length;
43 Ok(())
44 }
45}
46
47impl InlineString {
48 fn as_str(&self) -> &str {
49 unsafe { std::str::from_utf8_unchecked(&self.buffer[..self.length]) }
52 }
53}
54
55#[derive(Default)]
56struct CachedTimestamp {
57 buffer: InlineString,
58 last_regenerated_at: u64,
59 last_fractional: u32,
60}
61
62thread_local! {
63 static TIMESTAMP: RefCell<CachedTimestamp> = Default::default();
64}
65
66impl FormatTime for FastLocalTime {
67 fn format_time(&self, w: &mut format::Writer<'_>) -> std::fmt::Result {
68 const TIMESTAMP_PARTIAL_LENGTH: usize = "0000-00-00 00:00:00".len();
69
70 let elapsed = SystemTime::now()
71 .duration_since(SystemTime::UNIX_EPOCH)
72 .expect("system time is never before UNIX epoch; qed");
73 let unix_time = elapsed.as_secs();
74
75 TIMESTAMP.with(|cache| {
76 let mut cache = cache.borrow_mut();
77
78 if cache.last_regenerated_at != unix_time {
80 let ts = chrono::Local::now();
81 let fractional = (ts.nanosecond() % 1_000_000_000) / 1_000_000;
82 cache.last_regenerated_at = unix_time;
83 cache.last_fractional = fractional;
84 cache.buffer.length = 0;
85
86 write!(
87 &mut cache.buffer,
88 "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}",
89 ts.year(),
90 ts.month(),
91 ts.day(),
92 ts.hour(),
93 ts.minute(),
94 ts.second(),
95 fractional
96 )?;
97 } else if self.with_fractional {
98 let fractional = elapsed.subsec_millis();
99
100 if cache.last_fractional != fractional {
102 cache.last_fractional = fractional;
103 cache.buffer.length = TIMESTAMP_PARTIAL_LENGTH + 1;
104 write!(&mut cache.buffer, "{:03}", fractional)?;
105 }
106 }
107
108 let mut slice = cache.buffer.as_str();
109 if !self.with_fractional {
110 slice = &slice[..TIMESTAMP_PARTIAL_LENGTH];
111 }
112
113 w.write_str(slice)
114 })
115 }
116}
117
118impl std::fmt::Display for FastLocalTime {
119 fn fmt(&self, mut w: &mut std::fmt::Formatter) -> std::fmt::Result {
120 self.format_time(&mut format::Writer::new(&mut w))
121 }
122}
123
124#[test]
125fn test_format_fast_local_time() {
126 assert_eq!(
127 chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string().len(),
128 FastLocalTime { with_fractional: false }.to_string().len()
129 );
130 assert_eq!(
131 chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string().len(),
132 FastLocalTime { with_fractional: true }.to_string().len()
133 );
134
135 let now_1 = FastLocalTime { with_fractional: false }.to_string();
138 let expected = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
139 let now_2 = FastLocalTime { with_fractional: false }.to_string();
140
141 assert!(
142 now_1 == expected || now_2 == expected,
143 "'{}' or '{}' should have been equal to '{}'",
144 now_1,
145 now_2,
146 expected
147 );
148}