diff --git a/Cargo.lock b/Cargo.lock index f146c4b8d5..5b3461c193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1415,6 +1415,7 @@ dependencies = [ "settings", "smol", "sum_tree", + "sysinfo", "tempfile", "text", "thiserror", @@ -7607,9 +7608,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.27.8" +version = "0.29.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a902e9050fca0a5d6877550b769abd2bd1ce8c04634b941dbe2809735e1a1e33" +checksum = "0a18d114d420ada3a891e6bc8e96a2023402203296a47cdd65083377dad18ba5" dependencies = [ "cfg-if 1.0.0", "core-foundation-sys 0.8.3", diff --git a/Cargo.toml b/Cargo.toml index f09d44e8da..801435ee2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,6 +111,7 @@ serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } smallvec = { version = "1.6", features = ["union"] } smol = { version = "1.2" } +sysinfo = "0.29.10" tempdir = { version = "0.3.7" } thiserror = { version = "1.0.29" } time = { version = "0.3", features = ["serde", "serde-well-known"] } diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index e3038e5bcc..9e371ec8bd 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -33,15 +33,16 @@ parking_lot.workspace = true postage.workspace = true rand.workspace = true schemars.workspace = true +serde.workspace = true +serde_derive.workspace = true smol.workspace = true +sysinfo.workspace = true +tempfile = "3" thiserror.workspace = true time.workspace = true tiny_http = "0.8" -uuid = { version = "1.1.2", features = ["v4"] } url = "2.2" -serde.workspace = true -serde_derive.workspace = true -tempfile = "3" +uuid = { version = "1.1.2", features = ["v4"] } [dev-dependencies] collections = { path = "../collections", features = ["test-support"] } diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index 1596e6d850..8d51a3d1fe 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -4,6 +4,7 @@ use lazy_static::lazy_static; use parking_lot::Mutex; use serde::Serialize; use std::{env, io::Write, mem, path::PathBuf, sync::Arc, time::Duration}; +use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt}; use tempfile::NamedTempFile; use util::http::HttpClient; use util::{channel::ReleaseChannel, TryFutureExt}; @@ -88,6 +89,16 @@ pub enum ClickhouseEvent { kind: AssistantKind, model: &'static str, }, + Cpu { + usage_as_percent: f32, + core_count: u32, + }, + Memory { + memory_in_bytes: u64, + virtual_memory_in_bytes: u64, + start_time_in_seconds: u64, + run_time_in_seconds: u64, + }, } #[cfg(debug_assertions)] @@ -136,7 +147,7 @@ impl Telemetry { Some(self.state.lock().log_file.as_ref()?.path().to_path_buf()) } - pub fn start(self: &Arc, installation_id: Option) { + pub fn start(self: &Arc, installation_id: Option, cx: &mut AppContext) { let mut state = self.state.lock(); state.installation_id = installation_id.map(|id| id.into()); let has_clickhouse_events = !state.clickhouse_events_queue.is_empty(); @@ -145,6 +156,48 @@ impl Telemetry { if has_clickhouse_events { self.flush_clickhouse_events(); } + + let this = self.clone(); + cx.spawn(|mut cx| async move { + let mut system = System::new_all(); + system.refresh_all(); + + loop { + // Waiting some amount of time before the first query is important to get a reasonable value + // https://docs.rs/sysinfo/0.29.10/sysinfo/trait.ProcessExt.html#tymethod.cpu_usage + const DURATION_BETWEEN_SYSTEM_EVENTS: Duration = Duration::from_secs(60); + smol::Timer::after(DURATION_BETWEEN_SYSTEM_EVENTS).await; + + let telemetry_settings = cx.update(|cx| *settings::get::(cx)); + + system.refresh_memory(); + system.refresh_processes(); + + let current_process = Pid::from_u32(std::process::id()); + let Some(process) = system.processes().get(¤t_process) else { + let process = current_process; + log::error!("Failed to find own process {process:?} in system process table"); + // TODO: Fire an error telemetry event + return; + }; + + let memory_event = ClickhouseEvent::Memory { + memory_in_bytes: process.memory(), + virtual_memory_in_bytes: process.virtual_memory(), + start_time_in_seconds: process.start_time(), + run_time_in_seconds: process.run_time(), + }; + + let cpu_event = ClickhouseEvent::Cpu { + usage_as_percent: process.cpu_usage(), + core_count: system.cpus().len() as u32, + }; + + this.report_clickhouse_event(memory_event, telemetry_settings); + this.report_clickhouse_event(cpu_event, telemetry_settings); + } + }) + .detach(); } pub fn set_authenticated_user_info( diff --git a/crates/feedback/Cargo.toml b/crates/feedback/Cargo.toml index 07b6ad790c..651d32ba91 100644 --- a/crates/feedback/Cargo.toml +++ b/crates/feedback/Cargo.toml @@ -33,7 +33,7 @@ lazy_static.workspace = true postage.workspace = true serde.workspace = true serde_derive.workspace = true -sysinfo = "0.27.1" +sysinfo.workspace = true tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" } urlencoding = "2.1.2" diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 7991cabde2..d6f3be2b46 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -177,7 +177,7 @@ fn main() { }) .detach(); - client.telemetry().start(installation_id); + client.telemetry().start(installation_id, cx); let app_state = Arc::new(AppState { languages,