1#[cfg(feature = "stacktrace")]
3use backtrace::Backtrace;
4use std::borrow::Cow;
5use std::time::SystemTime;
6
7#[derive(Debug)]
9pub struct LogBuilder {
10 fields: Vec<LogField>,
11 time: Option<SystemTime>,
12}
13impl LogBuilder {
14 pub fn field<T: Into<LogField>>(&mut self, field: T) -> &mut Self {
16 self.fields.push(field.into());
17 self
18 }
19
20 pub fn time(&mut self, time: SystemTime) -> &mut Self {
22 self.time = Some(time);
23 self
24 }
25
26 pub fn std(&mut self) -> StdLogFieldsBuilder<'_> {
28 StdLogFieldsBuilder(self)
29 }
30
31 pub fn error(&mut self) -> StdErrorLogFieldsBuilder<'_> {
33 self.field(LogField::new("event", "error"));
34 StdErrorLogFieldsBuilder(self)
35 }
36
37 pub(crate) fn new() -> Self {
38 LogBuilder {
39 fields: Vec::new(),
40 time: None,
41 }
42 }
43
44 pub(crate) fn finish(mut self) -> Option<Log> {
45 if self.fields.is_empty() {
46 None
47 } else {
48 self.fields.reverse();
49 self.fields.sort_by(|a, b| a.name.cmp(&b.name));
50 self.fields.dedup_by(|a, b| a.name == b.name);
51 Some(Log {
52 fields: self.fields,
53 time: self.time.unwrap_or_else(SystemTime::now),
54 })
55 }
56 }
57}
58
59#[derive(Debug, Clone)]
61pub struct Log {
62 fields: Vec<LogField>,
63 time: SystemTime,
64}
65impl Log {
66 pub fn fields(&self) -> &[LogField] {
68 &self.fields
69 }
70
71 pub fn time(&self) -> SystemTime {
73 self.time
74 }
75}
76
77#[derive(Debug, Clone)]
79pub struct LogField {
80 name: Cow<'static, str>,
81 value: Cow<'static, str>,
82}
83impl LogField {
84 pub fn new<N, V>(name: N, value: V) -> Self
86 where
87 N: Into<Cow<'static, str>>,
88 V: Into<Cow<'static, str>>,
89 {
90 LogField {
91 name: name.into(),
92 value: value.into(),
93 }
94 }
95
96 pub fn name(&self) -> &str {
98 self.name.as_ref()
99 }
100
101 pub fn value(&self) -> &str {
103 self.value.as_ref()
104 }
105}
106impl<N, V> From<(N, V)> for LogField
107where
108 N: Into<Cow<'static, str>>,
109 V: Into<Cow<'static, str>>,
110{
111 fn from((n, v): (N, V)) -> Self {
112 LogField::new(n, v)
113 }
114}
115
116#[derive(Debug)]
120pub struct StdLogFieldsBuilder<'a>(&'a mut LogBuilder);
121impl StdLogFieldsBuilder<'_> {
122 pub fn event<T>(&mut self, event: T) -> &mut Self
133 where
134 T: Into<Cow<'static, str>>,
135 {
136 self.0.field(LogField::new("event", event));
137 self
138 }
139
140 pub fn message<T>(&mut self, message: T) -> &mut Self
146 where
147 T: Into<Cow<'static, str>>,
148 {
149 self.0.field(LogField::new("message", message));
150 self
151 }
152
153 #[cfg(feature = "stacktrace")]
154 pub fn stack(&mut self) -> &mut Self {
156 self.0
157 .field(LogField::new("stack", format!("{:?}", Backtrace::new())));
158 self
159 }
160}
161
162#[derive(Debug)]
168pub struct StdErrorLogFieldsBuilder<'a>(&'a mut LogBuilder);
169impl StdErrorLogFieldsBuilder<'_> {
170 pub fn kind<T>(&mut self, kind: T) -> &mut Self
176 where
177 T: Into<Cow<'static, str>>,
178 {
179 self.0.field(LogField::new("error.kind", kind));
180 self
181 }
182
183 pub fn message<T>(&mut self, message: T) -> &mut Self
189 where
190 T: Into<Cow<'static, str>>,
191 {
192 self.0.field(LogField::new("message", message));
193 self
194 }
195
196 #[cfg(feature = "stacktrace")]
197 pub fn stack(&mut self) -> &mut Self {
199 self.0
200 .field(LogField::new("stack", format!("{:?}", Backtrace::new())));
201 self
202 }
203}