cf_rustracing/
log.rs

1//! Span log.
2#[cfg(feature = "stacktrace")]
3use backtrace::Backtrace;
4use std::borrow::Cow;
5use std::time::SystemTime;
6
7/// Span log builder.
8#[derive(Debug)]
9pub struct LogBuilder {
10    fields: Vec<LogField>,
11    time: Option<SystemTime>,
12}
13impl LogBuilder {
14    /// Adds the field.
15    pub fn field<T: Into<LogField>>(&mut self, field: T) -> &mut Self {
16        self.fields.push(field.into());
17        self
18    }
19
20    /// Sets the value of timestamp to `time`.
21    pub fn time(&mut self, time: SystemTime) -> &mut Self {
22        self.time = Some(time);
23        self
24    }
25
26    /// Returns a specialized builder for the standard log fields.
27    pub fn std(&mut self) -> StdLogFieldsBuilder<'_> {
28        StdLogFieldsBuilder(self)
29    }
30
31    /// Returns a specialized builder for the standard error log fields.
32    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/// Span log.
60#[derive(Debug, Clone)]
61pub struct Log {
62    fields: Vec<LogField>,
63    time: SystemTime,
64}
65impl Log {
66    /// Returns the fields of this log.
67    pub fn fields(&self) -> &[LogField] {
68        &self.fields
69    }
70
71    /// Returns the timestamp of this log.
72    pub fn time(&self) -> SystemTime {
73        self.time
74    }
75}
76
77/// Span log field.
78#[derive(Debug, Clone)]
79pub struct LogField {
80    name: Cow<'static, str>,
81    value: Cow<'static, str>,
82}
83impl LogField {
84    /// Makes a new `LogField` instance.
85    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    /// Returns the name of this field.
97    pub fn name(&self) -> &str {
98        self.name.as_ref()
99    }
100
101    /// Returns the value of this field.
102    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/// A specialized span log builder for [the standard log fields].
117///
118/// [the standard log fields]: https://github.com/opentracing/specification/blob/master/semantic_conventions.md#log-fields-table
119#[derive(Debug)]
120pub struct StdLogFieldsBuilder<'a>(&'a mut LogBuilder);
121impl StdLogFieldsBuilder<'_> {
122    /// Adds the field `LogField::new("event", event)`.
123    ///
124    /// `event` is a stable identifier for some notable moment in the lifetime of a Span.
125    /// For instance, a mutex lock acquisition or release or the sorts of lifetime events
126    /// in a browser page load described in the [Performance.timing] specification.
127    ///
128    /// E.g., from Zipkin, `"cs"`, `"sr"`, `"ss"`, or `"cr"`.
129    /// Or, more generally, `"initialized"` or `"timed out"`.
130    ///
131    /// [Performance.timing]: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming
132    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    /// Adds the field `LogField::new("message", message)`.
141    ///
142    /// `message` is a concise, human-readable, one-line message explaining the event.
143    ///
144    /// E.g., `"Could not connect to backend"`, `"Cache invalidation succeeded"`
145    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    /// Adds the field `LogField::new("stack", {stack trace})`.
155    pub fn stack(&mut self) -> &mut Self {
156        self.0
157            .field(LogField::new("stack", format!("{:?}", Backtrace::new())));
158        self
159    }
160}
161
162/// A specialized span log builder for [the standard error log fields].
163///
164/// This builder automatically inserts the field `LogField::new("event", "error")`.
165///
166/// [the standard error log fields]: https://github.com/opentracing/specification/blob/master/semantic_conventions.md#log-fields-table
167#[derive(Debug)]
168pub struct StdErrorLogFieldsBuilder<'a>(&'a mut LogBuilder);
169impl StdErrorLogFieldsBuilder<'_> {
170    /// Adds the field `LogField::new("error.kind", kind)`.
171    ///
172    /// `kind` is the type or "kind" of an error.
173    ///
174    /// E.g., `"Exception"`, `"OSError"`
175    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    /// Adds the field `LogField::new("message", message)`.
184    ///
185    /// `message` is a concise, human-readable, one-line message explaining the event.
186    ///
187    /// E.g., `"Could not connect to backend"`, `"Cache invalidation succeeded"`
188    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    /// Adds the field `LogField::new("stack", {stack trace})`.
198    pub fn stack(&mut self) -> &mut Self {
199        self.0
200            .field(LogField::new("stack", format!("{:?}", Backtrace::new())));
201        self
202    }
203}