use opentelemetry::global::BoxedSpan;
use opentelemetry::trace::{Span as OtelSpan, TraceContextExt, Tracer};
use opentelemetry::{KeyValue, Value, global};
use tracing_opentelemetry::OpenTelemetrySpanExt;
pub fn start_span(name: impl Into<String>) -> SpanGuard {
let parent_ctx = tracing::Span::current().context();
if !parent_ctx.span().span_context().is_valid() {
return SpanGuard { span: None };
}
let tracer = global::tracer("dynamo");
let span = tracer
.span_builder(name.into())
.start_with_context(&tracer, &parent_ctx);
SpanGuard { span: Some(span) }
}
pub struct SpanGuard {
span: Option<BoxedSpan>,
}
impl SpanGuard {
pub fn set_attribute(&mut self, key: impl Into<String>, value: impl Into<Value>) {
if let Some(span) = self.span.as_mut() {
span.set_attribute(KeyValue::new(key.into(), value.into()));
}
}
pub fn add_event(&mut self, name: impl Into<String>, attrs: Vec<KeyValue>) {
if let Some(span) = self.span.as_mut() {
span.add_event(name.into(), attrs);
}
}
pub fn close(&mut self) {
if let Some(mut span) = self.span.take() {
span.end();
}
}
}
impl Drop for SpanGuard {
fn drop(&mut self) {
self.close();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn start_span_is_noop_without_bridge() {
let mut guard = start_span("test_dynamic");
guard.set_attribute("k", "v");
guard.add_event("e", vec![]);
guard.close();
guard.close(); }
}