tracing_actix_web2/
lib.rs1use actix_web::http::header::{HeaderName, HeaderValue};
2use actix_web::{
3 dev::{Service, ServiceRequest, ServiceResponse, Transform},
4 Error,
5};
6use future::{ok, LocalBoxFuture, Ready};
7use futures::prelude::*;
8use std::{
9 cell::RefCell,
10 rc::Rc,
11 task::{Context, Poll},
12};
13use tracing::{span, trace, Instrument, Level};
14use uuid::Uuid;
15
16pub const REQUEST_ID_HEADER: &str = "x-request-id";
17
18pub struct Tracer;
19
20impl<S, B> Transform<S, ServiceRequest> for Tracer
21where
22 S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
23 S::Future: 'static,
24 B: 'static,
25{
26 type Response = ServiceResponse<B>;
27 type Error = Error;
28 type InitError = ();
29 type Transform = TracerMiddleware<S>;
30 type Future = Ready<Result<Self::Transform, Self::InitError>>;
31
32 fn new_transform(&self, service: S) -> Self::Future {
33 ok(TracerMiddleware {
34 service: Rc::new(RefCell::new(service)),
35 })
36 }
37}
38
39pub struct TracerMiddleware<S> {
40 pub service: Rc<RefCell<S>>,
41}
42
43impl<S, B> Service<ServiceRequest> for TracerMiddleware<S>
44where
45 S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
46 S::Future: 'static,
47 B: 'static,
48{
49 type Response = ServiceResponse<B>;
50 type Error = S::Error;
51 type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
52
53 fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
54 self.service.poll_ready(cx)
55 }
56
57 fn call(&self, req: ServiceRequest) -> Self::Future {
58 let request_id = Uuid::new_v4().to_string();
59 let root_span = span!(Level::INFO, "HttpRequest", %request_id, method = req.method().as_str(), path = req.path(), query = req.query_string(), remote_ip = req.connection_info().peer_addr().unwrap_or("-"));
60
61 let fut = self.service.call(req);
62 Box::pin(
63 async move {
64 let mut res = fut.await?;
65
66 res.headers_mut().insert(
67 HeaderName::from_static(REQUEST_ID_HEADER),
68 HeaderValue::from_str(&request_id).unwrap(),
69 );
70 trace!("request");
71
72 Ok(res)
73 }
74 .instrument(root_span),
75 )
76 }
77}