1#![doc = include_str!("../README.md")]
2
3use std::task::Context;
4use std::task::Poll;
5
6use fastrace::prelude::*;
7use http::HeaderValue;
8use http::Request;
9use tower_layer::Layer;
10use tower_service::Service;
11
12pub const TRACEPARENT_HEADER: &str = "traceparent";
17
18#[derive(Clone)]
24pub struct FastraceServerLayer;
25
26impl<S> Layer<S> for FastraceServerLayer {
27 type Service = FastraceServerService<S>;
28
29 fn layer(&self, service: S) -> Self::Service {
30 FastraceServerService { service }
31 }
32}
33
34#[derive(Clone)]
40pub struct FastraceServerService<S> {
41 service: S,
42}
43
44impl<S, Body> Service<Request<Body>> for FastraceServerService<S>
45where S: Service<Request<Body>>
46{
47 type Response = S::Response;
48 type Error = S::Error;
49 type Future = fastrace::future::InSpan<S::Future>;
50
51 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
52 self.service.poll_ready(cx)
53 }
54
55 fn call(&mut self, req: Request<Body>) -> Self::Future {
56 let headers = req.headers();
57 let parent = headers.get(TRACEPARENT_HEADER).and_then(|traceparent| {
58 SpanContext::decode_w3c_traceparent(traceparent.to_str().ok()?)
59 });
60
61 let span = if let Some(parent) = parent {
62 Span::root(req.uri().to_string(), parent)
63 } else {
64 Span::noop()
65 };
66
67 self.service.call(req).in_span(span)
68 }
69}
70
71#[derive(Clone)]
77pub struct FastraceClientLayer;
78
79impl<S> Layer<S> for FastraceClientLayer {
80 type Service = FastraceClientService<S>;
81
82 fn layer(&self, service: S) -> Self::Service {
83 FastraceClientService { service }
84 }
85}
86
87#[derive(Clone)]
92pub struct FastraceClientService<S> {
93 service: S,
94}
95
96impl<S, Body> Service<Request<Body>> for FastraceClientService<S>
97where S: Service<Request<Body>>
98{
99 type Response = S::Response;
100 type Error = S::Error;
101 type Future = S::Future;
102
103 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
104 self.service.poll_ready(cx)
105 }
106
107 fn call(&mut self, mut req: Request<Body>) -> Self::Future {
108 if let Some(current) = SpanContext::current_local_parent() {
109 req.headers_mut().insert(
110 TRACEPARENT_HEADER,
111 HeaderValue::from_str(¤t.encode_w3c_traceparent()).unwrap(),
112 );
113 }
114
115 self.service.call(req)
116 }
117}