diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index a78e691459..7eea13a923 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -1,8 +1,8 @@ -use crate::{http::HttpClient, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL}; +use crate::{http::HttpClient, ZED_SECRET_CLIENT_TOKEN}; use gpui::{ executor::Background, serde_json::{self, value::Map, Value}, - AppContext, AppVersion, Task, + AppContext, Task, }; use isahc::Request; use parking_lot::Mutex; @@ -12,38 +12,48 @@ use std::{ sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; -use util::ResultExt; +use util::{post_inc, ResultExt}; pub struct Telemetry { client: Arc, executor: Arc, + session_id: u128, state: Mutex, } #[derive(Default)] struct TelemetryState { - device_id: Option, - app_version: Option, - os_version: Option, - queue: Vec, + user_id: Option>, + device_id: Option>, + app_version: Option>, + os_version: Option>, + os_name: &'static str, + queue: Vec, + next_event_id: usize, flush_task: Option>, } +const AMPLITUDE_EVENTS_URL: &'static str = "https//api2.amplitude.com/batch"; + #[derive(Serialize)] -struct RecordEventParams { - token: &'static str, - device_id: Option, - app_version: Option, - os_version: Option, - events: Vec, +struct AmplitudeEventBatch { + api_key: &'static str, + events: Vec, } #[derive(Serialize)] -struct Event { - #[serde(rename = "type")] - kind: String, +struct AmplitudeEvent { + user_id: Option>, + device_id: Option>, + event_type: String, + event_properties: Option>, + user_properties: Option>, + os_name: &'static str, + os_version: Option>, + app_version: Option>, + event_id: usize, + session_id: u128, time: u128, - properties: Option>, } #[cfg(debug_assertions)] @@ -52,7 +62,6 @@ const MAX_QUEUE_LEN: usize = 1; #[cfg(not(debug_assertions))] const MAX_QUEUE_LEN: usize = 10; -const EVENTS_URI: &'static str = "api/telemetry"; const DEBOUNCE_INTERVAL: Duration = Duration::from_secs(30); impl Telemetry { @@ -61,30 +70,52 @@ impl Telemetry { Arc::new(Self { client, executor: cx.background().clone(), + session_id: SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis(), state: Mutex::new(TelemetryState { - os_version: platform.os_version().log_err(), - app_version: platform.app_version().log_err(), + os_version: platform + .os_version() + .log_err() + .map(|v| v.to_string().into()), + os_name: platform.os_name().into(), + app_version: platform + .app_version() + .log_err() + .map(|v| v.to_string().into()), device_id: None, queue: Default::default(), flush_task: Default::default(), + next_event_id: 0, + user_id: None, }), }) } pub fn log_event(self: &Arc, kind: &str, properties: Value) { let mut state = self.state.lock(); - state.queue.push(Event { - kind: kind.to_string(), + let event = AmplitudeEvent { + event_type: kind.to_string(), time: SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_millis(), - properties: if let Value::Object(properties) = properties { + session_id: self.session_id, + event_properties: if let Value::Object(properties) = properties { Some(properties) } else { None }, - }); + user_properties: None, + user_id: state.user_id.clone(), + device_id: state.device_id.clone(), + os_name: state.os_name, + os_version: state.os_version.clone(), + app_version: state.app_version.clone(), + event_id: post_inc(&mut state.next_event_id), + }; + state.queue.push(event); if state.queue.len() >= MAX_QUEUE_LEN { drop(state); self.flush(); @@ -102,21 +133,15 @@ impl Telemetry { let mut state = self.state.lock(); let events = mem::take(&mut state.queue); let client = self.client.clone(); - let app_version = state.app_version; - let os_version = state.os_version; - let device_id = state.device_id.clone(); state.flush_task.take(); self.executor .spawn(async move { - let body = serde_json::to_vec(&RecordEventParams { - token: ZED_SECRET_CLIENT_TOKEN, + let body = serde_json::to_vec(&AmplitudeEventBatch { + api_key: ZED_SECRET_CLIENT_TOKEN, events, - app_version: app_version.map(|v| v.to_string()), - os_version: os_version.map(|v| v.to_string()), - device_id, }) .log_err()?; - let request = Request::post(format!("{}/{}", *ZED_SERVER_URL, EVENTS_URI)) + let request = Request::post(AMPLITUDE_EVENTS_URL) .header("Content-Type", "application/json") .body(body.into()) .log_err()?; diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 7467dad547..8997bde527 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -69,6 +69,7 @@ pub trait Platform: Send + Sync { fn path_for_auxiliary_executable(&self, name: &str) -> Result; fn app_path(&self) -> Result; fn app_version(&self) -> Result; + fn os_name(&self) -> &'static str; fn os_version(&self) -> Result; } diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 02fe73504e..628ddde13c 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -750,6 +750,10 @@ impl platform::Platform for MacPlatform { } } + fn os_name(&self) -> &'static str { + "macOS" + } + fn os_version(&self) -> Result { unsafe { let process_info = NSProcessInfo::processInfo(nil); diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 1bb53d49ab..58ef1ffaf2 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -197,6 +197,10 @@ impl super::Platform for Platform { }) } + fn os_name(&self) -> &'static str { + "test" + } + fn os_version(&self) -> Result { Ok(AppVersion { major: 1,