wip

Max Brunsfeld created

Change summary

crates/client/src/telemetry.rs           | 91 ++++++++++++++++---------
crates/gpui/src/platform.rs              |  1 
crates/gpui/src/platform/mac/platform.rs |  4 +
crates/gpui/src/platform/test.rs         |  4 +
4 files changed, 67 insertions(+), 33 deletions(-)

Detailed changes

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<dyn HttpClient>,
     executor: Arc<Background>,
+    session_id: u128,
     state: Mutex<TelemetryState>,
 }
 
 #[derive(Default)]
 struct TelemetryState {
-    device_id: Option<String>,
-    app_version: Option<AppVersion>,
-    os_version: Option<AppVersion>,
-    queue: Vec<Event>,
+    user_id: Option<Arc<str>>,
+    device_id: Option<Arc<str>>,
+    app_version: Option<Arc<str>>,
+    os_version: Option<Arc<str>>,
+    os_name: &'static str,
+    queue: Vec<AmplitudeEvent>,
+    next_event_id: usize,
     flush_task: Option<Task<()>>,
 }
 
+const AMPLITUDE_EVENTS_URL: &'static str = "https//api2.amplitude.com/batch";
+
 #[derive(Serialize)]
-struct RecordEventParams {
-    token: &'static str,
-    device_id: Option<String>,
-    app_version: Option<String>,
-    os_version: Option<String>,
-    events: Vec<Event>,
+struct AmplitudeEventBatch {
+    api_key: &'static str,
+    events: Vec<AmplitudeEvent>,
 }
 
 #[derive(Serialize)]
-struct Event {
-    #[serde(rename = "type")]
-    kind: String,
+struct AmplitudeEvent {
+    user_id: Option<Arc<str>>,
+    device_id: Option<Arc<str>>,
+    event_type: String,
+    event_properties: Option<Map<String, Value>>,
+    user_properties: Option<Map<String, Value>>,
+    os_name: &'static str,
+    os_version: Option<Arc<str>>,
+    app_version: Option<Arc<str>>,
+    event_id: usize,
+    session_id: u128,
     time: u128,
-    properties: Option<Map<String, Value>>,
 }
 
 #[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<Self>, 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()?;

crates/gpui/src/platform.rs 🔗

@@ -69,6 +69,7 @@ pub trait Platform: Send + Sync {
     fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
     fn app_path(&self) -> Result<PathBuf>;
     fn app_version(&self) -> Result<AppVersion>;
+    fn os_name(&self) -> &'static str;
     fn os_version(&self) -> Result<AppVersion>;
 }
 

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<crate::AppVersion> {
         unsafe {
             let process_info = NSProcessInfo::processInfo(nil);

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<AppVersion> {
         Ok(AppVersion {
             major: 1,