mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-30 09:04:59 +08:00
add more analytics
This commit is contained in:
parent
3af2f8b344
commit
e51ea55ae3
@ -1,20 +1,72 @@
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::thread;
|
use std::{error, thread};
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_qs as qs;
|
use serde_qs as qs;
|
||||||
use siphasher::sip::SipHasher;
|
use siphasher::sip::SipHasher;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::Data;
|
||||||
|
use crate::Opt;
|
||||||
|
|
||||||
const AMPLITUDE_API_KEY: &str = "f7fba398780e06d8fe6666a9be7e3d47";
|
const AMPLITUDE_API_KEY: &str = "f7fba398780e06d8fe6666a9be7e3d47";
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct EventProperties {
|
||||||
|
database_size: u64,
|
||||||
|
last_update_timestamp: Option<i64>, //timestamp
|
||||||
|
number_of_documents: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventProperties {
|
||||||
|
fn from(data: Data) -> Result<EventProperties, Box<dyn error::Error>> {
|
||||||
|
let mut index_list = Vec::new();
|
||||||
|
|
||||||
|
let reader = data.db.main_read_txn()?;
|
||||||
|
|
||||||
|
for index_uid in data.db.indexes_uids() {
|
||||||
|
if let Some(index) = data.db.open_index(&index_uid) {
|
||||||
|
let number_of_documents = index.main.number_of_documents(&reader)?;
|
||||||
|
index_list.push(number_of_documents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let database_size = WalkDir::new(&data.db_path)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|entry| entry.ok())
|
||||||
|
.filter_map(|entry| entry.metadata().ok())
|
||||||
|
.filter(|metadata| metadata.is_file())
|
||||||
|
.fold(0, |acc, m| acc + m.len());
|
||||||
|
|
||||||
|
let last_update_timestamp = data.db.last_update(&reader)?.map(|u| u.timestamp());
|
||||||
|
|
||||||
|
Ok(EventProperties {
|
||||||
|
database_size,
|
||||||
|
last_update_timestamp,
|
||||||
|
number_of_documents: index_list,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct UserProperties<'a> {
|
||||||
|
env: &'a str,
|
||||||
|
start_since_days: u64,
|
||||||
|
user_email: Option<String>,
|
||||||
|
server_provider: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
struct Event<'a> {
|
struct Event<'a> {
|
||||||
user_id: &'a str,
|
user_id: &'a str,
|
||||||
event_type: &'a str,
|
event_type: &'a str,
|
||||||
device_id: &'a str,
|
device_id: &'a str,
|
||||||
time: u64,
|
time: u64,
|
||||||
|
app_version: &'a str,
|
||||||
|
user_properties: UserProperties<'a>,
|
||||||
|
event_properties: Option<EventProperties>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
@ -23,7 +75,7 @@ struct AmplitudeRequest<'a> {
|
|||||||
event: &'a str,
|
event: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analytics_sender() {
|
pub fn analytics_sender(data: Data, opt: Opt) {
|
||||||
let username = whoami::username();
|
let username = whoami::username();
|
||||||
let hostname = whoami::hostname();
|
let hostname = whoami::hostname();
|
||||||
let platform = whoami::platform();
|
let platform = whoami::platform();
|
||||||
@ -36,6 +88,7 @@ pub fn analytics_sender() {
|
|||||||
|
|
||||||
let uid = format!("{:X}", hash);
|
let uid = format!("{:X}", hash);
|
||||||
let platform = platform.to_string();
|
let platform = platform.to_string();
|
||||||
|
let first_start = Instant::now();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let n = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
let n = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||||
@ -43,12 +96,27 @@ pub fn analytics_sender() {
|
|||||||
let device_id = &platform;
|
let device_id = &platform;
|
||||||
let time = n.as_secs();
|
let time = n.as_secs();
|
||||||
let event_type = "runtime_tick";
|
let event_type = "runtime_tick";
|
||||||
|
let elapsed_since_start = first_start.elapsed().as_secs() / 86_400; // One day
|
||||||
|
let event_properties = EventProperties::from(data.clone()).ok();
|
||||||
|
let app_version = env!("CARGO_PKG_VERSION").to_string();
|
||||||
|
let app_version = app_version.as_str();
|
||||||
|
let user_email = std::env::var("MEILI_USER_EMAIL").ok();
|
||||||
|
let server_provider = std::env::var("MEILI_SERVER_PROVIDER").ok();
|
||||||
|
let user_properties = UserProperties {
|
||||||
|
env: &opt.env,
|
||||||
|
start_since_days: elapsed_since_start,
|
||||||
|
user_email,
|
||||||
|
server_provider,
|
||||||
|
};
|
||||||
|
|
||||||
let event = Event {
|
let event = Event {
|
||||||
user_id,
|
user_id,
|
||||||
event_type,
|
event_type,
|
||||||
device_id,
|
device_id,
|
||||||
time,
|
time,
|
||||||
|
app_version,
|
||||||
|
user_properties,
|
||||||
|
event_properties
|
||||||
};
|
};
|
||||||
let event = serde_json::to_string(&event).unwrap();
|
let event = serde_json::to_string(&event).unwrap();
|
||||||
|
|
||||||
@ -64,6 +132,6 @@ pub fn analytics_sender() {
|
|||||||
error!("Unsuccessful call to Amplitude: {}", body);
|
error!("Unsuccessful call to Amplitude: {}", body);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread::sleep(Duration::from_secs(86_400)) // one day
|
thread::sleep(Duration::from_secs(3600)) // one hour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ pub mod helpers;
|
|||||||
pub mod models;
|
pub mod models;
|
||||||
pub mod option;
|
pub mod option;
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
|
pub mod analytics;
|
||||||
|
|
||||||
use actix_http::Error;
|
use actix_http::Error;
|
||||||
use actix_service::ServiceFactory;
|
use actix_service::ServiceFactory;
|
||||||
@ -15,6 +16,7 @@ use log::error;
|
|||||||
|
|
||||||
use meilisearch_core::ProcessedUpdateResult;
|
use meilisearch_core::ProcessedUpdateResult;
|
||||||
|
|
||||||
|
pub use option::Opt;
|
||||||
pub use self::data::Data;
|
pub use self::data::Data;
|
||||||
use self::error::{json_error_handler, ResponseError};
|
use self::error::{json_error_handler, ResponseError};
|
||||||
|
|
||||||
|
@ -3,10 +3,8 @@ use std::{env, thread};
|
|||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
use actix_web::{middleware, HttpServer};
|
use actix_web::{middleware, HttpServer};
|
||||||
use main_error::MainError;
|
use main_error::MainError;
|
||||||
use meilisearch_http::data::Data;
|
|
||||||
use meilisearch_http::helpers::NormalizePath;
|
use meilisearch_http::helpers::NormalizePath;
|
||||||
use meilisearch_http::option::Opt;
|
use meilisearch_http::{Data, Opt, create_app, index_update_callback};
|
||||||
use meilisearch_http::{create_app, index_update_callback};
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
mod analytics;
|
mod analytics;
|
||||||
@ -49,12 +47,16 @@ async fn main() -> Result<(), MainError> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opt.no_analytics {
|
|
||||||
thread::spawn(analytics::analytics_sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = Data::new(opt.clone());
|
let data = Data::new(opt.clone());
|
||||||
|
|
||||||
|
if !opt.no_analytics {
|
||||||
|
let analytics_data = data.clone();
|
||||||
|
let analytics_opt = opt.clone();
|
||||||
|
thread::spawn(move|| {
|
||||||
|
analytics::analytics_sender(analytics_data, analytics_opt)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let data_cloned = data.clone();
|
let data_cloned = data.clone();
|
||||||
data.db.set_update_callback(Box::new(move |name, status| {
|
data.db.set_update_callback(Box::new(move |name, status| {
|
||||||
index_update_callback(name, &data_cloned, status);
|
index_update_callback(name, &data_cloned, status);
|
||||||
|
Loading…
Reference in New Issue
Block a user