sh_layer1/observability/
span.rs1use tracing::Span;
4
5pub struct SpanGuard {
9 span: Option<Span>,
10}
11
12impl SpanGuard {
13 pub fn new(span: Span) -> Self {
15 Self { span: Some(span) }
16 }
17
18 pub fn noop() -> Self {
20 Self { span: None }
21 }
22
23 pub fn set_attribute(&self, key: &str, value: &str) {
25 if let Some(span) = &self.span {
26 span.record(key, value);
27 }
28 }
29
30 pub fn add_event(&self, name: &str, attributes: &[(&str, &str)]) {
32 if let Some(span) = &self.span {
33 let mut fields = Vec::new();
34 for (k, v) in attributes {
35 fields.push(format!("{}={}", k, v));
36 }
37 span.record("event", format!("{}: {}", name, fields.join(", ")));
38 }
39 }
40
41 pub fn as_ref(&self) -> Option<&Span> {
43 self.span.as_ref()
44 }
45}
46
47impl Default for SpanGuard {
48 fn default() -> Self {
49 Self::noop()
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_span_guard_noop() {
59 let guard = SpanGuard::noop();
60 guard.set_attribute("key", "value");
61 guard.add_event("test", &[("a", "b")]);
62 }
64
65 #[test]
66 fn test_span_guard_default() {
67 let guard = SpanGuard::default();
68 assert!(guard.as_ref().is_none());
69 }
70
71 #[test]
72 fn test_span_guard_with_span() {
73 let span = tracing::info_span!("test_span");
74 let guard = SpanGuard::new(span);
75
76 guard.set_attribute("key", "value");
77 guard.add_event("event", &[("status", "ok")]);
78
79 assert!(guard.as_ref().is_some());
80 }
81}