1use std::{
2 borrow::{Borrow, Cow},
3 cell::RefCell,
4 time::SystemTime,
5};
6
7use crate::{kv, Level, SourceLocation};
8
9#[derive(Clone, Debug)]
24pub struct Record<'a> {
25 logger_name: Option<&'a str>,
26 payload: Cow<'a, str>,
27 kvs: Cow<'a, [kv::Pair<'a>]>,
28 inner: Cow<'a, RecordInner>,
29}
30
31#[derive(Clone, Debug)]
32struct RecordInner {
33 level: Level,
34 source_location: Option<SourceLocation>,
35 time: SystemTime,
36 tid: u64,
37}
38
39impl<'a> Record<'a> {
40 #[must_use]
41 pub(crate) fn new(
42 level: Level,
43 payload: impl Into<Cow<'a, str>>,
44 srcloc: Option<SourceLocation>,
45 logger_name: Option<&'a str>,
46 kvs: &'a [(kv::Key<'a>, kv::Value<'a>)],
47 ) -> Record<'a> {
48 Record {
49 logger_name,
50 payload: payload.into(),
51 kvs: Cow::Borrowed(kvs),
52 inner: Cow::Owned(RecordInner {
53 level,
54 source_location: srcloc,
55 time: SystemTime::now(),
56 tid: get_current_tid(),
57 }),
58 }
59 }
60
61 #[must_use]
63 pub fn to_owned(&self) -> RecordOwned {
64 RecordOwned {
65 logger_name: self.logger_name.map(|n| n.to_owned()),
66 payload: self.payload.to_string(),
67 kvs: self
68 .kvs
69 .iter()
70 .map(|(k, v)| (k.to_owned(), v.to_owned()))
71 .collect(),
72 inner: self.inner.clone().into_owned(),
73 }
74 }
75
76 #[must_use]
78 pub fn logger_name(&self) -> Option<&str> {
79 self.logger_name
80 }
81
82 #[must_use]
84 pub fn level(&self) -> Level {
85 self.inner.level
86 }
87
88 #[must_use]
90 pub fn payload(&self) -> &str {
91 self.payload.borrow()
92 }
93
94 #[must_use]
96 pub fn source_location(&self) -> Option<&SourceLocation> {
97 self.inner.source_location.as_ref()
98 }
99
100 #[must_use]
102 pub fn time(&self) -> SystemTime {
103 self.inner.time
104 }
105
106 #[must_use]
108 pub fn tid(&self) -> u64 {
109 self.inner.tid
110 }
111
112 #[must_use]
114 pub fn key_values(&self) -> kv::KeyValues<'_> {
115 kv::KeyValues::with_borrowed(&self.kvs)
116 }
117
118 #[must_use]
121 pub(crate) fn replace_payload(&'a self, new: impl Into<Cow<'a, str>>) -> Self {
122 Self {
123 logger_name: self.logger_name,
124 payload: new.into(),
125 kvs: self.kvs.clone(),
126 inner: Cow::Borrowed(&self.inner),
127 }
128 }
129
130 #[cfg(test)]
131 pub(crate) fn set_time(&mut self, new: SystemTime) {
132 self.inner.to_mut().time = new;
133 }
134}
135
136#[derive(Clone, Debug)]
140pub struct RecordOwned {
141 logger_name: Option<String>,
142 payload: String,
143 kvs: Vec<(kv::KeyOwned, kv::ValueOwned)>,
144 inner: RecordInner,
145}
146
147impl RecordOwned {
148 #[must_use]
150 pub fn as_ref(&self) -> Record<'_> {
151 Record {
152 logger_name: self.logger_name.as_deref(),
153 payload: Cow::Borrowed(&self.payload),
154 kvs: Cow::Owned(
155 self.kvs
156 .iter()
157 .map(|(k, v)| (k.as_ref(), v.by_ref()))
158 .collect::<Vec<_>>(),
159 ),
160 inner: Cow::Borrowed(&self.inner),
161 }
162 }
163
164 #[must_use]
166 pub fn logger_name(&self) -> Option<&str> {
167 self.logger_name.as_deref()
168 }
169
170 #[must_use]
172 pub fn level(&self) -> Level {
173 self.inner.level
174 }
175
176 #[must_use]
178 pub fn payload(&self) -> &str {
179 self.payload.borrow()
180 }
181
182 #[must_use]
184 pub fn source_location(&self) -> Option<&SourceLocation> {
185 self.inner.source_location.as_ref()
186 }
187
188 #[must_use]
190 pub fn time(&self) -> SystemTime {
191 self.inner.time
192 }
193
194 #[must_use]
196 pub fn tid(&self) -> u64 {
197 self.inner.tid
198 }
199
200 #[must_use]
202 pub fn key_values(&self) -> kv::KeyValues<'_> {
203 kv::KeyValues::with_owned(&self.kvs)
204 }
205
206 }
208
209#[cfg(feature = "log")]
210#[derive(Clone, Debug)]
211pub(crate) struct LogCrateRecord<'a> {
212 logger_name: Option<&'a str>,
213 payload: Cow<'a, str>,
214 kvs: Vec<(log::kv::Key<'a>, kv::ValueOwned)>,
215 inner: Cow<'a, RecordInner>,
216}
217
218#[cfg(feature = "log")]
219impl<'a> LogCrateRecord<'a> {
220 #[must_use]
221 pub(crate) fn new(
222 logger: &'a crate::Logger,
223 record: &'a log::Record,
224 time: SystemTime,
225 ) -> Self {
226 let args = record.args();
227
228 Self {
229 logger_name: logger.name().or_else(|| Some(record.target())),
232 kvs: {
233 let kvs = record.key_values();
234 let mut cvt = kv::LogCrateConverter::new(kvs.count());
235 assert!(kvs.visit(&mut cvt).is_ok());
236 cvt.finalize()
237 },
238 payload: match args.as_str() {
239 Some(literal_str) => literal_str.into(),
240 None => args.to_string().into(),
241 },
242 inner: Cow::Owned(RecordInner {
243 level: record.level().into(),
244 source_location: SourceLocation::from_log_crate_record(record),
245 time,
246 tid: get_current_tid(),
249 }),
250 }
251 }
252
253 #[must_use]
254 pub(crate) fn as_record(&self) -> Record<'_> {
255 Record {
256 logger_name: self.logger_name,
257 payload: self.payload.clone(),
258 kvs: self
259 .kvs
260 .iter()
261 .map(|(k, v)| (kv::Key::from_str(k.as_str()), v.by_ref()))
262 .collect(),
263 inner: self.inner.clone(),
264 }
265 }
266}
267
268fn get_current_tid() -> u64 {
269 #[cfg(any(target_os = "linux", target_os = "android"))]
270 #[must_use]
271 fn get_current_tid_inner() -> u64 {
272 let tid = unsafe { libc::syscall(libc::SYS_gettid) };
277 tid as u64
278 }
279
280 #[cfg(target_os = "freebsd")]
281 #[must_use]
282 fn get_current_tid_inner() -> u64 {
283 let tid = unsafe { libc::pthread_getthreadid_np() };
284 tid as u64
285 }
286
287 #[cfg(target_os = "illumos")]
288 #[must_use]
289 fn get_current_tid_inner() -> u64 {
290 let tid = unsafe { libc::thr_self() };
291 tid as u64
292 }
293
294 #[cfg(any(target_os = "macos", target_os = "ios"))]
295 #[must_use]
296 fn get_current_tid_inner() -> u64 {
297 let mut tid = 0;
298 unsafe { libc::pthread_threadid_np(0, &mut tid) };
299 tid
300 }
301
302 #[cfg(target_os = "windows")]
303 #[must_use]
304 fn get_current_tid_inner() -> u64 {
305 let tid = unsafe { winapi::um::processthreadsapi::GetCurrentThreadId() };
306 tid as u64
307 }
308
309 thread_local! {
310 static TID: RefCell<Option<u64>> = const { RefCell::new(None)} ;
311 }
312
313 TID.with(|tid| *tid.borrow_mut().get_or_insert_with(get_current_tid_inner))
314}