1use crate::{
2 trace::{SpanContext, SpanId, TraceContextExt, TraceFlags, TraceId},
3 Array, Key, OrderMap, StringValue, Value,
4};
5use std::{borrow::Cow, time::SystemTime};
6
7#[derive(Debug, Clone, Default)]
8#[non_exhaustive]
9pub struct LogRecord {
12 pub timestamp: Option<SystemTime>,
14
15 pub observed_timestamp: Option<SystemTime>,
17
18 pub trace_context: Option<TraceContext>,
20
21 pub severity_text: Option<Cow<'static, str>>,
23 pub severity_number: Option<Severity>,
25
26 pub body: Option<AnyValue>,
28
29 pub attributes: Option<Vec<(Key, AnyValue)>>,
31}
32
33impl LogRecord {
34 pub fn builder() -> LogRecordBuilder {
36 LogRecordBuilder::new()
37 }
38}
39
40#[derive(Debug, Clone)]
43#[non_exhaustive]
44pub struct TraceContext {
45 pub trace_id: TraceId,
47 pub span_id: SpanId,
49 pub trace_flags: Option<TraceFlags>,
51}
52
53impl From<&SpanContext> for TraceContext {
54 fn from(span_context: &SpanContext) -> Self {
55 TraceContext {
56 trace_id: span_context.trace_id(),
57 span_id: span_context.span_id(),
58 trace_flags: Some(span_context.trace_flags()),
59 }
60 }
61}
62
63#[derive(Debug, Clone)]
65pub enum AnyValue {
66 Int(i64),
68 Double(f64),
70 String(StringValue),
72 Boolean(bool),
74 Bytes(Vec<u8>),
76 ListAny(Vec<AnyValue>),
78 Map(OrderMap<Key, AnyValue>),
80}
81
82macro_rules! impl_trivial_from {
83 ($t:ty, $variant:path) => {
84 impl From<$t> for AnyValue {
85 fn from(val: $t) -> AnyValue {
86 $variant(val.into())
87 }
88 }
89 };
90}
91
92impl_trivial_from!(i8, AnyValue::Int);
93impl_trivial_from!(i16, AnyValue::Int);
94impl_trivial_from!(i32, AnyValue::Int);
95impl_trivial_from!(i64, AnyValue::Int);
96
97impl_trivial_from!(u8, AnyValue::Int);
98impl_trivial_from!(u16, AnyValue::Int);
99impl_trivial_from!(u32, AnyValue::Int);
100
101impl_trivial_from!(f64, AnyValue::Double);
102impl_trivial_from!(f32, AnyValue::Double);
103
104impl_trivial_from!(String, AnyValue::String);
105impl_trivial_from!(Cow<'static, str>, AnyValue::String);
106impl_trivial_from!(&'static str, AnyValue::String);
107impl_trivial_from!(StringValue, AnyValue::String);
108
109impl_trivial_from!(bool, AnyValue::Boolean);
110
111impl<T: Into<AnyValue>> FromIterator<T> for AnyValue {
112 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
114 AnyValue::ListAny(iter.into_iter().map(Into::into).collect())
115 }
116}
117
118impl<K: Into<Key>, V: Into<AnyValue>> FromIterator<(K, V)> for AnyValue {
119 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
122 AnyValue::Map(OrderMap::from_iter(
123 iter.into_iter().map(|(k, v)| (k.into(), v.into())),
124 ))
125 }
126}
127
128impl From<Value> for AnyValue {
129 fn from(value: Value) -> Self {
130 match value {
131 Value::Bool(b) => b.into(),
132 Value::I64(i) => i.into(),
133 Value::F64(f) => f.into(),
134 Value::String(s) => s.into(),
135 Value::Array(a) => match a {
136 Array::Bool(b) => AnyValue::from_iter(b),
137 Array::F64(f) => AnyValue::from_iter(f),
138 Array::I64(i) => AnyValue::from_iter(i),
139 Array::String(s) => AnyValue::from_iter(s),
140 },
141 }
142 }
143}
144
145#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
147pub enum Severity {
148 Trace = 1,
150 Trace2 = 2,
152 Trace3 = 3,
154 Trace4 = 4,
156 Debug = 5,
158 Debug2 = 6,
160 Debug3 = 7,
162 Debug4 = 8,
164 Info = 9,
166 Info2 = 10,
168 Info3 = 11,
170 Info4 = 12,
172 Warn = 13,
174 Warn2 = 14,
176 Warn3 = 15,
178 Warn4 = 16,
180 Error = 17,
182 Error2 = 18,
184 Error3 = 19,
186 Error4 = 20,
188 Fatal = 21,
190 Fatal2 = 22,
192 Fatal3 = 23,
194 Fatal4 = 24,
196}
197
198impl Severity {
199 pub const fn name(&self) -> &'static str {
202 match &self {
203 Severity::Trace => "TRACE",
204 Severity::Trace2 => "TRACE2",
205 Severity::Trace3 => "TRACE3",
206 Severity::Trace4 => "TRACE4",
207
208 Severity::Debug => "DEBUG",
209 Severity::Debug2 => "DEBUG2",
210 Severity::Debug3 => "DEBUG3",
211 Severity::Debug4 => "DEBUG4",
212
213 Severity::Info => "INFO",
214 Severity::Info2 => "INFO2",
215 Severity::Info3 => "INFO3",
216 Severity::Info4 => "INFO4",
217
218 Severity::Warn => "WARN",
219 Severity::Warn2 => "WARN2",
220 Severity::Warn3 => "WARN3",
221 Severity::Warn4 => "WARN4",
222
223 Severity::Error => "ERROR",
224 Severity::Error2 => "ERROR2",
225 Severity::Error3 => "ERROR3",
226 Severity::Error4 => "ERROR4",
227
228 Severity::Fatal => "FATAL",
229 Severity::Fatal2 => "FATAL2",
230 Severity::Fatal3 => "FATAL3",
231 Severity::Fatal4 => "FATAL4",
232 }
233 }
234}
235
236#[derive(Debug, Clone)]
238pub struct LogRecordBuilder {
239 record: LogRecord,
240}
241
242impl LogRecordBuilder {
243 pub fn new() -> Self {
245 Self {
246 record: Default::default(),
247 }
248 }
249
250 pub fn with_timestamp(self, timestamp: SystemTime) -> Self {
252 Self {
253 record: LogRecord {
254 timestamp: Some(timestamp),
255 ..self.record
256 },
257 }
258 }
259
260 pub fn with_observed_timestamp(self, timestamp: SystemTime) -> Self {
262 Self {
263 record: LogRecord {
264 observed_timestamp: Some(timestamp),
265 ..self.record
266 },
267 }
268 }
269
270 pub fn with_span_context(self, span_context: &SpanContext) -> Self {
272 Self {
273 record: LogRecord {
274 trace_context: Some(TraceContext {
275 span_id: span_context.span_id(),
276 trace_id: span_context.trace_id(),
277 trace_flags: Some(span_context.trace_flags()),
278 }),
279 ..self.record
280 },
281 }
282 }
283
284 pub fn with_context<T>(self, context: &T) -> Self
286 where
287 T: TraceContextExt,
288 {
289 if context.has_active_span() {
290 self.with_span_context(context.span().span_context())
291 } else {
292 self
293 }
294 }
295
296 pub fn with_severity_text<T>(self, severity: T) -> Self
298 where
299 T: Into<Cow<'static, str>>,
300 {
301 Self {
302 record: LogRecord {
303 severity_text: Some(severity.into()),
304 ..self.record
305 },
306 }
307 }
308
309 pub fn with_severity_number(self, severity: Severity) -> Self {
311 Self {
312 record: LogRecord {
313 severity_number: Some(severity),
314 ..self.record
315 },
316 }
317 }
318
319 pub fn with_body(self, body: AnyValue) -> Self {
321 Self {
322 record: LogRecord {
323 body: Some(body),
324 ..self.record
325 },
326 }
327 }
328
329 pub fn with_attributes(self, attributes: Vec<(Key, AnyValue)>) -> Self {
332 Self {
333 record: LogRecord {
334 attributes: Some(attributes),
335 ..self.record
336 },
337 }
338 }
339
340 pub fn with_attribute<K, V>(mut self, key: K, value: V) -> Self
343 where
344 K: Into<Key>,
345 V: Into<AnyValue>,
346 {
347 if let Some(ref mut vec) = self.record.attributes {
348 vec.push((key.into(), value.into()));
349 } else {
350 let vec = vec![(key.into(), value.into())];
351 self.record.attributes = Some(vec);
352 }
353
354 self
355 }
356
357 pub fn build(self) -> LogRecord {
359 self.record
360 }
361}
362
363impl Default for LogRecordBuilder {
364 fn default() -> Self {
365 Self::new()
366 }
367}