use crate::{Annotation, Endpoint, SpanId, TraceId};
use std::collections::HashMap;
use std::time::{Duration, SystemTime};
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
#[non_exhaustive]
pub enum Kind {
Client,
Server,
Producer,
Consumer,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Span {
trace_id: TraceId,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
name: Option<String>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
parent_id: Option<SpanId>,
id: SpanId,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
kind: Option<Kind>,
#[cfg_attr(
feature = "serde",
serde(
skip_serializing_if = "Option::is_none",
with = "crate::opt_time_micros"
)
)]
timestamp: Option<SystemTime>,
#[cfg_attr(
feature = "serde",
serde(
skip_serializing_if = "Option::is_none",
with = "crate::opt_duration_micros"
)
)]
duration: Option<Duration>,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "is_false", default = "value_false")
)]
debug: bool,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "is_false", default = "value_false")
)]
shared: bool,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
local_endpoint: Option<Endpoint>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
remote_endpoint: Option<Endpoint>,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "Vec::is_empty", default)
)]
annotations: Vec<Annotation>,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "HashMap::is_empty", default)
)]
tags: HashMap<String, String>,
}
#[cfg(feature = "serde")]
#[inline]
fn is_false(v: &bool) -> bool {
!*v
}
#[cfg(feature = "serde")]
#[inline]
fn value_false() -> bool {
false
}
impl Span {
#[inline]
pub fn builder() -> Builder {
Builder {
trace_id: None,
name: None,
parent_id: None,
id: None,
kind: None,
timestamp: None,
duration: None,
debug: false,
shared: false,
local_endpoint: None,
remote_endpoint: None,
annotations: vec![],
tags: HashMap::new(),
}
}
#[inline]
pub fn trace_id(&self) -> TraceId {
self.trace_id
}
#[inline]
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
#[inline]
pub fn parent_id(&self) -> Option<SpanId> {
self.parent_id
}
#[inline]
pub fn id(&self) -> SpanId {
self.id
}
#[inline]
pub fn kind(&self) -> Option<Kind> {
self.kind
}
#[inline]
pub fn timestamp(&self) -> Option<SystemTime> {
self.timestamp
}
#[inline]
pub fn duration(&self) -> Option<Duration> {
self.duration
}
#[inline]
pub fn debug(&self) -> bool {
self.debug
}
#[inline]
pub fn shared(&self) -> bool {
self.shared
}
#[inline]
pub fn local_endpoint(&self) -> Option<&Endpoint> {
self.local_endpoint.as_ref()
}
#[inline]
pub fn remote_endpoint(&self) -> Option<&Endpoint> {
self.remote_endpoint.as_ref()
}
#[inline]
pub fn annotations(&self) -> &[Annotation] {
&self.annotations
}
#[inline]
pub fn tags(&self) -> &HashMap<String, String> {
&self.tags
}
}
pub struct Builder {
trace_id: Option<TraceId>,
name: Option<String>,
parent_id: Option<SpanId>,
id: Option<SpanId>,
kind: Option<Kind>,
timestamp: Option<SystemTime>,
duration: Option<Duration>,
debug: bool,
shared: bool,
local_endpoint: Option<Endpoint>,
remote_endpoint: Option<Endpoint>,
annotations: Vec<Annotation>,
tags: HashMap<String, String>,
}
impl From<Span> for Builder {
#[inline]
fn from(s: Span) -> Builder {
Builder {
trace_id: Some(s.trace_id),
name: s.name,
parent_id: s.parent_id,
id: Some(s.id),
kind: s.kind,
timestamp: s.timestamp,
duration: s.duration,
debug: s.debug,
shared: s.shared,
local_endpoint: s.local_endpoint,
remote_endpoint: s.remote_endpoint,
annotations: s.annotations,
tags: s.tags,
}
}
}
impl Builder {
#[inline]
pub fn trace_id(&mut self, trace_id: TraceId) -> &mut Builder {
self.trace_id = Some(trace_id);
self
}
#[inline]
pub fn name(&mut self, name: &str) -> &mut Builder {
self.name = Some(name.to_lowercase());
self
}
#[inline]
pub fn parent_id(&mut self, parent_id: SpanId) -> &mut Builder {
self.parent_id = Some(parent_id);
self
}
#[inline]
pub fn id(&mut self, id: SpanId) -> &mut Builder {
self.id = Some(id);
self
}
#[inline]
pub fn kind(&mut self, kind: Kind) -> &mut Builder {
self.kind = Some(kind);
self
}
#[inline]
pub fn timestamp(&mut self, timestamp: SystemTime) -> &mut Builder {
self.timestamp = Some(timestamp);
self
}
#[inline]
pub fn duration(&mut self, duration: Duration) -> &mut Builder {
self.duration = Some(duration);
self
}
#[inline]
pub fn debug(&mut self, debug: bool) -> &mut Builder {
self.debug = debug;
self
}
#[inline]
pub fn shared(&mut self, shared: bool) -> &mut Builder {
self.shared = shared;
self
}
#[inline]
pub fn local_endpoint(&mut self, local_endpoint: Endpoint) -> &mut Builder {
self.local_endpoint = Some(local_endpoint);
self
}
#[inline]
pub fn remote_endpoint(&mut self, remote_endpoint: Endpoint) -> &mut Builder {
self.remote_endpoint = Some(remote_endpoint);
self
}
#[inline]
pub fn annotation(&mut self, annotation: Annotation) -> &mut Builder {
self.annotations.push(annotation);
self
}
#[inline]
pub fn annotations<I>(&mut self, annotations: I) -> &mut Builder
where
I: IntoIterator<Item = Annotation>,
{
self.annotations.extend(annotations);
self
}
#[inline]
pub fn tag(&mut self, key: &str, value: &str) -> &mut Builder {
self.tags.insert(key.to_string(), value.to_string());
self
}
#[inline]
pub fn tags<I>(&mut self, tags: I) -> &mut Builder
where
I: IntoIterator<Item = (String, String)>,
{
self.tags.extend(tags);
self
}
#[inline]
pub fn build(&self) -> Span {
Span {
trace_id: self.trace_id.expect("trace ID not set"),
name: self.name.clone(),
id: self.id.expect("span ID not set"),
kind: self.kind,
parent_id: self.parent_id,
timestamp: self.timestamp,
duration: self.duration,
debug: self.debug,
shared: self.shared,
local_endpoint: self.local_endpoint.clone(),
remote_endpoint: self.remote_endpoint.clone(),
annotations: self.annotations.clone(),
tags: self.tags.clone(),
}
}
}