opentelemetry_sdk/logs/
record.rs

1use opentelemetry::{
2    logs::{AnyValue, Severity},
3    trace::{SpanContext, SpanId, TraceFlags, TraceId},
4    Key,
5};
6use std::{borrow::Cow, time::SystemTime};
7
8#[derive(Debug, Default, Clone)]
9#[non_exhaustive]
10/// LogRecord represents all data carried by a log record, and
11/// is provided to `LogExporter`s as input.
12pub struct LogRecord {
13    /// Event name. Optional as not all the logging API support it.
14    pub event_name: Option<Cow<'static, str>>,
15
16    /// Target of the log record
17    pub target: Option<Cow<'static, str>>,
18
19    /// Record timestamp
20    pub timestamp: Option<SystemTime>,
21
22    /// Timestamp for when the record was observed by OpenTelemetry
23    pub observed_timestamp: Option<SystemTime>,
24
25    /// Trace context for logs associated with spans
26    pub trace_context: Option<TraceContext>,
27
28    /// The original severity string from the source
29    pub severity_text: Option<Cow<'static, str>>,
30    /// The corresponding severity value, normalized
31    pub severity_number: Option<Severity>,
32
33    /// Record body
34    pub body: Option<AnyValue>,
35
36    /// Additional attributes associated with this record
37    pub attributes: Option<Vec<(Key, AnyValue)>>,
38}
39
40impl opentelemetry::logs::LogRecord for LogRecord {
41    fn set_event_name<T>(&mut self, name: T)
42    where
43        T: Into<Cow<'static, str>>,
44    {
45        self.event_name = Some(name.into());
46    }
47
48    // Sets the `target` of a record
49    fn set_target<T>(&mut self, _target: T)
50    where
51        T: Into<Cow<'static, str>>,
52    {
53        self.target = Some(_target.into());
54    }
55
56    fn set_timestamp(&mut self, timestamp: SystemTime) {
57        self.timestamp = Some(timestamp);
58    }
59
60    fn set_observed_timestamp(&mut self, timestamp: SystemTime) {
61        self.observed_timestamp = Some(timestamp);
62    }
63
64    fn set_severity_text(&mut self, severity_text: Cow<'static, str>) {
65        self.severity_text = Some(severity_text);
66    }
67
68    fn set_severity_number(&mut self, severity_number: Severity) {
69        self.severity_number = Some(severity_number);
70    }
71
72    fn set_body(&mut self, body: AnyValue) {
73        self.body = Some(body);
74    }
75
76    fn add_attributes<I, K, V>(&mut self, attributes: I)
77    where
78        I: IntoIterator<Item = (K, V)>,
79        K: Into<Key>,
80        V: Into<AnyValue>,
81    {
82        for (key, value) in attributes.into_iter() {
83            self.add_attribute(key, value);
84        }
85    }
86
87    fn add_attribute<K, V>(&mut self, key: K, value: V)
88    where
89        K: Into<Key>,
90        V: Into<AnyValue>,
91    {
92        if let Some(ref mut attrs) = self.attributes {
93            attrs.push((key.into(), value.into()));
94        } else {
95            self.attributes = Some(vec![(key.into(), value.into())]);
96        }
97    }
98}
99
100/// TraceContext stores the trace context for logs that have an associated
101/// span.
102#[derive(Debug, Clone)]
103#[non_exhaustive]
104pub struct TraceContext {
105    /// Trace id
106    pub trace_id: TraceId,
107    /// Span Id
108    pub span_id: SpanId,
109    /// Trace flags
110    pub trace_flags: Option<TraceFlags>,
111}
112
113impl From<&SpanContext> for TraceContext {
114    fn from(span_context: &SpanContext) -> Self {
115        TraceContext {
116            trace_id: span_context.trace_id(),
117            span_id: span_context.span_id(),
118            trace_flags: Some(span_context.trace_flags()),
119        }
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use opentelemetry::logs::{AnyValue, LogRecord as _, Severity};
127    use std::borrow::Cow;
128    use std::time::SystemTime;
129
130    #[test]
131    fn test_set_eventname() {
132        let mut log_record = LogRecord::default();
133        log_record.set_event_name("test_event");
134        assert_eq!(log_record.event_name, Some(Cow::Borrowed("test_event")));
135    }
136
137    #[test]
138    fn test_set_target() {
139        let mut log_record = LogRecord::default();
140        log_record.set_target("foo::bar");
141        assert_eq!(log_record.target, Some(Cow::Borrowed("foo::bar")));
142    }
143
144    #[test]
145    fn test_set_timestamp() {
146        let mut log_record = LogRecord::default();
147        let now = SystemTime::now();
148        log_record.set_timestamp(now);
149        assert_eq!(log_record.timestamp, Some(now));
150    }
151
152    #[test]
153    fn test_set_observed_timestamp() {
154        let mut log_record = LogRecord::default();
155        let now = SystemTime::now();
156        log_record.set_observed_timestamp(now);
157        assert_eq!(log_record.observed_timestamp, Some(now));
158    }
159
160    #[test]
161    fn test_set_severity_text() {
162        let mut log_record = LogRecord::default();
163        let severity_text: Cow<'static, str> = "ERROR".into(); // Explicitly typed
164        log_record.set_severity_text(severity_text);
165        assert_eq!(log_record.severity_text, Some(Cow::Borrowed("ERROR")));
166    }
167
168    #[test]
169    fn test_set_severity_number() {
170        let mut log_record = LogRecord::default();
171        let severity_number = Severity::Error;
172        log_record.set_severity_number(severity_number);
173        assert_eq!(log_record.severity_number, Some(Severity::Error));
174    }
175
176    #[test]
177    fn test_set_body() {
178        let mut log_record = LogRecord::default();
179        let body = AnyValue::String("Test body".into());
180        log_record.set_body(body.clone());
181        assert_eq!(log_record.body, Some(body));
182    }
183
184    #[test]
185    fn test_set_attributes() {
186        let mut log_record = LogRecord::default();
187        let attributes = vec![(Key::new("key"), AnyValue::String("value".into()))];
188        log_record.add_attributes(attributes.clone());
189        assert_eq!(log_record.attributes, Some(attributes));
190    }
191
192    #[test]
193    fn test_set_attribute() {
194        let mut log_record = LogRecord::default();
195        log_record.add_attribute("key", "value");
196        assert_eq!(
197            log_record.attributes,
198            Some(vec![(Key::new("key"), AnyValue::String("value".into()))])
199        );
200    }
201}