mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	feat(logging): add a logging middleware to log all api requests (#3437)
This commit is contained in:
		| @ -245,7 +245,13 @@ pub async fn update_customer_payment_method( | ||||
|             .as_ref() | ||||
|             .map(|card_network| card_network.to_string()), | ||||
|     }; | ||||
|     add_payment_method(state, new_pm, &merchant_account, &key_store).await | ||||
|     Box::pin(add_payment_method( | ||||
|         state, | ||||
|         new_pm, | ||||
|         &merchant_account, | ||||
|         &key_store, | ||||
|     )) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| // Wrapper function to switch lockers | ||||
|  | ||||
| @ -81,11 +81,11 @@ where | ||||
|                     ) | ||||
|                     .await? | ||||
|                 } else { | ||||
|                     save_in_locker( | ||||
|                     Box::pin(save_in_locker( | ||||
|                         state, | ||||
|                         merchant_account, | ||||
|                         payment_method_create_request.to_owned(), | ||||
|                     ) | ||||
|                     )) | ||||
|                     .await? | ||||
|                 }; | ||||
|  | ||||
|  | ||||
| @ -267,5 +267,6 @@ pub fn get_application_builder( | ||||
|         .wrap(middleware::default_response_headers()) | ||||
|         .wrap(middleware::RequestId) | ||||
|         .wrap(cors::cors()) | ||||
|         .wrap(middleware::LogSpanInitializer) | ||||
|         .wrap(router_env::tracing_actix_web::TracingLogger::default()) | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| use router_env::tracing::{field::Empty, Instrument}; | ||||
| /// Middleware to include request ID in response header. | ||||
| pub struct RequestId; | ||||
|  | ||||
| @ -48,20 +49,23 @@ where | ||||
|         let request_id_fut = req.extract::<router_env::tracing_actix_web::RequestId>(); | ||||
|         let response_fut = self.service.call(req); | ||||
|  | ||||
|         Box::pin(async move { | ||||
|             let request_id = request_id_fut.await?; | ||||
|             let request_id = request_id.as_hyphenated().to_string(); | ||||
|             if let Some(upstream_request_id) = old_x_request_id { | ||||
|                 router_env::logger::info!(?request_id, ?upstream_request_id); | ||||
|             } | ||||
|             let mut response = response_fut.await?; | ||||
|             response.headers_mut().append( | ||||
|                 http::header::HeaderName::from_static("x-request-id"), | ||||
|                 http::HeaderValue::from_str(&request_id)?, | ||||
|             ); | ||||
|         Box::pin( | ||||
|             async move { | ||||
|                 let request_id = request_id_fut.await?; | ||||
|                 let request_id = request_id.as_hyphenated().to_string(); | ||||
|                 if let Some(upstream_request_id) = old_x_request_id { | ||||
|                     router_env::logger::info!(?request_id, ?upstream_request_id); | ||||
|                 } | ||||
|                 let mut response = response_fut.await?; | ||||
|                 response.headers_mut().append( | ||||
|                     http::header::HeaderName::from_static("x-request-id"), | ||||
|                     http::HeaderValue::from_str(&request_id)?, | ||||
|                 ); | ||||
|  | ||||
|             Ok(response) | ||||
|         }) | ||||
|                 Ok(response) | ||||
|             } | ||||
|             .in_current_span(), | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -81,3 +85,67 @@ pub fn default_response_headers() -> actix_web::middleware::DefaultHeaders { | ||||
|         .add((header::STRICT_TRANSPORT_SECURITY, "max-age=31536000")) | ||||
|         .add((header::VIA, "HyperSwitch")) | ||||
| } | ||||
|  | ||||
| /// Middleware to build a TOP level domain span for each request. | ||||
| pub struct LogSpanInitializer; | ||||
|  | ||||
| impl<S, B> actix_web::dev::Transform<S, actix_web::dev::ServiceRequest> for LogSpanInitializer | ||||
| where | ||||
|     S: actix_web::dev::Service< | ||||
|         actix_web::dev::ServiceRequest, | ||||
|         Response = actix_web::dev::ServiceResponse<B>, | ||||
|         Error = actix_web::Error, | ||||
|     >, | ||||
|     S::Future: 'static, | ||||
|     B: 'static, | ||||
| { | ||||
|     type Response = actix_web::dev::ServiceResponse<B>; | ||||
|     type Error = actix_web::Error; | ||||
|     type Transform = LogSpanInitializerMiddleware<S>; | ||||
|     type InitError = (); | ||||
|     type Future = std::future::Ready<Result<Self::Transform, Self::InitError>>; | ||||
|  | ||||
|     fn new_transform(&self, service: S) -> Self::Future { | ||||
|         std::future::ready(Ok(LogSpanInitializerMiddleware { service })) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct LogSpanInitializerMiddleware<S> { | ||||
|     service: S, | ||||
| } | ||||
|  | ||||
| impl<S, B> actix_web::dev::Service<actix_web::dev::ServiceRequest> | ||||
|     for LogSpanInitializerMiddleware<S> | ||||
| where | ||||
|     S: actix_web::dev::Service< | ||||
|         actix_web::dev::ServiceRequest, | ||||
|         Response = actix_web::dev::ServiceResponse<B>, | ||||
|         Error = actix_web::Error, | ||||
|     >, | ||||
|     S::Future: 'static, | ||||
|     B: 'static, | ||||
| { | ||||
|     type Response = actix_web::dev::ServiceResponse<B>; | ||||
|     type Error = actix_web::Error; | ||||
|     type Future = futures::future::LocalBoxFuture<'static, Result<Self::Response, Self::Error>>; | ||||
|  | ||||
|     actix_web::dev::forward_ready!(service); | ||||
|  | ||||
|     // TODO: have a common source of truth for the list of top level fields | ||||
|     // /crates/router_env/src/logger/storage.rs also has a list of fields  called PERSISTENT_KEYS | ||||
|     fn call(&self, req: actix_web::dev::ServiceRequest) -> Self::Future { | ||||
|         let response_fut = self.service.call(req); | ||||
|  | ||||
|         Box::pin( | ||||
|             response_fut.instrument( | ||||
|                 router_env::tracing::info_span!( | ||||
|                     "golden_log_line", | ||||
|                     payment_id = Empty, | ||||
|                     merchant_id = Empty, | ||||
|                     connector_name = Empty | ||||
|                 ) | ||||
|                 .or_current(), | ||||
|             ), | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -520,7 +520,7 @@ pub async fn business_profile_update( | ||||
|     let flow = Flow::BusinessProfileUpdate; | ||||
|     let (merchant_id, profile_id) = path.into_inner(); | ||||
|  | ||||
|     api::server_wrap( | ||||
|     Box::pin(api::server_wrap( | ||||
|         flow, | ||||
|         state, | ||||
|         &req, | ||||
| @ -535,7 +535,7 @@ pub async fn business_profile_update( | ||||
|             req.headers(), | ||||
|         ), | ||||
|         api_locking::LockAction::NotApplicable, | ||||
|     ) | ||||
|     )) | ||||
|     .await | ||||
| } | ||||
| #[instrument(skip_all, fields(flow = ?Flow::BusinessProfileDelete))] | ||||
|  | ||||
| @ -75,7 +75,7 @@ pub async fn revoke_mandate( | ||||
|     let mandate_id = mandates::MandateId { | ||||
|         mandate_id: path.into_inner(), | ||||
|     }; | ||||
|     api::server_wrap( | ||||
|     Box::pin(api::server_wrap( | ||||
|         flow, | ||||
|         state, | ||||
|         &req, | ||||
| @ -85,7 +85,7 @@ pub async fn revoke_mandate( | ||||
|         }, | ||||
|         &auth::ApiKeyAuth, | ||||
|         api_locking::LockAction::NotApplicable, | ||||
|     ) | ||||
|     )) | ||||
|     .await | ||||
| } | ||||
| /// Mandates - List Mandates | ||||
|  | ||||
| @ -44,7 +44,13 @@ pub async fn create_payment_method_api( | ||||
|         &req, | ||||
|         json_payload.into_inner(), | ||||
|         |state, auth, req| async move { | ||||
|             cards::add_payment_method(state, req, &auth.merchant_account, &auth.key_store).await | ||||
|             Box::pin(cards::add_payment_method( | ||||
|                 state, | ||||
|                 req, | ||||
|                 &auth.merchant_account, | ||||
|                 &auth.key_store, | ||||
|             )) | ||||
|             .await | ||||
|         }, | ||||
|         &auth::ApiKeyAuth, | ||||
|         api_locking::LockAction::NotApplicable, | ||||
|  | ||||
| @ -1131,7 +1131,6 @@ where | ||||
|         status_code = response_code, | ||||
|         time_taken_ms = request_duration.as_millis(), | ||||
|     ); | ||||
|  | ||||
|     res | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Sampras Lopes
					Sampras Lopes