use std::{ future::{ready, Ready}, rc::Rc, }; use actix_web::dev::{self, Service, Transform}; use actix_web::web::BytesMut; use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage}; use futures::future::LocalBoxFuture; use futures::stream::StreamExt; pub struct Logging; impl Transform for Logging where S: Service, Error = Error>, S::Future: 'static, B: 'static, { type Response = ServiceResponse; type Error = Error; type InitError = (); type Transform = LoggingMiddleware; type Future = Ready>; fn new_transform(&self, service: S) -> Self::Future { ready(Ok(LoggingMiddleware { service: Rc::new(service), })) } } pub struct LoggingMiddleware { // This is special: We need this to avoid lifetime issues. service: Rc, } impl Service for LoggingMiddleware where S: Service, Error = Error> + 'static, S::Future: 'static, B: 'static, { type Response = ServiceResponse; type Error = Error; type Future = LocalBoxFuture<'static, Result>; dev::forward_ready!(service); fn call(&self, mut req: ServiceRequest) -> Self::Future { let svc = self.service.clone(); Box::pin(async move { let mut body = BytesMut::new(); let mut stream = req.take_payload(); while let Some(chunk) = stream.next().await { body.extend_from_slice(&chunk?); } println!("request body: {:?}", body); let res = svc.call(req).await?; println!("response: {:?}", res.headers()); Ok(res) }) } }