feat(analytics): add new filters, dimensions and metrics for authentication analytics (#7451)

Co-authored-by: Sandeep Kumar <sandeep.kumar@Sandeep-Kumar-LVF93XQXPC.local>
This commit is contained in:
Sandeep Kumar
2025-03-06 21:49:44 +05:30
committed by GitHub
parent 957a228525
commit 7473182b30
27 changed files with 1177 additions and 81 deletions

View File

@ -7,7 +7,7 @@ use masking::Secret;
use self::{
active_payments::ActivePaymentsMetrics,
api_event::{ApiEventDimensions, ApiEventMetrics},
auth_events::AuthEventMetrics,
auth_events::{AuthEventDimensions, AuthEventFilters, AuthEventMetrics},
disputes::{DisputeDimensions, DisputeMetrics},
frm::{FrmDimensions, FrmMetrics},
payment_intents::{PaymentIntentDimensions, PaymentIntentMetrics},
@ -226,6 +226,10 @@ pub struct GetAuthEventMetricRequest {
pub time_series: Option<TimeSeries>,
pub time_range: TimeRange,
#[serde(default)]
pub group_by_names: Vec<AuthEventDimensions>,
#[serde(default)]
pub filters: AuthEventFilters,
#[serde(default)]
pub metrics: HashSet<AuthEventMetrics>,
#[serde(default)]
pub delta: bool,
@ -509,3 +513,36 @@ pub struct SankeyResponse {
pub dispute_status: Option<String>,
pub first_attempt: i64,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetAuthEventFilterRequest {
pub time_range: TimeRange,
#[serde(default)]
pub group_by_names: Vec<AuthEventDimensions>,
}
#[derive(Debug, Default, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthEventFiltersResponse {
pub query_data: Vec<AuthEventFilterValue>,
}
#[derive(Debug, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AuthEventFilterValue {
pub dimension: AuthEventDimensions,
pub values: Vec<String>,
}
#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthEventMetricsResponse<T> {
pub query_data: Vec<T>,
pub meta_data: [AuthEventsAnalyticsMetadata; 1],
}
#[derive(Debug, serde::Serialize)]
pub struct AuthEventsAnalyticsMetadata {
pub total_error_message_count: Option<u64>,
}

View File

@ -3,7 +3,23 @@ use std::{
hash::{Hash, Hasher},
};
use super::NameDescription;
use common_enums::{AuthenticationConnectors, AuthenticationStatus, TransactionStatus};
use super::{NameDescription, TimeRange};
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct AuthEventFilters {
#[serde(default)]
pub authentication_status: Vec<AuthenticationStatus>,
#[serde(default)]
pub trans_status: Vec<TransactionStatus>,
#[serde(default)]
pub error_message: Vec<String>,
#[serde(default)]
pub authentication_connector: Vec<AuthenticationConnectors>,
#[serde(default)]
pub message_version: Vec<String>,
}
#[derive(
Debug,
@ -22,10 +38,13 @@ use super::NameDescription;
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum AuthEventDimensions {
#[serde(rename = "authentication_status")]
AuthenticationStatus,
#[strum(serialize = "trans_status")]
#[serde(rename = "trans_status")]
TransactionStatus,
ErrorMessage,
AuthenticationConnector,
MessageVersion,
}
#[derive(
@ -51,6 +70,8 @@ pub enum AuthEventMetrics {
FrictionlessSuccessCount,
ChallengeAttemptCount,
ChallengeSuccessCount,
AuthenticationErrorMessage,
AuthenticationFunnel,
}
#[derive(
@ -79,6 +100,7 @@ pub mod metric_behaviour {
pub struct FrictionlessSuccessCount;
pub struct ChallengeAttemptCount;
pub struct ChallengeSuccessCount;
pub struct AuthenticationErrorMessage;
}
impl From<AuthEventMetrics> for NameDescription {
@ -90,19 +112,58 @@ impl From<AuthEventMetrics> for NameDescription {
}
}
impl From<AuthEventDimensions> for NameDescription {
fn from(value: AuthEventDimensions) -> Self {
Self {
name: value.to_string(),
desc: String::new(),
}
}
}
#[derive(Debug, serde::Serialize, Eq)]
pub struct AuthEventMetricsBucketIdentifier {
pub time_bucket: Option<String>,
pub authentication_status: Option<AuthenticationStatus>,
pub trans_status: Option<TransactionStatus>,
pub error_message: Option<String>,
pub authentication_connector: Option<AuthenticationConnectors>,
pub message_version: Option<String>,
#[serde(rename = "time_range")]
pub time_bucket: TimeRange,
#[serde(rename = "time_bucket")]
#[serde(with = "common_utils::custom_serde::iso8601custom")]
pub start_time: time::PrimitiveDateTime,
}
impl AuthEventMetricsBucketIdentifier {
pub fn new(time_bucket: Option<String>) -> Self {
Self { time_bucket }
#[allow(clippy::too_many_arguments)]
pub fn new(
authentication_status: Option<AuthenticationStatus>,
trans_status: Option<TransactionStatus>,
error_message: Option<String>,
authentication_connector: Option<AuthenticationConnectors>,
message_version: Option<String>,
normalized_time_range: TimeRange,
) -> Self {
Self {
authentication_status,
trans_status,
error_message,
authentication_connector,
message_version,
time_bucket: normalized_time_range,
start_time: normalized_time_range.start_time,
}
}
}
impl Hash for AuthEventMetricsBucketIdentifier {
fn hash<H: Hasher>(&self, state: &mut H) {
self.authentication_status.hash(state);
self.trans_status.hash(state);
self.authentication_connector.hash(state);
self.message_version.hash(state);
self.error_message.hash(state);
self.time_bucket.hash(state);
}
}
@ -127,6 +188,8 @@ pub struct AuthEventMetricsBucketValue {
pub challenge_success_count: Option<u64>,
pub frictionless_flow_count: Option<u64>,
pub frictionless_success_count: Option<u64>,
pub error_message_count: Option<u64>,
pub authentication_funnel: Option<u64>,
}
#[derive(Debug, serde::Serialize)]

View File

@ -113,10 +113,12 @@ impl_api_event_type!(
GetActivePaymentsMetricRequest,
GetSdkEventMetricRequest,
GetAuthEventMetricRequest,
GetAuthEventFilterRequest,
GetPaymentFiltersRequest,
PaymentFiltersResponse,
GetRefundFilterRequest,
RefundFiltersResponse,
AuthEventFiltersResponse,
GetSdkEventFiltersRequest,
SdkEventFiltersResponse,
ApiLogsRequest,
@ -180,6 +182,13 @@ impl<T> ApiEventMetric for DisputesMetricsResponse<T> {
Some(ApiEventsType::Miscellaneous)
}
}
impl<T> ApiEventMetric for AuthEventMetricsResponse<T> {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Miscellaneous)
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl ApiEventMetric for PaymentMethodIntentConfirmInternal {
fn get_api_event_type(&self) -> Option<ApiEventsType> {