From d2092dcb0a5ccddf8248ffb33fae91280268610e Mon Sep 17 00:00:00 2001 From: Chethan Rao <70657455+Chethan-rao@users.noreply.github.com> Date: Tue, 18 Jun 2024 18:29:12 +0530 Subject: [PATCH] refactor: add basic counter metrics for IMC (#5006) --- crates/analytics/src/api_event/core.rs | 9 +- crates/analytics/src/disputes/core.rs | 9 +- crates/analytics/src/metrics/request.rs | 19 ++- crates/analytics/src/payments/core.rs | 17 +-- crates/analytics/src/refunds/core.rs | 9 +- crates/hyperswitch_interfaces/src/api.rs | 3 +- crates/hyperswitch_interfaces/src/metrics.rs | 10 +- crates/router/src/connector/boku.rs | 3 +- crates/router/src/connector/braintree.rs | 2 +- crates/router/src/connector/cybersource.rs | 5 +- crates/router/src/connector/noon.rs | 2 +- crates/router/src/connector/payme.rs | 2 +- crates/router/src/connector/rapyd.rs | 2 +- crates/router/src/connector/threedsecureio.rs | 5 +- crates/router/src/connector/trustpay.rs | 2 +- crates/router/src/core/admin.rs | 9 +- crates/router/src/core/api_keys.rs | 6 +- crates/router/src/core/mandate.rs | 9 +- .../router/src/core/payment_methods/cards.rs | 4 +- .../router/src/core/payment_methods/vault.rs | 7 +- crates/router/src/core/payments.rs | 13 +-- .../router/src/core/payments/access_token.rs | 16 +-- crates/router/src/core/payments/customers.rs | 7 +- .../src/core/payments/flows/authorize_flow.rs | 25 ++-- .../src/core/payments/flows/cancel_flow.rs | 6 +- .../payments/flows/complete_authorize_flow.rs | 12 +- .../src/core/payments/flows/session_flow.rs | 6 +- crates/router/src/core/payments/helpers.rs | 32 ++--- .../router/src/core/payments/tokenization.rs | 16 +-- .../router/src/core/payments/transformers.rs | 14 +-- .../router/src/core/payouts/access_token.rs | 6 +- crates/router/src/core/refunds.rs | 18 +-- crates/router/src/core/webhooks/incoming.rs | 11 +- crates/router/src/core/webhooks/outgoing.rs | 7 +- crates/router/src/routes/metrics.rs | 5 +- .../routes/metrics/bg_metrics_collector.rs | 41 +++---- crates/router/src/routes/metrics/request.rs | 29 +++-- crates/router/src/services/api.rs | 30 +++-- crates/router/src/utils.rs | 53 ++++----- crates/router/src/workflows/api_key_expiry.rs | 4 +- crates/router_env/src/metrics.rs | 15 +++ crates/storage_impl/src/metrics.rs | 8 +- crates/storage_impl/src/redis/cache.rs | 109 ++++++++++++++---- 43 files changed, 301 insertions(+), 316 deletions(-) diff --git a/crates/analytics/src/api_event/core.rs b/crates/analytics/src/api_event/core.rs index 7225a6322d47..c7d6d9ac3394 100644 --- a/crates/analytics/src/api_event/core.rs +++ b/crates/analytics/src/api_event/core.rs @@ -12,6 +12,7 @@ use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; use router_env::{ instrument, logger, + metrics::add_attributes, tracing::{self, Instrument}, }; @@ -135,10 +136,10 @@ pub async fn get_api_event_metrics( .change_context(AnalyticsError::UnknownError)? { let data = data?; - let attributes = &[ - metrics::request::add_attributes("metric_type", metric.to_string()), - metrics::request::add_attributes("source", pool.to_string()), - ]; + let attributes = &add_attributes([ + ("metric_type", metric.to_string()), + ("source", pool.to_string()), + ]); let value = u64::try_from(data.len()); if let Ok(val) = value { diff --git a/crates/analytics/src/disputes/core.rs b/crates/analytics/src/disputes/core.rs index dfba5fea1126..d2279180255d 100644 --- a/crates/analytics/src/disputes/core.rs +++ b/crates/analytics/src/disputes/core.rs @@ -11,6 +11,7 @@ use api_models::analytics::{ use error_stack::ResultExt; use router_env::{ logger, + metrics::add_attributes, tracing::{self, Instrument}, }; @@ -70,10 +71,10 @@ pub async fn get_metrics( .change_context(AnalyticsError::UnknownError)? { let data = data?; - let attributes = &[ - metrics::request::add_attributes("metric_type", metric.to_string()), - metrics::request::add_attributes("source", pool.to_string()), - ]; + let attributes = &add_attributes([ + ("metric_type", metric.to_string()), + ("source", pool.to_string()), + ]); let value = u64::try_from(data.len()); if let Ok(val) = value { diff --git a/crates/analytics/src/metrics/request.rs b/crates/analytics/src/metrics/request.rs index 3d1a78808f34..39375d391a3e 100644 --- a/crates/analytics/src/metrics/request.rs +++ b/crates/analytics/src/metrics/request.rs @@ -1,9 +1,6 @@ -pub fn add_attributes>( - key: &'static str, - value: T, -) -> router_env::opentelemetry::KeyValue { - router_env::opentelemetry::KeyValue::new(key, value) -} +use std::time; + +use router_env::metrics::add_attributes; #[inline] pub async fn record_operation_time( @@ -17,10 +14,10 @@ where T: ToString, { let (result, time) = time_future(future).await; - let attributes = &[ - add_attributes("metric_name", metric_name.to_string()), - add_attributes("source", source.to_string()), - ]; + let attributes = &add_attributes([ + ("metric_name", metric_name.to_string()), + ("source", source.to_string()), + ]); let value = time.as_secs_f64(); metric.record(&super::CONTEXT, value, attributes); @@ -28,8 +25,6 @@ where result } -use std::time; - #[inline] pub async fn time_future(future: F) -> (R, time::Duration) where diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs index a3f24b65a17e..2508866626a3 100644 --- a/crates/analytics/src/payments/core.rs +++ b/crates/analytics/src/payments/core.rs @@ -13,6 +13,7 @@ use common_utils::errors::CustomResult; use error_stack::ResultExt; use router_env::{ instrument, logger, + metrics::add_attributes, tracing::{self, Instrument}, }; @@ -120,10 +121,10 @@ pub async fn get_metrics( match task_type { TaskType::MetricTask(metric, data) => { let data = data?; - let attributes = &[ - metrics::request::add_attributes("metric_type", metric.to_string()), - metrics::request::add_attributes("source", pool.to_string()), - ]; + let attributes = &add_attributes([ + ("metric_type", metric.to_string()), + ("source", pool.to_string()), + ]); let value = u64::try_from(data.len()); if let Ok(val) = value { @@ -172,10 +173,10 @@ pub async fn get_metrics( } TaskType::DistributionTask(distribution, data) => { let data = data?; - let attributes = &[ - metrics::request::add_attributes("distribution_type", distribution.to_string()), - metrics::request::add_attributes("source", pool.to_string()), - ]; + let attributes = &add_attributes([ + ("distribution_type", distribution.to_string()), + ("source", pool.to_string()), + ]); let value = u64::try_from(data.len()); if let Ok(val) = value { diff --git a/crates/analytics/src/refunds/core.rs b/crates/analytics/src/refunds/core.rs index b53d482e620a..57480c7cec77 100644 --- a/crates/analytics/src/refunds/core.rs +++ b/crates/analytics/src/refunds/core.rs @@ -11,6 +11,7 @@ use api_models::analytics::{ use error_stack::ResultExt; use router_env::{ logger, + metrics::add_attributes, tracing::{self, Instrument}, }; @@ -69,10 +70,10 @@ pub async fn get_metrics( .change_context(AnalyticsError::UnknownError)? { let data = data?; - let attributes = &[ - metrics::request::add_attributes("metric_type", metric.to_string()), - metrics::request::add_attributes("source", pool.to_string()), - ]; + let attributes = &add_attributes([ + ("metric_type", metric.to_string()), + ("source", pool.to_string()), + ]); let value = u64::try_from(data.len()); if let Ok(val) = value { diff --git a/crates/hyperswitch_interfaces/src/api.rs b/crates/hyperswitch_interfaces/src/api.rs index 63cbc6dabf88..ac397cfa0754 100644 --- a/crates/hyperswitch_interfaces/src/api.rs +++ b/crates/hyperswitch_interfaces/src/api.rs @@ -6,6 +6,7 @@ use common_utils::{ }; use hyperswitch_domain_models::router_data::{ErrorResponse, RouterData}; use masking::Maskable; +use router_env::metrics::add_attributes; use serde_json::json; use crate::{ @@ -87,7 +88,7 @@ pub trait ConnectorIntegration: ConnectorIntegrationAny>( - key: &'static str, - value: T, -) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(key, value) -} diff --git a/crates/router/src/connector/boku.rs b/crates/router/src/connector/boku.rs index 7c456d2ec1c2..d565cc6567eb 100644 --- a/crates/router/src/connector/boku.rs +++ b/crates/router/src/connector/boku.rs @@ -6,6 +6,7 @@ use diesel_models::enums; use error_stack::{report, Report, ResultExt}; use masking::{ExposeInterface, PeekInterface, Secret, WithType}; use ring::hmac; +use router_env::metrics::add_attributes; use roxmltree; use time::OffsetDateTime; use transformers as boku; @@ -665,7 +666,7 @@ fn get_xml_deserialized( metrics::RESPONSE_DESERIALIZATION_FAILURE.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes("connector", "boku")], + &add_attributes([("connector", "boku")]), ); let response_data = String::from_utf8(res.response.to_vec()) diff --git a/crates/router/src/connector/braintree.rs b/crates/router/src/connector/braintree.rs index f7e142a9af9d..750e2e6e3cc2 100644 --- a/crates/router/src/connector/braintree.rs +++ b/crates/router/src/connector/braintree.rs @@ -155,7 +155,7 @@ impl ConnectorCommon for Braintree { Err(error_msg) => { event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code}))); logger::error!(deserialization_error =? error_msg); - utils::handle_json_response_deserialization_failure(res, "braintree".to_owned()) + utils::handle_json_response_deserialization_failure(res, "braintree") } } } diff --git a/crates/router/src/connector/cybersource.rs b/crates/router/src/connector/cybersource.rs index 1f8de468846b..7bd3fa08dda7 100644 --- a/crates/router/src/connector/cybersource.rs +++ b/crates/router/src/connector/cybersource.rs @@ -229,10 +229,7 @@ impl ConnectorCommon for Cybersource { Err(error_msg) => { event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code}))); router_env::logger::error!(deserialization_error =? error_msg); - crate::utils::handle_json_response_deserialization_failure( - res, - "cybersource".to_owned(), - ) + crate::utils::handle_json_response_deserialization_failure(res, "cybersource") } } } diff --git a/crates/router/src/connector/noon.rs b/crates/router/src/connector/noon.rs index 23e15b2cfdcc..909f7a435c13 100644 --- a/crates/router/src/connector/noon.rs +++ b/crates/router/src/connector/noon.rs @@ -155,7 +155,7 @@ impl ConnectorCommon for Noon { Err(error_message) => { event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code}))); logger::error!(deserialization_error =? error_message); - utils::handle_json_response_deserialization_failure(res, "noon".to_owned()) + utils::handle_json_response_deserialization_failure(res, "noon") } } } diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index 397715d102db..88b2ec675959 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -111,7 +111,7 @@ impl ConnectorCommon for Payme { Err(error_msg) => { event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code}))); router_env::logger::error!(deserialization_error =? error_msg); - handle_json_response_deserialization_failure(res, "payme".to_owned()) + handle_json_response_deserialization_failure(res, "payme") } } } diff --git a/crates/router/src/connector/rapyd.rs b/crates/router/src/connector/rapyd.rs index 5d4579fffa75..f4bd09976271 100644 --- a/crates/router/src/connector/rapyd.rs +++ b/crates/router/src/connector/rapyd.rs @@ -114,7 +114,7 @@ impl ConnectorCommon for Rapyd { Err(error_msg) => { event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code}))); logger::error!(deserialization_error =? error_msg); - utils::handle_json_response_deserialization_failure(res, "rapyd".to_owned()) + utils::handle_json_response_deserialization_failure(res, "rapyd") } } } diff --git a/crates/router/src/connector/threedsecureio.rs b/crates/router/src/connector/threedsecureio.rs index 75a746648f10..a051cf471f19 100644 --- a/crates/router/src/connector/threedsecureio.rs +++ b/crates/router/src/connector/threedsecureio.rs @@ -126,10 +126,7 @@ impl ConnectorCommon for Threedsecureio { } Err(err) => { router_env::logger::error!(deserialization_error =? err); - utils::handle_json_response_deserialization_failure( - res, - "threedsecureio".to_owned(), - ) + utils::handle_json_response_deserialization_failure(res, "threedsecureio") } } } diff --git a/crates/router/src/connector/trustpay.rs b/crates/router/src/connector/trustpay.rs index 1f9e77de9cd2..e2904221e59c 100644 --- a/crates/router/src/connector/trustpay.rs +++ b/crates/router/src/connector/trustpay.rs @@ -153,7 +153,7 @@ impl ConnectorCommon for Trustpay { Err(error_msg) => { event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code}))); logger::error!(deserialization_error =? error_msg); - utils::handle_json_response_deserialization_failure(res, "trustpay".to_owned()) + utils::handle_json_response_deserialization_failure(res, "trustpay") } } } diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 71e913734548..b9ac5a02b7e0 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -15,6 +15,7 @@ use error_stack::{report, FutureExt, ResultExt}; use futures::future::try_join_all; use masking::{PeekInterface, Secret}; use pm_auth::connector::plaid::transformers::PlaidAuthType; +use router_env::metrics::add_attributes; use uuid::Uuid; use crate::{ @@ -1009,10 +1010,10 @@ pub async fn create_payment_connector( metrics::MCA_CREATE.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes("connector", req.connector_name.to_string()), - metrics::request::add_attributes("merchant", merchant_id.to_string()), - ], + &add_attributes([ + ("connector", req.connector_name.to_string()), + ("merchant", merchant_id.to_string()), + ]), ); let mca_response = mca.try_into()?; diff --git a/crates/router/src/core/api_keys.rs b/crates/router/src/core/api_keys.rs index ef81e3c190dd..5d41b9c18541 100644 --- a/crates/router/src/core/api_keys.rs +++ b/crates/router/src/core/api_keys.rs @@ -3,7 +3,7 @@ use common_utils::date_time; use diesel_models::{api_keys::ApiKey, enums as storage_enums}; use error_stack::{report, ResultExt}; use masking::{PeekInterface, StrongSecret}; -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; use crate::{ configs::settings, @@ -151,7 +151,7 @@ pub async fn create_api_key( metrics::API_KEY_CREATED.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes("merchant", merchant_id)], + &add_attributes([("merchant", merchant_id)]), ); // Add process to process_tracker for email reminder, only if expiry is set to future date @@ -236,7 +236,7 @@ pub async fn add_api_key_expiry_task( metrics::TASKS_ADDED_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes("flow", "ApiKeyExpiry")], + &add_attributes([("flow", "ApiKeyExpiry")]), ); Ok(()) diff --git a/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs index f484467f3547..9fa4b4782178 100644 --- a/crates/router/src/core/mandate.rs +++ b/crates/router/src/core/mandate.rs @@ -5,7 +5,7 @@ use common_utils::{ext_traits::Encode, id_type}; use diesel_models::{enums as storage_enums, Mandate}; use error_stack::{report, ResultExt}; use futures::future; -use router_env::{instrument, logger, tracing}; +use router_env::{instrument, logger, metrics::add_attributes, tracing}; use super::payments::helpers as payment_helper; use crate::{ @@ -404,10 +404,7 @@ where metrics::SUBSEQUENT_MANDATE_PAYMENT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - mandate.connector, - )], + &add_attributes([("connector", mandate.connector)]), ); Ok(Some(mandate_id.clone())) } @@ -463,7 +460,7 @@ where metrics::MANDATE_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes("connector", connector)], + &add_attributes([("connector", connector)]), ); Ok(Some(res_mandate_id)) } diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index ba2de78a6acb..f14997b20aa1 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -36,7 +36,7 @@ use euclid::{ use hyperswitch_constraint_graph as cgraph; use kgraph_utils::transformers::IntoDirValue; use masking::Secret; -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; use strum::IntoEnumIterator; use super::surcharge_decision_configs::{ @@ -3958,7 +3958,7 @@ impl TempLockerCardSupport { metrics::TASKS_ADDED_COUNT.add( &metrics::CONTEXT, 1, - &[request::add_attributes("flow", "DeleteTokenizeData")], + &add_attributes([("flow", "DeleteTokenizeData")]), ); Ok(card) } diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs index f37385b80c6f..4e17ec6abd3a 100644 --- a/crates/router/src/core/payment_methods/vault.rs +++ b/crates/router/src/core/payment_methods/vault.rs @@ -7,7 +7,7 @@ use common_utils::{ }; use error_stack::{report, ResultExt}; use masking::PeekInterface; -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; use scheduler::{types::process_data, utils as process_tracker_utils}; #[cfg(feature = "payouts")] @@ -1232,10 +1232,7 @@ pub async fn retry_delete_tokenize( metrics::TASKS_RESET_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "flow", - "DeleteTokenizeData", - )], + &add_attributes([("flow", "DeleteTokenizeData")]), ); retry_schedule } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index b4ac878d372c..d459fef935ec 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -42,7 +42,7 @@ pub use hyperswitch_domain_models::{ }; use masking::{ExposeInterface, Secret}; use redis_interface::errors::RedisError; -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; #[cfg(feature = "olap")] use router_types::transformers::ForeignFrom; use scheduler::utils as pt_utils; @@ -857,16 +857,13 @@ pub trait PaymentRedirectFlow: Sync { metrics::REDIRECTION_TRIGGERED.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( + &add_attributes([ + ( "connector", req.connector.to_owned().unwrap_or("null".to_string()), ), - metrics::request::add_attributes( - "merchant_id", - merchant_account.merchant_id.to_owned(), - ), - ], + ("merchant_id", merchant_account.merchant_id.to_owned()), + ]), ); let connector = req.connector.clone().get_required_value("connector")?; diff --git a/crates/router/src/core/payments/access_token.rs b/crates/router/src/core/payments/access_token.rs index 4241db6742da..a53a3d405a9d 100644 --- a/crates/router/src/core/payments/access_token.rs +++ b/crates/router/src/core/payments/access_token.rs @@ -2,6 +2,7 @@ use std::fmt::Debug; use common_utils::ext_traits::AsyncExt; use error_stack::ResultExt; +use router_env::metrics::add_attributes; use crate::{ consts, @@ -94,10 +95,7 @@ pub async fn add_access_token< metrics::ACCESS_TOKEN_CACHE_HIT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ); Ok(Some(access_token)) } @@ -105,10 +103,7 @@ pub async fn add_access_token< metrics::ACCESS_TOKEN_CACHE_MISS.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ); let cloned_router_data = router_data.clone(); @@ -247,10 +242,7 @@ pub async fn refresh_connector_auth( metrics::ACCESS_TOKEN_CREATION.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ); Ok(access_token_router_data) } diff --git a/crates/router/src/core/payments/customers.rs b/crates/router/src/core/payments/customers.rs index 448e5fedb8b1..67fdd7746af1 100644 --- a/crates/router/src/core/payments/customers.rs +++ b/crates/router/src/core/payments/customers.rs @@ -1,4 +1,4 @@ -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; use crate::{ core::{ @@ -54,10 +54,7 @@ pub async fn create_connector_customer( metrics::CONNECTOR_CUSTOMER_CREATE.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ); let connector_customer_id = match resp.response { diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index 7497ca6a9e5e..433274587a8d 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use router_env::metrics::add_attributes; // use router_env::tracing::Instrument; use super::{ConstructFlowSpecificData, Feature}; @@ -209,13 +210,10 @@ impl Feature for types::PaymentsAu metrics::EXECUTE_PRETASK_COUNT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - ), - metrics::request::add_attributes("flow", format!("{:?}", api::Authorize)), - ], + &add_attributes([ + ("connector", connector.connector_name.to_string()), + ("flow", format!("{:?}", api::Authorize)), + ]), ); logger::debug!(completed_pre_tasks=?true); @@ -333,13 +331,10 @@ pub async fn authorize_preprocessing_steps( metrics::PREPROCESSING_STEPS_COUNT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes("connector", connector.connector_name.to_string()), - metrics::request::add_attributes( - "payment_method", - router_data.payment_method.to_string(), - ), - metrics::request::add_attributes( + &add_attributes([ + ("connector", connector.connector_name.to_string()), + ("payment_method", router_data.payment_method.to_string()), + ( "payment_method_type", router_data .request @@ -348,7 +343,7 @@ pub async fn authorize_preprocessing_steps( .map(|inner| inner.to_string()) .unwrap_or("null".to_string()), ), - ], + ]), ); let mut authorize_router_data = helpers::router_data_type_conversion::<_, F, _, _, _, _>( resp.clone(), diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs index d7e8cc3d9b57..2a6774a91e29 100644 --- a/crates/router/src/core/payments/flows/cancel_flow.rs +++ b/crates/router/src/core/payments/flows/cancel_flow.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use router_env::metrics::add_attributes; use super::{ConstructFlowSpecificData, Feature}; use crate::{ @@ -55,10 +56,7 @@ impl Feature metrics::PAYMENT_CANCEL_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ); let connector_integration: services::BoxedConnectorIntegration< diff --git a/crates/router/src/core/payments/flows/complete_authorize_flow.rs b/crates/router/src/core/payments/flows/complete_authorize_flow.rs index 5d0cb9f9f381..bb2c959f2907 100644 --- a/crates/router/src/core/payments/flows/complete_authorize_flow.rs +++ b/crates/router/src/core/payments/flows/complete_authorize_flow.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use router_env::metrics::add_attributes; use super::{ConstructFlowSpecificData, Feature}; use crate::{ @@ -191,13 +192,10 @@ pub async fn complete_authorize_preprocessing_steps( metrics::PREPROCESSING_STEPS_COUNT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes("connector", connector.connector_name.to_string()), - metrics::request::add_attributes( - "payment_method", - router_data.payment_method.to_string(), - ), - ], + &add_attributes([ + ("connector", connector.connector_name.to_string()), + ("payment_method", router_data.payment_method.to_string()), + ]), ); let mut router_data_request = router_data.request.to_owned(); diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 14a3b9327dc0..e279e6f7c347 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -3,6 +3,7 @@ use async_trait::async_trait; use common_utils::{ext_traits::ByteSliceExt, request::RequestContent}; use error_stack::{Report, ResultExt}; use masking::ExposeInterface; +use router_env::metrics::add_attributes; use super::{ConstructFlowSpecificData, Feature}; use crate::{ @@ -64,10 +65,7 @@ impl Feature for types::PaymentsSessio metrics::SESSION_TOKEN_CREATED.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ); self.decide_flow( state, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 1a2f0a5cbaa4..0c696c1b8305 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -26,7 +26,7 @@ use openssl::{ pkey::PKey, symm::{decrypt_aead, Cipher}, }; -use router_env::{instrument, logger, tracing}; +use router_env::{instrument, logger, metrics::add_attributes, tracing}; use uuid::Uuid; use x509_parser::parse_x509_certificate; @@ -1219,10 +1219,7 @@ where metrics::TASKS_ADDED_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "flow", - format!("{:#?}", operation), - )], + &add_attributes([("flow", format!("{:#?}", operation))]), ); super::add_process_sync_task(&*state.store, payment_attempt, stime) .await @@ -1233,10 +1230,7 @@ where metrics::TASKS_RESET_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "flow", - format!("{:#?}", operation), - )], + &add_attributes([("flow", format!("{:#?}", operation))]), ); super::reset_process_sync_task(&*state.store, payment_attempt, stime) .await @@ -3406,10 +3400,7 @@ pub fn get_attempt_type( metrics::MANUAL_RETRY_REQUEST_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "merchant_id", - payment_attempt.merchant_id.clone(), - )], + &add_attributes([("merchant_id", payment_attempt.merchant_id.clone())]), ); match payment_attempt.status { enums::AttemptStatus::Started @@ -3433,10 +3424,7 @@ pub fn get_attempt_type( metrics::MANUAL_RETRY_VALIDATION_FAILED.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "merchant_id", - payment_attempt.merchant_id.clone(), - )], + &add_attributes([("merchant_id", payment_attempt.merchant_id.clone())]), ); Err(errors::ApiErrorResponse::InternalServerError) .attach_printable("Payment Attempt unexpected state") @@ -3448,10 +3436,7 @@ pub fn get_attempt_type( metrics::MANUAL_RETRY_VALIDATION_FAILED.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "merchant_id", - payment_attempt.merchant_id.clone(), - )], + &add_attributes([("merchant_id", payment_attempt.merchant_id.clone())]), ); Err(report!(errors::ApiErrorResponse::PreconditionFailed { message: @@ -3466,10 +3451,7 @@ pub fn get_attempt_type( metrics::MANUAL_RETRY_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "merchant_id", - payment_attempt.merchant_id.clone(), - )], + &add_attributes([("merchant_id", payment_attempt.merchant_id.clone())]), ); Ok(AttemptType::New) } diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 715963cdc912..54a4e20c89c5 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -8,7 +8,7 @@ use common_utils::{ }; use error_stack::{report, ResultExt}; use masking::ExposeInterface; -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; use super::helpers; use crate::{ @@ -806,16 +806,10 @@ pub async fn add_payment_method_token( metrics::CONNECTOR_PAYMENT_METHOD_TOKENIZATION.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - ), - metrics::request::add_attributes( - "payment_method", - router_data.payment_method.to_string(), - ), - ], + &add_attributes([ + ("connector", connector.connector_name.to_string()), + ("payment_method", router_data.payment_method.to_string()), + ]), ); let pm_token = match resp.response { diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 604bc5cda996..6b54427d87af 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -11,7 +11,7 @@ use common_utils::{consts::X_HS_LATENCY, fp_utils, types::MinorUnit}; use diesel_models::ephemeral_key; use error_stack::{report, ResultExt}; use masking::{Maskable, PeekInterface, Secret}; -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; use super::{flows::Feature, types::AuthenticationData, PaymentData}; use crate::{ @@ -844,12 +844,12 @@ where metrics::PAYMENT_OPS_COUNT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes("operation", format!("{:?}", operation)), - metrics::request::add_attributes("merchant", merchant_id), - metrics::request::add_attributes("payment_method_type", payment_method_type), - metrics::request::add_attributes("payment_method", payment_method), - ], + &add_attributes([ + ("operation", format!("{:?}", operation)), + ("merchant", merchant_id), + ("payment_method_type", payment_method_type), + ("payment_method", payment_method), + ]), ); Ok(output) diff --git a/crates/router/src/core/payouts/access_token.rs b/crates/router/src/core/payouts/access_token.rs index 5e40720f4efb..2f1892af821a 100644 --- a/crates/router/src/core/payouts/access_token.rs +++ b/crates/router/src/core/payouts/access_token.rs @@ -1,5 +1,6 @@ use common_utils::ext_traits::AsyncExt; use error_stack::ResultExt; +use router_env::metrics::add_attributes; use crate::{ consts, @@ -185,10 +186,7 @@ pub async fn refresh_connector_auth( metrics::ACCESS_TOKEN_CREATION.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ); Ok(access_token_router_data) } diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 164fd1ec7844..78b4762777f7 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -12,7 +12,7 @@ use common_utils::{ use diesel_models::process_tracker::business_status; use error_stack::{report, ResultExt}; use masking::PeekInterface; -use router_env::{instrument, tracing}; +use router_env::{instrument, metrics::add_attributes, tracing}; use scheduler::{consumer::types::process_data, utils as process_tracker_utils}; #[cfg(feature = "olap")] use strum::IntoEnumIterator; @@ -154,10 +154,7 @@ pub async fn trigger_refund_to_gateway( metrics::REFUND_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - routed_through.clone(), - )], + &add_attributes([("connector", routed_through.clone())]), ); let connector: api::ConnectorData = api::ConnectorData::get_connector_by_name( @@ -280,10 +277,7 @@ pub async fn trigger_refund_to_gateway( metrics::SUCCESSFUL_REFUND.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - connector.connector_name.to_string(), - )], + &add_attributes([("connector", connector.connector_name.to_string())]), ) } storage::RefundUpdate::Update { @@ -1246,11 +1240,7 @@ pub async fn add_refund_sync_task( refund.refund_id ) })?; - metrics::TASKS_ADDED_COUNT.add( - &metrics::CONTEXT, - 1, - &[metrics::request::add_attributes("flow", "Refund")], - ); + metrics::TASKS_ADDED_COUNT.add(&metrics::CONTEXT, 1, &add_attributes([("flow", "Refund")])); Ok(response) } diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index 2f1a37981ec6..503a67855d9d 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -10,7 +10,7 @@ use api_models::{ use common_utils::{errors::ReportSwitchExt, events::ApiEventsType}; use error_stack::{report, ResultExt}; use masking::ExposeInterface; -use router_env::{instrument, tracing, tracing_actix_web::RequestId}; +use router_env::{instrument, metrics::add_attributes, tracing, tracing_actix_web::RequestId}; use super::{types, utils, MERCHANT_ID}; use crate::{ @@ -25,9 +25,7 @@ use crate::{ logger, routes::{ app::{ReqState, SessionStateInfo}, - lock_utils, - metrics::request::add_attributes, - SessionState, + lock_utils, SessionState, }, services::{self, authentication as auth}, types::{ @@ -567,10 +565,7 @@ async fn payments_incoming_webhook_flow( metrics::WEBHOOK_PAYMENT_NOT_FOUND.add( &metrics::CONTEXT, 1, - &[add_attributes( - "merchant_id", - merchant_account.merchant_id.clone(), - )], + &add_attributes([("merchant_id", merchant_account.merchant_id.clone())]), ); return Ok(WebhookResponseTracker::NoEffect); } diff --git a/crates/router/src/core/webhooks/outgoing.rs b/crates/router/src/core/webhooks/outgoing.rs index 07fe78f51ceb..410d6c3d851c 100644 --- a/crates/router/src/core/webhooks/outgoing.rs +++ b/crates/router/src/core/webhooks/outgoing.rs @@ -8,6 +8,7 @@ use error_stack::{report, ResultExt}; use masking::{ExposeInterface, Mask, PeekInterface, Secret}; use router_env::{ instrument, + metrics::add_attributes, tracing::{self, Instrument}, }; @@ -22,7 +23,7 @@ use crate::{ db::StorageInterface, events::outgoing_webhook_logs::{OutgoingWebhookEvent, OutgoingWebhookEventMetric}, logger, - routes::{app::SessionStateInfo, metrics::request::add_attributes, SessionState}, + routes::{app::SessionStateInfo, SessionState}, services, types::{ api, @@ -501,7 +502,7 @@ pub(crate) async fn add_outgoing_webhook_retry_task_to_process_tracker( crate::routes::metrics::TASKS_ADDED_COUNT.add( &metrics::CONTEXT, 1, - &[add_attributes("flow", "OutgoingWebhookRetry")], + &add_attributes([("flow", "OutgoingWebhookRetry")]), ); Ok(process_tracker) } @@ -509,7 +510,7 @@ pub(crate) async fn add_outgoing_webhook_retry_task_to_process_tracker( crate::routes::metrics::TASK_ADDITION_FAILURES_COUNT.add( &metrics::CONTEXT, 1, - &[add_attributes("flow", "OutgoingWebhookRetry")], + &add_attributes([("flow", "OutgoingWebhookRetry")]), ); Err(error) } diff --git a/crates/router/src/routes/metrics.rs b/crates/router/src/routes/metrics.rs index eef85410981a..fffb5e20c9d9 100644 --- a/crates/router/src/routes/metrics.rs +++ b/crates/router/src/routes/metrics.rs @@ -2,7 +2,7 @@ pub mod bg_metrics_collector; pub mod request; pub mod utils; -use router_env::{counter_metric, gauge_metric, global_meter, histogram_metric, metrics_context}; +use router_env::{counter_metric, global_meter, histogram_metric, metrics_context}; metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); @@ -135,6 +135,3 @@ counter_metric!(ACCESS_TOKEN_CACHE_HIT, GLOBAL_METER); // A counter to indicate the access token cache miss counter_metric!(ACCESS_TOKEN_CACHE_MISS, GLOBAL_METER); - -// Metrics for In-memory cache -gauge_metric!(CACHE_ENTRY_COUNT, GLOBAL_METER); diff --git a/crates/router/src/routes/metrics/bg_metrics_collector.rs b/crates/router/src/routes/metrics/bg_metrics_collector.rs index 65cb7a13e5ef..52d7777f5aa8 100644 --- a/crates/router/src/routes/metrics/bg_metrics_collector.rs +++ b/crates/router/src/routes/metrics/bg_metrics_collector.rs @@ -2,40 +2,25 @@ use storage_impl::redis::cache; const DEFAULT_BG_METRICS_COLLECTION_INTERVAL_IN_SECS: u16 = 15; -macro_rules! gauge_metrics_for_imc { - ($($cache:ident),*) => { - $( - { - cache::$cache.run_pending_tasks().await; - - super::CACHE_ENTRY_COUNT.observe( - &super::CONTEXT, - cache::$cache.get_entry_count(), - &[super::request::add_attributes( - "cache_type", - stringify!($cache), - )], - ); - } - )* - }; -} - pub fn spawn_metrics_collector(metrics_collection_interval_in_secs: &Option) { let metrics_collection_interval = metrics_collection_interval_in_secs .unwrap_or(DEFAULT_BG_METRICS_COLLECTION_INTERVAL_IN_SECS); + let cache_instances = [ + &cache::CONFIG_CACHE, + &cache::ACCOUNTS_CACHE, + &cache::ROUTING_CACHE, + &cache::CGRAPH_CACHE, + &cache::PM_FILTERS_CGRAPH_CACHE, + &cache::DECISION_MANAGER_CACHE, + &cache::SURCHARGE_CACHE, + ]; + tokio::spawn(async move { loop { - gauge_metrics_for_imc!( - CONFIG_CACHE, - ACCOUNTS_CACHE, - ROUTING_CACHE, - CGRAPH_CACHE, - PM_FILTERS_CGRAPH_CACHE, - DECISION_MANAGER_CACHE, - SURCHARGE_CACHE - ); + for instance in cache_instances { + instance.record_entry_count_metric().await + } tokio::time::sleep(std::time::Duration::from_secs( metrics_collection_interval.into(), diff --git a/crates/router/src/routes/metrics/request.rs b/crates/router/src/routes/metrics/request.rs index ef53ad83f2cb..905f089a0c63 100644 --- a/crates/router/src/routes/metrics/request.rs +++ b/crates/router/src/routes/metrics/request.rs @@ -1,4 +1,4 @@ -use router_env::opentelemetry; +use router_env::{metrics::add_attributes, opentelemetry}; use super::utils as metric_utils; use crate::services::ApplicationResponse; @@ -11,12 +11,16 @@ where F: futures::Future, { let key = "request_type"; - super::REQUESTS_RECEIVED.add(&super::CONTEXT, 1, &[add_attributes(key, flow.to_string())]); + super::REQUESTS_RECEIVED.add( + &super::CONTEXT, + 1, + &add_attributes([(key, flow.to_string())]), + ); let (result, time) = metric_utils::time_future(future).await; super::REQUEST_TIME.record( &super::CONTEXT, time.as_secs_f64(), - &[add_attributes(key, flow.to_string())], + &add_attributes([(key, flow.to_string())]), ); result } @@ -35,22 +39,15 @@ where result } -pub fn add_attributes>( - key: &'static str, - value: T, -) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(key, value) -} - -pub fn status_code_metrics(status_code: i64, flow: String, merchant_id: String) { +pub fn status_code_metrics(status_code: String, flow: String, merchant_id: String) { super::REQUEST_STATUS.add( &super::CONTEXT, 1, - &[ - add_attributes("status_code", status_code), - add_attributes("flow", flow), - add_attributes("merchant_id", merchant_id), - ], + &add_attributes([ + ("status_code", status_code), + ("flow", flow), + ("merchant_id", merchant_id), + ]), ) } diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index cccbaa496e10..928b3a400eb6 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -29,7 +29,7 @@ pub use hyperswitch_interfaces::api::{ BoxedConnectorIntegration, CaptureSyncMethod, ConnectorIntegration, ConnectorIntegrationAny, }; use masking::{Maskable, PeekInterface}; -use router_env::{instrument, tracing, tracing_actix_web::RequestId, Tag}; +use router_env::{instrument, metrics::add_attributes, tracing, tracing_actix_web::RequestId, Tag}; use serde::Serialize; use serde_json::json; use tera::{Context, Tera}; @@ -178,9 +178,9 @@ where metrics::CONNECTOR_CALL_COUNT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes("connector", req.connector.to_string()), - metrics::request::add_attributes( + &add_attributes([ + ("connector", req.connector.to_string()), + ( "flow", std::any::type_name::() .split("::") @@ -188,7 +188,7 @@ where .unwrap_or_default() .to_string(), ), - ], + ]), ); let connector_request = match connector_request { @@ -204,10 +204,7 @@ where metrics::REQUEST_BUILD_FAILURE.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - req.connector.to_string(), - )], + &add_attributes([("connector", req.connector.to_string())]), ) } error @@ -272,10 +269,10 @@ where metrics::RESPONSE_DESERIALIZATION_FAILURE.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( + &add_attributes([( "connector", req.connector.to_string(), - )], + )]), ) } error @@ -313,10 +310,7 @@ where metrics::CONNECTOR_ERROR_RESPONSE_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes( - "connector", - req.connector.clone(), - )], + &add_attributes([("connector", req.connector.clone())]), ); let error = match body.status_code { @@ -915,7 +909,11 @@ where ); state.event_handler().log_event(&api_event); - metrics::request::status_code_metrics(status_code, flow.to_string(), merchant_id.to_string()); + metrics::request::status_code_metrics( + status_code.to_string(), + flow.to_string(), + merchant_id.to_string(), + ); output } diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index 701eda5d1c05..2aabed475b97 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -29,6 +29,7 @@ use image::Luma; use masking::ExposeInterface; use nanoid::nanoid; use qrcode; +use router_env::metrics::add_attributes; use serde::de::DeserializeOwned; use serde_json::Value; use tracing_futures::Instrument; @@ -553,12 +554,12 @@ pub async fn get_mca_from_object_reference_id( // validate json format for the error pub fn handle_json_response_deserialization_failure( res: types::Response, - connector: String, + connector: &'static str, ) -> CustomResult { metrics::RESPONSE_DESERIALIZATION_FAILURE.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes("connector", connector)], + &add_attributes([("connector", connector)]), ); let response_data = String::from_utf8(res.response.to_vec()) @@ -781,24 +782,24 @@ pub fn add_apple_pay_flow_metrics( domain::ApplePayFlow::Simplified(_) => metrics::APPLE_PAY_SIMPLIFIED_FLOW.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( + &add_attributes([ + ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - metrics::request::add_attributes("merchant_id", merchant_id.to_owned()), - ], + ("merchant_id", merchant_id.to_owned()), + ]), ), domain::ApplePayFlow::Manual => metrics::APPLE_PAY_MANUAL_FLOW.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( + &add_attributes([ + ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - metrics::request::add_attributes("merchant_id", merchant_id.to_owned()), - ], + ("merchant_id", merchant_id.to_owned()), + ]), ), } } @@ -817,26 +818,26 @@ pub fn add_apple_pay_payment_status_metrics( metrics::APPLE_PAY_SIMPLIFIED_FLOW_SUCCESSFUL_PAYMENT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( + &add_attributes([ + ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - metrics::request::add_attributes("merchant_id", merchant_id.to_owned()), - ], + ("merchant_id", merchant_id.to_owned()), + ]), ) } domain::ApplePayFlow::Manual => metrics::APPLE_PAY_MANUAL_FLOW_SUCCESSFUL_PAYMENT .add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( + &add_attributes([ + ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - metrics::request::add_attributes("merchant_id", merchant_id.to_owned()), - ], + ("merchant_id", merchant_id.to_owned()), + ]), ), } } @@ -847,25 +848,25 @@ pub fn add_apple_pay_payment_status_metrics( metrics::APPLE_PAY_SIMPLIFIED_FLOW_FAILED_PAYMENT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( + &add_attributes([ + ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - metrics::request::add_attributes("merchant_id", merchant_id.to_owned()), - ], + ("merchant_id", merchant_id.to_owned()), + ]), ) } domain::ApplePayFlow::Manual => metrics::APPLE_PAY_MANUAL_FLOW_FAILED_PAYMENT.add( &metrics::CONTEXT, 1, - &[ - metrics::request::add_attributes( + &add_attributes([ + ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - metrics::request::add_attributes("merchant_id", merchant_id.to_owned()), - ], + ("merchant_id", merchant_id.to_owned()), + ]), ), } } diff --git a/crates/router/src/workflows/api_key_expiry.rs b/crates/router/src/workflows/api_key_expiry.rs index c24671be34d1..8d8f1aa6c857 100644 --- a/crates/router/src/workflows/api_key_expiry.rs +++ b/crates/router/src/workflows/api_key_expiry.rs @@ -2,7 +2,7 @@ use common_utils::{errors::ValidationError, ext_traits::ValueExt}; use diesel_models::{ enums as storage_enums, process_tracker::business_status, ApiKeyExpiryTrackingData, }; -use router_env::logger; +use router_env::{logger, metrics::add_attributes}; use scheduler::{workflows::ProcessTrackerWorkflow, SchedulerSessionState}; use crate::{ @@ -130,7 +130,7 @@ impl ProcessTrackerWorkflow for ApiKeyExpiryWorkflow { metrics::TASKS_RESET_COUNT.add( &metrics::CONTEXT, 1, - &[metrics::request::add_attributes("flow", "ApiKeyExpiry")], + &add_attributes([("flow", "ApiKeyExpiry")]), ); } diff --git a/crates/router_env/src/metrics.rs b/crates/router_env/src/metrics.rs index e75cacaa3c95..780c010579f7 100644 --- a/crates/router_env/src/metrics.rs +++ b/crates/router_env/src/metrics.rs @@ -120,3 +120,18 @@ macro_rules! gauge_metric { > = once_cell::sync::Lazy::new(|| $meter.u64_observable_gauge($description).init()); }; } + +pub use helpers::add_attributes; + +mod helpers { + pub fn add_attributes(attributes: U) -> Vec + where + T: Into, + U: IntoIterator, + { + attributes + .into_iter() + .map(|(key, value)| opentelemetry::KeyValue::new(key, value)) + .collect::>() + } +} diff --git a/crates/storage_impl/src/metrics.rs b/crates/storage_impl/src/metrics.rs index 2f22d578133e..cb7a6b216e47 100644 --- a/crates/storage_impl/src/metrics.rs +++ b/crates/storage_impl/src/metrics.rs @@ -1,4 +1,4 @@ -use router_env::{counter_metric, global_meter, metrics_context}; +use router_env::{counter_metric, gauge_metric, global_meter, metrics_context}; metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); @@ -11,3 +11,9 @@ counter_metric!(KV_OPERATION_FAILED, GLOBAL_METER); counter_metric!(KV_PUSHED_TO_DRAINER, GLOBAL_METER); counter_metric!(KV_FAILED_TO_PUSH_TO_DRAINER, GLOBAL_METER); counter_metric!(KV_SOFT_KILL_ACTIVE_UPDATE, GLOBAL_METER); + +// Metrics for In-memory cache +gauge_metric!(IN_MEMORY_CACHE_ENTRY_COUNT, GLOBAL_METER); +counter_metric!(IN_MEMORY_CACHE_HIT, GLOBAL_METER); +counter_metric!(IN_MEMORY_CACHE_MISS, GLOBAL_METER); +counter_metric!(IN_MEMORY_CACHE_EVICTION_COUNT, GLOBAL_METER); diff --git a/crates/storage_impl/src/redis/cache.rs b/crates/storage_impl/src/redis/cache.rs index 6ad96be27950..81e7e38b1be0 100644 --- a/crates/storage_impl/src/redis/cache.rs +++ b/crates/storage_impl/src/redis/cache.rs @@ -9,10 +9,14 @@ use error_stack::{Report, ResultExt}; use moka::future::Cache as MokaCache; use once_cell::sync::Lazy; use redis_interface::{errors::RedisError, RedisConnectionPool, RedisValue}; -use router_env::tracing::{self, instrument}; +use router_env::{ + metrics::add_attributes, + tracing::{self, instrument}, +}; use crate::{ errors::StorageError, + metrics, redis::{PubSubInterface, RedisConnInterface}, }; @@ -53,31 +57,44 @@ const CACHE_TTI: u64 = 10 * 60; const MAX_CAPACITY: u64 = 30; /// Config Cache with time_to_live as 30 mins and time_to_idle as 10 mins. -pub static CONFIG_CACHE: Lazy = Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, None)); +pub static CONFIG_CACHE: Lazy = + Lazy::new(|| Cache::new("CONFIG_CACHE", CACHE_TTL, CACHE_TTI, None)); /// Accounts cache with time_to_live as 30 mins and size limit pub static ACCOUNTS_CACHE: Lazy = - Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); + Lazy::new(|| Cache::new("ACCOUNTS_CACHE", CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); /// Routing Cache pub static ROUTING_CACHE: Lazy = - Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); + Lazy::new(|| Cache::new("ROUTING_CACHE", CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); /// 3DS Decision Manager Cache -pub static DECISION_MANAGER_CACHE: Lazy = - Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); +pub static DECISION_MANAGER_CACHE: Lazy = Lazy::new(|| { + Cache::new( + "DECISION_MANAGER_CACHE", + CACHE_TTL, + CACHE_TTI, + Some(MAX_CAPACITY), + ) +}); /// Surcharge Cache pub static SURCHARGE_CACHE: Lazy = - Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); + Lazy::new(|| Cache::new("SURCHARGE_CACHE", CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); /// CGraph Cache pub static CGRAPH_CACHE: Lazy = - Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); + Lazy::new(|| Cache::new("CGRAPH_CACHE", CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); /// PM Filter CGraph Cache -pub static PM_FILTERS_CGRAPH_CACHE: Lazy = - Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); +pub static PM_FILTERS_CGRAPH_CACHE: Lazy = Lazy::new(|| { + Cache::new( + "PM_FILTERS_CGRAPH_CACHE", + CACHE_TTL, + CACHE_TTI, + Some(MAX_CAPACITY), + ) +}); /// Trait which defines the behaviour of types that's gonna be stored in Cache pub trait Cacheable: Any + Send + Sync + DynClone { @@ -150,6 +167,7 @@ where dyn_clone::clone_trait_object!(Cacheable); pub struct Cache { + name: &'static str, inner: MokaCache>, } @@ -173,19 +191,38 @@ impl From for String { impl Cache { /// With given `time_to_live` and `time_to_idle` creates a moka cache. /// + /// `name` : Cache type name to be used as an attribute in metrics /// `time_to_live`: Time in seconds before an object is stored in a caching system before it’s deleted /// `time_to_idle`: Time in seconds before a `get` or `insert` operation an object is stored in a caching system before it's deleted /// `max_capacity`: Max size in MB's that the cache can hold - pub fn new(time_to_live: u64, time_to_idle: u64, max_capacity: Option) -> Self { + pub fn new( + name: &'static str, + time_to_live: u64, + time_to_idle: u64, + max_capacity: Option, + ) -> Self { + // Record the metrics of manual invalidation of cache entry by the application + let eviction_listener = move |_, _, cause| { + metrics::IN_MEMORY_CACHE_EVICTION_COUNT.add( + &metrics::CONTEXT, + 1, + &add_attributes([ + ("cache_type", name.to_owned()), + ("removal_cause", format!("{:?}", cause)), + ]), + ); + }; let mut cache_builder = MokaCache::builder() .time_to_live(std::time::Duration::from_secs(time_to_live)) - .time_to_idle(std::time::Duration::from_secs(time_to_idle)); + .time_to_idle(std::time::Duration::from_secs(time_to_idle)) + .eviction_listener(eviction_listener); if let Some(capacity) = max_capacity { cache_builder = cache_builder.max_capacity(capacity * 1024 * 1024); } Self { + name, inner: cache_builder.build(), } } @@ -195,8 +232,26 @@ impl Cache { } pub async fn get_val(&self, key: CacheKey) -> Option { - let val = self.inner.get::(&key.into()).await?; - (*val).as_any().downcast_ref::().cloned() + let val = self.inner.get::(&key.into()).await; + + // Add cache hit and cache miss metrics + if val.is_some() { + metrics::IN_MEMORY_CACHE_HIT.add( + &metrics::CONTEXT, + 1, + &add_attributes([("cache_type", self.name)]), + ); + } else { + metrics::IN_MEMORY_CACHE_MISS.add( + &metrics::CONTEXT, + 1, + &add_attributes([("cache_type", self.name)]), + ); + } + + let val = (*val?).as_any().downcast_ref::().cloned(); + + val } /// Check if a key exists in cache @@ -209,14 +264,28 @@ impl Cache { } /// Performs any pending maintenance operations needed by the cache. - pub async fn run_pending_tasks(&self) { + async fn run_pending_tasks(&self) { self.inner.run_pending_tasks().await; } /// Returns an approximate number of entries in this cache. - pub fn get_entry_count(&self) -> u64 { + fn get_entry_count(&self) -> u64 { self.inner.entry_count() } + + pub fn name(&self) -> &'static str { + self.name + } + + pub async fn record_entry_count_metric(&self) { + self.run_pending_tasks().await; + + metrics::IN_MEMORY_CACHE_ENTRY_COUNT.observe( + &metrics::CONTEXT, + self.get_entry_count(), + &add_attributes([("cache_type", self.name)]), + ); + } } #[instrument(skip_all)] @@ -390,7 +459,7 @@ mod cache_tests { #[tokio::test] async fn construct_and_get_cache() { - let cache = Cache::new(1800, 1800, None); + let cache = Cache::new("test", 1800, 1800, None); cache .push( CacheKey { @@ -413,7 +482,7 @@ mod cache_tests { #[tokio::test] async fn eviction_on_size_test() { - let cache = Cache::new(2, 2, Some(0)); + let cache = Cache::new("test", 2, 2, Some(0)); cache .push( CacheKey { @@ -436,7 +505,7 @@ mod cache_tests { #[tokio::test] async fn invalidate_cache_for_key() { - let cache = Cache::new(1800, 1800, None); + let cache = Cache::new("test", 1800, 1800, None); cache .push( CacheKey { @@ -467,7 +536,7 @@ mod cache_tests { #[tokio::test] async fn eviction_on_time_test() { - let cache = Cache::new(2, 2, None); + let cache = Cache::new("test", 2, 2, None); cache .push( CacheKey {