renacer_core/
lazy_span.rs1use std::borrow::Cow;
9
10pub struct LazySpan {
12 name: Option<Cow<'static, str>>,
13 attributes: Vec<(Cow<'static, str>, String)>,
14 timestamp_nanos: u64,
15 duration_nanos: u64,
16 status_code: i32,
17 committed: bool,
18}
19
20impl LazySpan {
21 pub fn new() -> Self {
23 LazySpan {
24 name: None,
25 attributes: Vec::new(),
26 timestamp_nanos: 0,
27 duration_nanos: 0,
28 status_code: 0,
29 committed: false,
30 }
31 }
32
33 pub fn with_name_static(mut self, name: &'static str) -> Self {
35 self.name = Some(Cow::Borrowed(name));
36 self
37 }
38
39 pub fn with_name_owned(mut self, name: String) -> Self {
41 self.name = Some(Cow::Owned(name));
42 self
43 }
44
45 pub fn with_attribute_static(mut self, key: &'static str, value: String) -> Self {
47 self.attributes.push((Cow::Borrowed(key), value));
48 self
49 }
50
51 pub fn with_attribute_owned(mut self, key: String, value: String) -> Self {
53 self.attributes.push((Cow::Owned(key), value));
54 self
55 }
56
57 pub fn with_timestamp(mut self, timestamp_nanos: u64) -> Self {
59 self.timestamp_nanos = timestamp_nanos;
60 self
61 }
62
63 pub fn with_duration(mut self, duration_nanos: u64) -> Self {
65 self.duration_nanos = duration_nanos;
66 self
67 }
68
69 pub fn with_status(mut self, status_code: i32) -> Self {
71 self.status_code = status_code;
72 self
73 }
74
75 pub fn is_committed(&self) -> bool {
77 self.committed
78 }
79
80 pub fn commit(mut self) -> CommittedSpan {
85 self.committed = true;
86 CommittedSpan {
87 name: self.name.unwrap_or(Cow::Borrowed("")),
88 attributes: self.attributes,
89 timestamp_nanos: self.timestamp_nanos,
90 duration_nanos: self.duration_nanos,
91 status_code: self.status_code,
92 }
93 }
94
95 pub fn cancel(self) {
97 }
99}
100
101impl Default for LazySpan {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107pub struct CommittedSpan {
109 pub name: Cow<'static, str>,
110 pub attributes: Vec<(Cow<'static, str>, String)>,
111 pub timestamp_nanos: u64,
112 pub duration_nanos: u64,
113 pub status_code: i32,
114}
115
116#[macro_export]
118macro_rules! lazy_span {
119 ($name:expr) => {
120 LazySpan::new().with_name_static($name)
121 };
122 ($name:expr, $($key:expr => $value:expr),* $(,)?) => {
123 {
124 let mut span = LazySpan::new().with_name_static($name);
125 $(
126 span = span.with_attribute_static($key, $value);
127 )*
128 span
129 }
130 };
131}
132
133static_assertions::assert_impl_all!(LazySpan: Send, Sync);
135static_assertions::assert_impl_all!(CommittedSpan: Send, Sync);
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_lazy_span_minimal() {
143 let span = LazySpan::new();
144 assert!(!span.is_committed());
145 assert_eq!(span.name, None);
146 assert_eq!(span.attributes.len(), 0);
147 }
148
149 #[test]
150 fn test_lazy_span_builder() {
151 let span = LazySpan::new()
152 .with_name_static("syscall:open")
153 .with_attribute_static("syscall.name", "open".to_string())
154 .with_attribute_static("syscall.result", "3".to_string())
155 .with_timestamp(1234567890)
156 .with_duration(1000);
157
158 assert!(!span.is_committed());
159 assert_eq!(span.name, Some(Cow::Borrowed("syscall:open")));
160 assert_eq!(span.attributes.len(), 2);
161 }
162
163 #[test]
164 fn test_lazy_span_commit() {
165 let span = LazySpan::new()
166 .with_name_static("test")
167 .with_timestamp(100)
168 .with_duration(50);
169
170 let committed = span.commit();
171 assert_eq!(committed.name.as_ref(), "test");
172 assert_eq!(committed.timestamp_nanos, 100);
173 assert_eq!(committed.duration_nanos, 50);
174 }
175
176 #[test]
177 fn test_lazy_span_cancel() {
178 let span = LazySpan::new()
179 .with_name_static("cancelled")
180 .with_attribute_static("test", "value".to_string());
181
182 span.cancel();
184 }
186
187 #[test]
188 fn test_lazy_span_zero_copy() {
189 let span = LazySpan::new()
190 .with_name_static("syscall:open")
191 .with_attribute_static("syscall.name", "open".to_string());
192
193 if let Some(Cow::Borrowed(_)) = span.name {
194 } else {
196 panic!("Expected borrowed name");
197 }
198
199 assert!(matches!(span.attributes[0].0, Cow::Borrowed(_)));
200 }
201
202 #[test]
203 fn test_lazy_span_owned() {
204 let dynamic_name = format!("dynamic_{}", 42);
205 let span = LazySpan::new()
206 .with_name_owned(dynamic_name.clone())
207 .with_attribute_owned("key".to_string(), "value".to_string());
208
209 if let Some(Cow::Owned(_)) = span.name {
210 } else {
212 panic!("Expected owned name");
213 }
214
215 assert!(matches!(span.attributes[0].0, Cow::Owned(_)));
216 }
217
218 #[test]
219 fn test_span_not_committed_by_default() {
220 let span = LazySpan::new().with_name_static("test");
221 assert!(!span.is_committed());
222 }
223
224 #[test]
225 fn test_multiple_attributes() {
226 let span = LazySpan::new()
227 .with_name_static("test")
228 .with_attribute_static("key1", "value1".to_string())
229 .with_attribute_static("key2", "value2".to_string())
230 .with_attribute_static("key3", "value3".to_string());
231
232 assert_eq!(span.attributes.len(), 3);
233 assert_eq!(span.attributes[0].1, "value1");
234 assert_eq!(span.attributes[1].1, "value2");
235 assert_eq!(span.attributes[2].1, "value3");
236 }
237}