Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(analytics): three_ds and authentication events in sdkevents #4251

Merged
merged 4 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/analytics/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ impl_to_sql_for_to_string!(&DisputeDimensions, DisputeDimensions, DisputeStage);
#[derive(Debug)]
pub enum FilterTypes {
Equal,
NotEqual,
EqualBool,
In,
Gte,
Expand All @@ -402,6 +403,7 @@ pub fn filter_type_to_sql(l: &String, op: &FilterTypes, r: &String) -> String {
match op {
FilterTypes::EqualBool => format!("{l} = {r}"),
FilterTypes::Equal => format!("{l} = '{r}'"),
FilterTypes::NotEqual => format!("{l} != '{r}'"),
FilterTypes::In => format!("{l} IN ({r})"),
FilterTypes::Gte => format!("{l} >= '{r}'"),
FilterTypes::Gt => format!("{l} > {r}"),
Expand Down
16 changes: 14 additions & 2 deletions crates/analytics/src/sdk_events/accumulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ use super::metrics::SdkEventMetricRow;
#[derive(Debug, Default)]
pub struct SdkEventMetricsAccumulator {
pub payment_attempts: CountAccumulator,
pub payment_success: CountAccumulator,
pub payment_methods_call_count: CountAccumulator,
pub average_payment_time: AverageAccumulator,
pub sdk_initiated_count: CountAccumulator,
pub sdk_rendered_count: CountAccumulator,
pub payment_method_selected_count: CountAccumulator,
pub payment_data_filled_count: CountAccumulator,
pub three_ds_method_invoked_count: CountAccumulator,
pub three_ds_method_skipped_count: CountAccumulator,
pub three_ds_method_successful_count: CountAccumulator,
pub three_ds_method_unsuccessful_count: CountAccumulator,
pub authentication_unsuccessful_count: CountAccumulator,
pub three_ds_challenge_flow_count: CountAccumulator,
pub three_ds_frictionless_flow_count: CountAccumulator,
}

#[derive(Debug, Default)]
Expand Down Expand Up @@ -86,13 +92,19 @@ impl SdkEventMetricsAccumulator {
pub fn collect(self) -> SdkEventMetricsBucketValue {
SdkEventMetricsBucketValue {
payment_attempts: self.payment_attempts.collect(),
payment_success_count: self.payment_success.collect(),
payment_methods_call_count: self.payment_methods_call_count.collect(),
average_payment_time: self.average_payment_time.collect(),
sdk_initiated_count: self.sdk_initiated_count.collect(),
sdk_rendered_count: self.sdk_rendered_count.collect(),
payment_method_selected_count: self.payment_method_selected_count.collect(),
payment_data_filled_count: self.payment_data_filled_count.collect(),
three_ds_method_invoked_count: self.three_ds_method_invoked_count.collect(),
three_ds_method_skipped_count: self.three_ds_method_skipped_count.collect(),
three_ds_method_successful_count: self.three_ds_method_successful_count.collect(),
three_ds_method_unsuccessful_count: self.three_ds_method_unsuccessful_count.collect(),
authentication_unsuccessful_count: self.authentication_unsuccessful_count.collect(),
three_ds_challenge_flow_count: self.three_ds_challenge_flow_count.collect(),
three_ds_frictionless_flow_count: self.three_ds_frictionless_flow_count.collect(),
}
}
}
24 changes: 21 additions & 3 deletions crates/analytics/src/sdk_events/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,6 @@ pub async fn get_metrics(
SdkEventMetrics::PaymentAttempts => {
metrics_builder.payment_attempts.add_metrics_bucket(&value)
}
SdkEventMetrics::PaymentSuccessCount => {
metrics_builder.payment_success.add_metrics_bucket(&value)
}
SdkEventMetrics::PaymentMethodsCallCount => metrics_builder
.payment_methods_call_count
.add_metrics_bucket(&value),
Expand All @@ -109,6 +106,27 @@ pub async fn get_metrics(
SdkEventMetrics::AveragePaymentTime => metrics_builder
.average_payment_time
.add_metrics_bucket(&value),
SdkEventMetrics::ThreeDsMethodInvokedCount => metrics_builder
.three_ds_method_invoked_count
.add_metrics_bucket(&value),
SdkEventMetrics::ThreeDsMethodSkippedCount => metrics_builder
.three_ds_method_skipped_count
.add_metrics_bucket(&value),
SdkEventMetrics::ThreeDsMethodSuccessfulCount => metrics_builder
.three_ds_method_successful_count
.add_metrics_bucket(&value),
SdkEventMetrics::ThreeDsMethodUnsuccessfulCount => metrics_builder
.three_ds_method_unsuccessful_count
.add_metrics_bucket(&value),
SdkEventMetrics::AuthenticationUnsuccessfulCount => metrics_builder
.authentication_unsuccessful_count
.add_metrics_bucket(&value),
SdkEventMetrics::ThreeDsChallengeFlowCount => metrics_builder
.three_ds_challenge_flow_count
.add_metrics_bucket(&value),
SdkEventMetrics::ThreeDsFrictionlessFlowCount => metrics_builder
.three_ds_frictionless_flow_count
.add_metrics_bucket(&value),
}
}

Expand Down
112 changes: 98 additions & 14 deletions crates/analytics/src/sdk_events/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,35 @@ use crate::{
types::{AnalyticsCollection, AnalyticsDataSource, LoadRow, MetricsResult},
};

mod authentication_unsuccessful_count;
mod average_payment_time;
mod payment_attempts;
mod payment_data_filled_count;
mod payment_method_selected_count;
mod payment_methods_call_count;
mod payment_success_count;
mod sdk_initiated_count;
mod sdk_rendered_count;
mod three_ds_challenge_flow_count;
mod three_ds_frictionless_flow_count;
mod three_ds_method_invoked_count;
mod three_ds_method_skipped_count;
mod three_ds_method_successful_count;
mod three_ds_method_unsuccessful_count;

use authentication_unsuccessful_count::AuthenticationUnsuccessfulCount;
use average_payment_time::AveragePaymentTime;
use payment_attempts::PaymentAttempts;
use payment_data_filled_count::PaymentDataFilledCount;
use payment_method_selected_count::PaymentMethodSelectedCount;
use payment_methods_call_count::PaymentMethodsCallCount;
use payment_success_count::PaymentSuccessCount;
use sdk_initiated_count::SdkInitiatedCount;
use sdk_rendered_count::SdkRenderedCount;
use three_ds_challenge_flow_count::ThreeDsChallengeFlowCount;
use three_ds_frictionless_flow_count::ThreeDsFrictionlessFlowCount;
use three_ds_method_invoked_count::ThreeDsMethodInvokedCount;
use three_ds_method_skipped_count::ThreeDsMethodSkippedCount;
use three_ds_method_successful_count::ThreeDsMethodSuccessfulCount;
use three_ds_method_unsuccessful_count::ThreeDsMethodUnsuccessfulCount;

#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
pub struct SdkEventMetricRow {
Expand Down Expand Up @@ -92,18 +104,6 @@ where
)
.await
}
Self::PaymentSuccessCount => {
PaymentSuccessCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
Self::PaymentMethodsCallCount => {
PaymentMethodsCallCount
.load_metrics(
Expand Down Expand Up @@ -176,6 +176,90 @@ where
)
.await
}
Self::ThreeDsMethodSkippedCount => {
ThreeDsMethodSkippedCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
Self::ThreeDsMethodInvokedCount => {
ThreeDsMethodInvokedCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
Self::ThreeDsMethodSuccessfulCount => {
ThreeDsMethodSuccessfulCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
Self::ThreeDsMethodUnsuccessfulCount => {
ThreeDsMethodUnsuccessfulCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
Self::AuthenticationUnsuccessfulCount => {
AuthenticationUnsuccessfulCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
Self::ThreeDsChallengeFlowCount => {
ThreeDsChallengeFlowCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
Self::ThreeDsFrictionlessFlowCount => {
ThreeDsFrictionlessFlowCount
.load_metrics(
dimensions,
publishable_key,
filters,
granularity,
time_range,
pool,
)
.await
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use api_models::analytics::{
sdk_events::{
SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
},
Granularity, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::SdkEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(super) struct AuthenticationUnsuccessfulCount;

#[async_trait::async_trait]
impl<T> super::SdkEventMetric<T> for AuthenticationUnsuccessfulCount
where
T: AnalyticsDataSource + super::SdkEventMetricAnalytics,
PrimitiveDateTime: ToSql<T>,
AnalyticsCollection: ToSql<T>,
Granularity: GroupByClause<T>,
Aggregate<&'static str>: ToSql<T>,
Window<&'static str>: ToSql<T>,
{
async fn load_metrics(
&self,
dimensions: &[SdkEventDimensions],
publishable_key: &str,
filters: &SdkEventFilters,
granularity: &Option<Granularity>,
time_range: &TimeRange,
pool: &T,
) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::SdkEvents);
let dimensions = dimensions.to_vec();

for dim in dimensions.iter() {
query_builder.add_select_column(dim).switch()?;
}

query_builder
.add_select_column(Aggregate::Count {
field: None,
alias: Some("count"),
})
.switch()?;

if let Some(granularity) = granularity.as_ref() {
query_builder
.add_granularity_in_mins(granularity)
.switch()?;
}

filters.set_filter_clause(&mut query_builder).switch()?;

query_builder
.add_filter_clause("merchant_id", publishable_key)
.switch()?;

query_builder
.add_filter_clause("event_name", SdkEventNames::AuthenticationCall)
.switch()?;

query_builder
.add_filter_clause("log_type", "ERROR")
.switch()?;

query_builder
.add_filter_clause("category", "USER_EVENT")
.switch()?;

time_range
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;

for dim in dimensions.iter() {
query_builder
.add_group_by_clause(dim)
.attach_printable("Error grouping by dimensions")
.switch()?;
}

if let Some(_granularity) = granularity.as_ref() {
query_builder
.add_group_by_clause("time_bucket")
.attach_printable("Error adding granularity")
.switch()?;
}

query_builder
.execute_query::<SdkEventMetricRow, _>(pool)
.await
.change_context(MetricsError::QueryBuildingError)?
.change_context(MetricsError::QueryExecutionFailure)?
.into_iter()
.map(|i| {
Ok((
SdkEventMetricsBucketIdentifier::new(
i.payment_method.clone(),
i.platform.clone(),
i.browser_name.clone(),
i.source.clone(),
i.component.clone(),
i.payment_experience.clone(),
i.time_bucket.clone(),
),
i,
))
})
.collect::<error_stack::Result<
Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
crate::query::PostProcessingError,
>>()
.change_context(MetricsError::PostProcessingFailure)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ where
.switch()?;

query_builder
.add_filter_clause("event_name", SdkEventNames::StripeElementsCalled)
.add_filter_clause("event_name", SdkEventNames::OrcaElementsCalled)
.switch()?;

time_range
Expand Down
Loading
Loading