use std::borrow::Cow;
pub struct LazySpan {
name: Option<Cow<'static, str>>,
attributes: Vec<(Cow<'static, str>, String)>,
timestamp_nanos: u64,
duration_nanos: u64,
status_code: i32,
committed: bool,
}
impl LazySpan {
pub fn new() -> Self {
LazySpan {
name: None,
attributes: Vec::new(),
timestamp_nanos: 0,
duration_nanos: 0,
status_code: 0,
committed: false,
}
}
pub fn with_name_static(mut self, name: &'static str) -> Self {
self.name = Some(Cow::Borrowed(name));
self
}
pub fn with_name_owned(mut self, name: String) -> Self {
self.name = Some(Cow::Owned(name));
self
}
pub fn with_attribute_static(mut self, key: &'static str, value: String) -> Self {
self.attributes.push((Cow::Borrowed(key), value));
self
}
pub fn with_attribute_owned(mut self, key: String, value: String) -> Self {
self.attributes.push((Cow::Owned(key), value));
self
}
pub fn with_timestamp(mut self, timestamp_nanos: u64) -> Self {
self.timestamp_nanos = timestamp_nanos;
self
}
pub fn with_duration(mut self, duration_nanos: u64) -> Self {
self.duration_nanos = duration_nanos;
self
}
pub fn with_status(mut self, status_code: i32) -> Self {
self.status_code = status_code;
self
}
pub fn is_committed(&self) -> bool {
self.committed
}
pub fn commit(mut self) -> CommittedSpan {
self.committed = true;
CommittedSpan {
name: self.name.unwrap_or(Cow::Borrowed("")),
attributes: self.attributes,
timestamp_nanos: self.timestamp_nanos,
duration_nanos: self.duration_nanos,
status_code: self.status_code,
}
}
pub fn cancel(self) {
}
}
impl Default for LazySpan {
fn default() -> Self {
Self::new()
}
}
pub struct CommittedSpan {
pub name: Cow<'static, str>,
pub attributes: Vec<(Cow<'static, str>, String)>,
pub timestamp_nanos: u64,
pub duration_nanos: u64,
pub status_code: i32,
}
#[macro_export]
macro_rules! lazy_span {
($name:expr) => {
LazySpan::new().with_name_static($name)
};
($name:expr, $($key:expr => $value:expr),* $(,)?) => {
{
let mut span = LazySpan::new().with_name_static($name);
$(
span = span.with_attribute_static($key, $value);
)*
span
}
};
}
static_assertions::assert_impl_all!(LazySpan: Send, Sync);
static_assertions::assert_impl_all!(CommittedSpan: Send, Sync);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lazy_span_minimal() {
let span = LazySpan::new();
assert!(!span.is_committed());
assert_eq!(span.name, None);
assert_eq!(span.attributes.len(), 0);
}
#[test]
fn test_lazy_span_builder() {
let span = LazySpan::new()
.with_name_static("syscall:open")
.with_attribute_static("syscall.name", "open".to_string())
.with_attribute_static("syscall.result", "3".to_string())
.with_timestamp(1234567890)
.with_duration(1000);
assert!(!span.is_committed());
assert_eq!(span.name, Some(Cow::Borrowed("syscall:open")));
assert_eq!(span.attributes.len(), 2);
}
#[test]
fn test_lazy_span_commit() {
let span = LazySpan::new().with_name_static("test").with_timestamp(100).with_duration(50);
let committed = span.commit();
assert_eq!(committed.name.as_ref(), "test");
assert_eq!(committed.timestamp_nanos, 100);
assert_eq!(committed.duration_nanos, 50);
}
#[test]
fn test_lazy_span_cancel() {
let span = LazySpan::new()
.with_name_static("cancelled")
.with_attribute_static("test", "value".to_string());
span.cancel();
}
#[test]
fn test_lazy_span_zero_copy() {
let span = LazySpan::new()
.with_name_static("syscall:open")
.with_attribute_static("syscall.name", "open".to_string());
if let Some(Cow::Borrowed(_)) = span.name {
} else {
panic!("Expected borrowed name");
}
assert!(matches!(span.attributes[0].0, Cow::Borrowed(_)));
}
#[test]
fn test_lazy_span_owned() {
let dynamic_name = format!("dynamic_{}", 42);
let span = LazySpan::new()
.with_name_owned(dynamic_name.clone())
.with_attribute_owned("key".to_string(), "value".to_string());
if let Some(Cow::Owned(_)) = span.name {
} else {
panic!("Expected owned name");
}
assert!(matches!(span.attributes[0].0, Cow::Owned(_)));
}
#[test]
fn test_span_not_committed_by_default() {
let span = LazySpan::new().with_name_static("test");
assert!(!span.is_committed());
}
#[test]
fn test_multiple_attributes() {
let span = LazySpan::new()
.with_name_static("test")
.with_attribute_static("key1", "value1".to_string())
.with_attribute_static("key2", "value2".to_string())
.with_attribute_static("key3", "value3".to_string());
assert_eq!(span.attributes.len(), 3);
assert_eq!(span.attributes[0].1, "value1");
assert_eq!(span.attributes[1].1, "value2");
assert_eq!(span.attributes[2].1, "value3");
}
}