use crate::{
trace::{Event, Link, Span, SpanKind, TraceContextExt},
Context, KeyValue,
};
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,
{
self.in_span_with_builder(self.span_builder(name), f)
}
fn in_span_with_context<T, F, N>(&self, name: N, parent_cx: &Context, f: F) -> T
where
F: FnOnce(Context) -> T,
N: Into<Cow<'static, str>>,
Self::Span: Send + Sync + 'static,
{
self.in_span_with_builder_and_context(self.span_builder(name), parent_cx, f)
}
fn in_span_with_builder<T, F>(&self, builder: SpanBuilder, f: F) -> T
where
F: FnOnce(Context) -> T,
Self::Span: Send + Sync + 'static,
{
let span = self.build(builder);
let cx = Context::current_with_span(span);
let _guard = cx.clone().attach();
f(cx)
}
fn in_span_with_builder_and_context<T, F>(
&self,
builder: SpanBuilder,
parent_cx: &Context,
f: F,
) -> T
where
F: FnOnce(Context) -> T,
Self::Span: Send + Sync + 'static,
{
let span = self.build_with_context(builder, parent_cx);
let cx = parent_cx.with_span(span);
let _guard = cx.clone().attach();
f(cx)
}
}
#[derive(Clone, Debug, Default)]
pub struct SpanBuilder {
pub span_kind: Option<SpanKind>,
pub name: Cow<'static, str>,
pub start_time: Option<SystemTime>,
pub attributes: Option<Vec<KeyValue>>,
pub events: Option<Vec<Event>>,
pub links: Option<Vec<Link>>,
}
impl SpanBuilder {
pub fn from_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
SpanBuilder {
name: name.into(),
..Default::default()
}
}
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_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 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)
}
}