alloy_transport_http/layers/
trace.rs

1use alloy_json_rpc::RequestPacket;
2use tower::{Layer, Service};
3use tracing_opentelemetry::OpenTelemetrySpanExt;
4
5/// A layer to propagate trace context using W3C `traceparent` header standard.
6///
7/// This layer injects the `traceparent` header into outgoing requests, enabling
8/// distributed tracing across services that support the W3C Trace Context
9/// specification.
10#[derive(Debug, Default, Clone, Copy)]
11pub struct TraceParentLayer;
12
13impl<S> Layer<S> for TraceParentLayer {
14    type Service = TraceParentService<S>;
15
16    fn layer(&self, inner: S) -> Self::Service {
17        TraceParentService { inner }
18    }
19}
20
21/// A service that injects trace context into requests using W3C `traceparent`
22/// header standard.
23///
24/// This service wraps another service and adds the `traceparent` header to each
25/// outgoing request, allowing for trace context propagation.
26#[derive(Debug)]
27pub struct TraceParentService<S> {
28    inner: S,
29}
30
31impl<S> Service<RequestPacket> for TraceParentService<S>
32where
33    S: Service<RequestPacket> + Send + 'static,
34    S::Future: Send + 'static,
35{
36    type Response = S::Response;
37    type Error = S::Error;
38    type Future = S::Future;
39
40    fn poll_ready(
41        &mut self,
42        cx: &mut std::task::Context<'_>,
43    ) -> std::task::Poll<Result<(), Self::Error>> {
44        self.inner.poll_ready(cx)
45    }
46
47    fn call(&mut self, mut req: RequestPacket) -> Self::Future {
48        // Insert the header into the LAST request in the batch. This ensures
49        // that this will override any other traceparents.
50        if let Some(req) = req.requests_mut().last_mut() {
51            let mut injector = opentelemetry_http::HeaderInjector(req.headers_mut());
52
53            let ctx = tracing::Span::current().context();
54
55            opentelemetry::global::get_text_map_propagator(|propagator| {
56                propagator.inject_context(&ctx, &mut injector)
57            });
58        }
59
60        self.inner.call(req)
61    }
62}