use crate::{
trace::{Event, Link, Span, SpanKind, Status, TraceContextExt, TraceState},
Context, KeyValue, SpanId, TraceId,
};
use std::borrow::Cow;
use std::time::SystemTime;
pub trait Tracer {
type Span: Span;
fn start<T>(&self, name: T) -> Self::Span
where
T: Into<Cow<'static, str>>,
{
Context::map_current(|cx| self.start_with_context(name, cx))
}
fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
where
T: Into<Cow<'static, str>>,
{
self.build_with_context(SpanBuilder::from_name(name), parent_cx)
}
fn span_builder<T>(&self, name: T) -> SpanBuilder
where
T: Into<Cow<'static, str>>,
{
SpanBuilder::from_name(name)
}
fn build(&self, builder: SpanBuilder) -> Self::Span {
Context::map_current(|cx| self.build_with_context(builder, cx))
}
fn build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span;
fn in_span<T, F, N>(&self, name: N, f: F) -> T
where
F: FnOnce(Context) -> T,
N: Into<Cow<'static, str>>,
Self::Span: Send + Sync + 'static,
{
let span = self.start(name);
let cx = Context::current_with_span(span);
let _guard = cx.clone().attach();
f(cx)
}
}
#[derive(Clone, Debug, Default)]
pub struct SpanBuilder {
pub trace_id: Option<TraceId>,
pub span_id: Option<SpanId>,
pub span_kind: Option<SpanKind>,
pub name: Cow<'static, str>,
pub start_time: Option<SystemTime>,
pub end_time: Option<SystemTime>,
pub attributes: Option<Vec<KeyValue>>,
pub events: Option<Vec<Event>>,
pub links: Option<Vec<Link>>,
pub status: Status,
pub sampling_result: Option<SamplingResult>,
}
impl SpanBuilder {
pub fn from_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
SpanBuilder {
name: name.into(),
..Default::default()
}
}
pub fn with_trace_id(self, trace_id: TraceId) -> Self {
SpanBuilder {
trace_id: Some(trace_id),
..self
}
}
pub fn with_span_id(self, span_id: SpanId) -> Self {
SpanBuilder {
span_id: Some(span_id),
..self
}
}
pub fn with_kind(self, span_kind: SpanKind) -> Self {
SpanBuilder {
span_kind: Some(span_kind),
..self
}
}
pub fn with_start_time<T: Into<SystemTime>>(self, start_time: T) -> Self {
SpanBuilder {
start_time: Some(start_time.into()),
..self
}
}
pub fn with_end_time<T: Into<SystemTime>>(self, end_time: T) -> Self {
SpanBuilder {
end_time: Some(end_time.into()),
..self
}
}
pub fn with_attributes<I>(self, attributes: I) -> Self
where
I: IntoIterator<Item = KeyValue>,
{
SpanBuilder {
attributes: Some(attributes.into_iter().collect()),
..self
}
}
pub fn with_events(self, events: Vec<Event>) -> Self {
SpanBuilder {
events: Some(events),
..self
}
}
pub fn with_links(self, mut links: Vec<Link>) -> Self {
links.retain(|l| l.span_context.is_valid());
SpanBuilder {
links: Some(links),
..self
}
}
pub fn with_status(self, status: Status) -> Self {
SpanBuilder { status, ..self }
}
pub fn with_sampling_result(self, sampling_result: SamplingResult) -> Self {
SpanBuilder {
sampling_result: Some(sampling_result),
..self
}
}
pub fn start<T: Tracer>(self, tracer: &T) -> T::Span {
Context::map_current(|cx| tracer.build_with_context(self, cx))
}
pub fn start_with_context<T: Tracer>(self, tracer: &T, parent_cx: &Context) -> T::Span {
tracer.build_with_context(self, parent_cx)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SamplingResult {
pub decision: SamplingDecision,
pub attributes: Vec<KeyValue>,
pub trace_state: TraceState,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SamplingDecision {
Drop,
RecordOnly,
RecordAndSample,
}