diff --git a/crates/meilisearch/src/routes/export.rs b/crates/meilisearch/src/routes/export.rs index 1c519224c..21a77ae32 100644 --- a/crates/meilisearch/src/routes/export.rs +++ b/crates/meilisearch/src/routes/export.rs @@ -22,6 +22,7 @@ use utoipa::{OpenApi, ToSchema}; use crate::analytics::Analytics; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; +use crate::routes::export_analytics::ExportAnalytics; use crate::routes::{get_task_id, is_dry_run, SummarizedTaskView}; use crate::Opt; @@ -67,7 +68,7 @@ async fn export( export: AwebJson, req: HttpRequest, opt: web::Data, - _analytics: Data, + analytics: Data, ) -> Result { // TODO make it experimental? // index_scheduler.features().check_network("Using the /network route")?; @@ -75,6 +76,8 @@ async fn export( let export = export.into_inner(); debug!(returns = ?export, "Trigger export"); + let analytics_aggregate = ExportAnalytics::from_export(&export); + let Export { url, api_key, payload_size, indexes } = export; let indexes = if indexes.is_empty() { @@ -101,6 +104,8 @@ async fn export( .await?? .into(); + analytics.publish(analytics_aggregate, &req); + Ok(HttpResponse::Ok().json(task)) } diff --git a/crates/meilisearch/src/routes/export_analytics.rs b/crates/meilisearch/src/routes/export_analytics.rs new file mode 100644 index 000000000..7299dba8d --- /dev/null +++ b/crates/meilisearch/src/routes/export_analytics.rs @@ -0,0 +1,67 @@ +use crate::analytics::Aggregate; +use crate::routes::export::Export; + +#[derive(Default)] +pub struct ExportAnalytics { + total_received: usize, + has_api_key: bool, + total_index_patterns: usize, + total_patterns_with_filter: usize, + payload_sizes: Vec, +} + +impl ExportAnalytics { + pub fn from_export(export: &Export) -> Self { + let Export { url: _, api_key, payload_size, indexes } = export; + + let has_api_key = api_key.is_some(); + let total_index_patterns = indexes.len(); + let total_patterns_with_filter = + indexes.values().filter(|settings| settings.filter.is_some()).count(); + let payload_sizes = + if let Some(crate::routes::export::ByteWithDeserr(byte_size)) = payload_size { + vec![byte_size.as_u64()] + } else { + vec![] + }; + + Self { + total_received: 1, + has_api_key, + total_index_patterns, + total_patterns_with_filter, + payload_sizes, + } + } +} + +impl Aggregate for ExportAnalytics { + fn event_name(&self) -> &'static str { + "Export Triggered" + } + + fn aggregate(mut self: Box, other: Box) -> Box { + self.total_received += other.total_received; + self.has_api_key |= other.has_api_key; + self.total_index_patterns += other.total_index_patterns; + self.total_patterns_with_filter += other.total_patterns_with_filter; + self.payload_sizes.extend(other.payload_sizes); + self + } + + fn into_event(self: Box) -> serde_json::Value { + let avg_payload_size = if self.payload_sizes.is_empty() { + None + } else { + Some(self.payload_sizes.iter().sum::() / self.payload_sizes.len() as u64) + }; + + serde_json::json!({ + "total_received": self.total_received, + "has_api_key": self.has_api_key, + "total_index_patterns": self.total_index_patterns, + "total_patterns_with_filter": self.total_patterns_with_filter, + "avg_payload_size": avg_payload_size, + }) + } +} diff --git a/crates/meilisearch/src/routes/mod.rs b/crates/meilisearch/src/routes/mod.rs index 748cd5d83..08583d20f 100644 --- a/crates/meilisearch/src/routes/mod.rs +++ b/crates/meilisearch/src/routes/mod.rs @@ -55,6 +55,7 @@ pub mod batches; pub mod chats; mod dump; mod export; +mod export_analytics; pub mod features; pub mod indexes; mod logs;