1use std::{
2 borrow::{Borrow, Cow},
3 cell::RefCell,
4 time::SystemTime,
5};
6
7use crate::{Level, SourceLocation};
8
9#[derive(Clone, Debug)]
24pub struct Record<'a> {
25 logger_name: Option<Cow<'a, str>>,
26 payload: Cow<'a, str>,
27 inner: Cow<'a, RecordInner>,
28}
29
30#[derive(Clone, Debug)]
31struct RecordInner {
32 level: Level,
33 source_location: Option<SourceLocation>,
34 time: SystemTime,
35 tid: u64,
36}
37
38impl<'a> Record<'a> {
39 #[must_use]
40 pub(crate) fn new(
41 level: Level,
42 payload: impl Into<Cow<'a, str>>,
43 srcloc: Option<SourceLocation>,
44 logger_name: Option<&'a str>,
45 ) -> Record<'a> {
46 Record {
47 logger_name: logger_name.map(Cow::Borrowed),
48 payload: payload.into(),
49 inner: Cow::Owned(RecordInner {
50 level,
51 source_location: srcloc,
52 time: SystemTime::now(),
53 tid: get_current_tid(),
54 }),
55 }
56 }
57
58 #[must_use]
60 pub fn to_owned(&self) -> RecordOwned {
61 RecordOwned {
62 logger_name: self.logger_name.clone().map(|n| n.into_owned()),
63 payload: self.payload.to_string(),
64 inner: self.inner.clone().into_owned(),
65 }
66 }
67
68 #[must_use]
70 pub fn logger_name(&self) -> Option<&str> {
71 self.logger_name.as_ref().map(|n| n.as_ref())
72 }
73
74 #[must_use]
76 pub fn level(&self) -> Level {
77 self.inner.level
78 }
79
80 #[must_use]
82 pub fn payload(&self) -> &str {
83 self.payload.borrow()
84 }
85
86 #[must_use]
88 pub fn source_location(&self) -> Option<&SourceLocation> {
89 self.inner.source_location.as_ref()
90 }
91
92 #[must_use]
94 pub fn time(&self) -> SystemTime {
95 self.inner.time
96 }
97
98 #[must_use]
100 pub fn tid(&self) -> u64 {
101 self.inner.tid
102 }
103
104 #[must_use]
107 pub(crate) fn replace_payload(&'a self, new: impl Into<Cow<'a, str>>) -> Self {
108 Self {
109 logger_name: self.logger_name.clone(),
110 payload: new.into(),
111 inner: Cow::Borrowed(&self.inner),
112 }
113 }
114
115 #[cfg(feature = "log")]
116 #[must_use]
117 pub(crate) fn from_log_crate_record(
118 logger: &'a crate::Logger,
119 record: &log::Record,
120 time: SystemTime,
121 ) -> Self {
122 let args = record.args();
123
124 Self {
125 logger_name: logger.name().map(Cow::Borrowed).or_else(|| {
128 let log_target = record.target();
129 if log_target.is_empty() {
130 None
131 } else {
132 Some(Cow::Owned(String::from(log_target)))
133 }
134 }),
135 payload: match args.as_str() {
136 Some(literal_str) => literal_str.into(),
137 None => args.to_string().into(),
138 },
139 inner: Cow::Owned(RecordInner {
140 level: record.level().into(),
141 source_location: SourceLocation::from_log_crate_record(record),
142 time,
143 tid: get_current_tid(),
146 }),
147 }
148 }
149
150 #[cfg(test)]
151 pub(crate) fn set_time(&mut self, new: SystemTime) {
152 self.inner.to_mut().time = new;
153 }
154}
155
156#[derive(Clone, Debug)]
160pub struct RecordOwned {
161 logger_name: Option<String>,
162 payload: String,
163 inner: RecordInner,
164}
165
166impl RecordOwned {
167 #[must_use]
169 pub fn as_ref(&self) -> Record {
170 Record {
171 logger_name: self.logger_name.as_deref().map(Cow::Borrowed),
172 payload: Cow::Borrowed(&self.payload),
173 inner: Cow::Borrowed(&self.inner),
174 }
175 }
176
177 #[must_use]
179 pub fn logger_name(&self) -> Option<&str> {
180 self.logger_name.as_deref()
181 }
182
183 #[must_use]
185 pub fn level(&self) -> Level {
186 self.inner.level
187 }
188
189 #[must_use]
191 pub fn payload(&self) -> &str {
192 self.payload.borrow()
193 }
194
195 #[must_use]
197 pub fn source_location(&self) -> Option<&SourceLocation> {
198 self.inner.source_location.as_ref()
199 }
200
201 #[must_use]
203 pub fn time(&self) -> SystemTime {
204 self.inner.time
205 }
206
207 #[must_use]
209 pub fn tid(&self) -> u64 {
210 self.inner.tid
211 }
212
213 }
215
216fn get_current_tid() -> u64 {
217 #[cfg(any(target_os = "linux", target_os = "android"))]
218 #[must_use]
219 fn get_current_tid_inner() -> u64 {
220 let tid = unsafe { libc::syscall(libc::SYS_gettid) };
225 tid as u64
226 }
227
228 #[cfg(target_os = "freebsd")]
229 #[must_use]
230 fn get_current_tid_inner() -> u64 {
231 let tid = unsafe { libc::pthread_getthreadid_np() };
232 tid as u64
233 }
234
235 #[cfg(target_os = "illumos")]
236 #[must_use]
237 fn get_current_tid_inner() -> u64 {
238 let tid = unsafe { libc::thr_self() };
239 tid as u64
240 }
241
242 #[cfg(any(target_os = "macos", target_os = "ios"))]
243 #[must_use]
244 fn get_current_tid_inner() -> u64 {
245 let mut tid = 0;
246 unsafe { libc::pthread_threadid_np(0, &mut tid) };
247 tid
248 }
249
250 #[cfg(target_os = "windows")]
251 #[must_use]
252 fn get_current_tid_inner() -> u64 {
253 let tid = unsafe { winapi::um::processthreadsapi::GetCurrentThreadId() };
254 tid as u64
255 }
256
257 thread_local! {
258 static TID: RefCell<Option<u64>> = const { RefCell::new(None)} ;
259 }
260
261 TID.with(|tid| *tid.borrow_mut().get_or_insert_with(get_current_tid_inner))
262}