#![doc = include_str!("../README.md")]
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
use fastrace::prelude::*;
use http::HeaderValue;
use http::Request;
use tower_layer::Layer;
use tower_service::Service;
pub const TRACEPARENT_HEADER: &str = "traceparent";
type SpanContextExtractor =
Arc<dyn Fn(&http::HeaderMap) -> Option<SpanContext> + Send + Sync + 'static>;
#[derive(Clone)]
pub struct FastraceServerLayer {
span_context_extractor: SpanContextExtractor,
}
impl Default for FastraceServerLayer {
fn default() -> Self {
Self {
span_context_extractor: Arc::new(|headers| {
headers
.get(TRACEPARENT_HEADER)
.and_then(|traceparent| {
SpanContext::decode_w3c_traceparent(traceparent.to_str().ok()?)
})
.or_else(|| Some(SpanContext::random()))
}),
}
}
}
impl FastraceServerLayer {
pub fn with_span_context_extractor<F>(mut self, f: F) -> Self
where F: Fn(&http::HeaderMap) -> Option<SpanContext> + Send + Sync + 'static {
self.span_context_extractor = Arc::new(f);
self
}
}
impl<S> Layer<S> for FastraceServerLayer {
type Service = FastraceServerService<S>;
fn layer(&self, service: S) -> Self::Service {
FastraceServerService {
service,
span_context_extractor: self.span_context_extractor.clone(),
}
}
}
#[derive(Clone)]
pub struct FastraceServerService<S> {
service: S,
span_context_extractor: SpanContextExtractor,
}
impl<S, Body> Service<Request<Body>> for FastraceServerService<S>
where S: Service<Request<Body>>
{
type Response = S::Response;
type Error = S::Error;
type Future = fastrace::future::InSpan<S::Future>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: Request<Body>) -> Self::Future {
let parent = (self.span_context_extractor)(req.headers());
let span = if let Some(parent) = parent {
Span::root(req.method().to_string(), parent)
} else {
Span::noop()
};
self.service.call(req).in_span(span)
}
}
#[derive(Clone)]
pub struct FastraceClientLayer;
impl<S> Layer<S> for FastraceClientLayer {
type Service = FastraceClientService<S>;
fn layer(&self, service: S) -> Self::Service {
FastraceClientService { service }
}
}
#[derive(Clone)]
pub struct FastraceClientService<S> {
service: S,
}
impl<S, Body> Service<Request<Body>> for FastraceClientService<S>
where S: Service<Request<Body>>
{
type Response = S::Response;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: Request<Body>) -> Self::Future {
if let Some(current) = SpanContext::current_local_parent() {
req.headers_mut().insert(
TRACEPARENT_HEADER,
HeaderValue::from_str(¤t.encode_w3c_traceparent()).unwrap(),
);
}
self.service.call(req)
}
}