diff --git a/Cargo.lock b/Cargo.lock index 01b2f33866392f..a7f690078f21ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2547,6 +2547,7 @@ dependencies = [ "settings", "sha2", "smol", + "telemetry", "telemetry_events", "text", "thiserror 1.0.69", @@ -2841,6 +2842,7 @@ dependencies = [ "serde", "serde_json", "settings", + "telemetry", "theme", "ui", "util", @@ -3938,6 +3940,7 @@ dependencies = [ "snippet", "sum_tree", "task", + "telemetry", "tempfile", "text", "theme", @@ -4373,6 +4376,7 @@ dependencies = [ "serde_json_lenient", "settings", "task", + "telemetry", "tempfile", "theme", "theme_extension", @@ -10399,6 +10403,7 @@ dependencies = [ "serde_json", "settings", "smol", + "telemetry", "terminal", "terminal_view", "theme", @@ -12663,12 +12668,23 @@ dependencies = [ "zed_actions", ] +[[package]] +name = "telemetry" +version = "0.1.0" +dependencies = [ + "futures 0.3.31", + "serde", + "serde_json", + "telemetry_events", +] + [[package]] name = "telemetry_events" version = "0.1.0" dependencies = [ "semantic_version", "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 743f6178bfc12c..7e5eebca0e2297 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -117,6 +117,7 @@ members = [ "crates/tab_switcher", "crates/task", "crates/tasks_ui", + "crates/telemetry", "crates/telemetry_events", "crates/terminal", "crates/terminal_view", @@ -305,6 +306,7 @@ supermaven_api = { path = "crates/supermaven_api" } tab_switcher = { path = "crates/tab_switcher" } task = { path = "crates/task" } tasks_ui = { path = "crates/tasks_ui" } +telemetry = { path = "crates/telemetry" } telemetry_events = { path = "crates/telemetry_events" } terminal = { path = "crates/terminal" } terminal_view = { path = "crates/terminal_view" } diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 23716f0c69da13..c68caa0108b129 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -51,6 +51,7 @@ tokio-socks = { version = "0.5.2", default-features = false, features = ["future url.workspace = true util.workspace = true worktree.workspace = true +telemetry.workspace = true [dev-dependencies] clock = { workspace = true, features = ["test-support"] } diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index 3e97b0164b4ee4..258b15c7279211 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -4,7 +4,8 @@ use crate::{ChannelId, TelemetrySettings}; use anyhow::Result; use clock::SystemClock; use collections::{HashMap, HashSet}; -use futures::Future; +use futures::channel::mpsc; +use futures::{Future, StreamExt}; use gpui::{AppContext, BackgroundExecutor, Task}; use http_client::{self, AsyncBody, HttpClient, HttpClientWithUrl, Method, Request}; use once_cell::sync::Lazy; @@ -17,9 +18,8 @@ use std::io::Write; use std::time::Instant; use std::{env, mem, path::PathBuf, sync::Arc, time::Duration}; use telemetry_events::{ - ActionEvent, AppEvent, AssistantEvent, CallEvent, EditEvent, EditorEvent, Event, - EventRequestBody, EventWrapper, ExtensionEvent, InlineCompletionEvent, InlineCompletionRating, - InlineCompletionRatingEvent, ReplEvent, SettingEvent, + AppEvent, AssistantEvent, CallEvent, EditEvent, Event, EventRequestBody, EventWrapper, + InlineCompletionEvent, InlineCompletionRating, InlineCompletionRatingEvent, SettingEvent, }; use util::{ResultExt, TryFutureExt}; use worktree::{UpdatedEntriesSet, WorktreeId}; @@ -245,7 +245,6 @@ impl Telemetry { }) .detach(); - // TODO: Replace all hardware stuff with nested SystemSpecs json let this = Arc::new(Self { clock, http_client: client, @@ -253,6 +252,21 @@ impl Telemetry { state, }); + let (tx, mut rx) = mpsc::unbounded(); + ::telemetry::init(tx); + + cx.background_executor() + .spawn({ + let this = Arc::downgrade(&this); + async move { + while let Some(event) = rx.next().await { + let Some(state) = this.upgrade() else { break }; + state.report_event(Event::Flexible(event)) + } + } + }) + .detach(); + // We should only ever have one instance of Telemetry, leak the subscription to keep it alive // rather than store in TelemetryState, complicating spawn as subscriptions are not Send std::mem::forget(cx.on_app_quit({ @@ -320,27 +334,6 @@ impl Telemetry { drop(state); } - pub fn report_editor_event( - self: &Arc, - file_extension: Option, - vim_mode: bool, - operation: &'static str, - copilot_enabled: bool, - copilot_enabled_for_language: bool, - is_via_ssh: bool, - ) { - let event = Event::Editor(EditorEvent { - file_extension, - vim_mode, - operation: operation.into(), - copilot_enabled, - copilot_enabled_for_language, - is_via_ssh, - }); - - self.report_event(event) - } - pub fn report_inline_completion_event( self: &Arc, provider: String, @@ -410,13 +403,6 @@ impl Telemetry { self.report_event(event) } - pub fn report_extension_event(self: &Arc, extension_id: Arc, version: Arc) { - self.report_event(Event::Extension(ExtensionEvent { - extension_id, - version, - })) - } - pub fn log_edit_event(self: &Arc, environment: &'static str, is_via_ssh: bool) { let mut state = self.state.lock(); let period_data = state.event_coalescer.log_event(environment); @@ -436,15 +422,6 @@ impl Telemetry { } } - pub fn report_action_event(self: &Arc, source: &'static str, action: String) { - let event = Event::Action(ActionEvent { - source: source.to_string(), - action, - }); - - self.report_event(event) - } - pub fn report_discovered_project_events( self: &Arc, worktree_id: WorktreeId, @@ -491,21 +468,6 @@ impl Telemetry { } } - pub fn report_repl_event( - self: &Arc, - kernel_language: String, - kernel_status: String, - repl_session_id: String, - ) { - let event = Event::Repl(ReplEvent { - kernel_language, - kernel_status, - repl_session_id, - }); - - self.report_event(event) - } - fn report_event(self: &Arc, event: Event) { let mut state = self.state.lock(); diff --git a/crates/collab/src/api/events.rs b/crates/collab/src/api/events.rs index 16cd884c2ec00f..add02a9406cc50 100644 --- a/crates/collab/src/api/events.rs +++ b/crates/collab/src/api/events.rs @@ -610,6 +610,10 @@ fn for_snowflake( "Kernel Status Changed".to_string(), serde_json::to_value(e).unwrap(), ), + Event::Flexible(e) => ( + e.event_type.clone(), + serde_json::to_value(&e.event_properties).unwrap(), + ), }; if let serde_json::Value::Object(ref mut map) = event_properties { diff --git a/crates/command_palette/Cargo.toml b/crates/command_palette/Cargo.toml index 1ca7c43f44fc9b..2e1c3aff4da3bc 100644 --- a/crates/command_palette/Cargo.toml +++ b/crates/command_palette/Cargo.toml @@ -25,6 +25,7 @@ settings.workspace = true theme.workspace = true ui.workspace = true util.workspace = true +telemetry.workspace = true workspace.workspace = true zed_actions.workspace = true diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 5e383c4d07f62e..405c7e7228f89e 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -4,7 +4,7 @@ use std::{ time::Duration, }; -use client::{parse_zed_link, telemetry::Telemetry}; +use client::parse_zed_link; use collections::HashMap; use command_palette_hooks::{ CommandInterceptResult, CommandPaletteFilter, CommandPaletteInterceptor, @@ -63,18 +63,12 @@ impl CommandPalette { let Some(previous_focus_handle) = cx.focused() else { return; }; - let telemetry = workspace.client().telemetry().clone(); workspace.toggle_modal(cx, move |cx| { - CommandPalette::new(previous_focus_handle, telemetry, query, cx) + CommandPalette::new(previous_focus_handle, query, cx) }); } - fn new( - previous_focus_handle: FocusHandle, - telemetry: Arc, - query: &str, - cx: &mut ViewContext, - ) -> Self { + fn new(previous_focus_handle: FocusHandle, query: &str, cx: &mut ViewContext) -> Self { let filter = CommandPaletteFilter::try_global(cx); let commands = cx @@ -92,12 +86,8 @@ impl CommandPalette { }) .collect(); - let delegate = CommandPaletteDelegate::new( - cx.view().downgrade(), - commands, - telemetry, - previous_focus_handle, - ); + let delegate = + CommandPaletteDelegate::new(cx.view().downgrade(), commands, previous_focus_handle); let picker = cx.new_view(|cx| { let picker = Picker::uniform_list(delegate, cx); @@ -133,7 +123,6 @@ pub struct CommandPaletteDelegate { commands: Vec, matches: Vec, selected_ix: usize, - telemetry: Arc, previous_focus_handle: FocusHandle, updating_matches: Option<( Task<()>, @@ -167,7 +156,6 @@ impl CommandPaletteDelegate { fn new( command_palette: WeakView, commands: Vec, - telemetry: Arc, previous_focus_handle: FocusHandle, ) -> Self { Self { @@ -176,7 +164,6 @@ impl CommandPaletteDelegate { matches: vec![], commands, selected_ix: 0, - telemetry, previous_focus_handle, updating_matches: None, } @@ -367,9 +354,11 @@ impl PickerDelegate for CommandPaletteDelegate { let action_ix = self.matches[self.selected_ix].candidate_id; let command = self.commands.swap_remove(action_ix); - self.telemetry - .report_action_event("command palette", command.name.clone()); - + telemetry::event!( + "Action Invoked", + source = "command palette", + action = command.name + ); self.matches.clear(); self.commands.clear(); HitCounts::update_global(cx, |hit_counts, _cx| { diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index a728ea86a2e38e..3b92a35dfd19f7 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -72,6 +72,7 @@ smol.workspace = true snippet.workspace = true sum_tree.workspace = true task.workspace = true +telemetry.workspace = true text.workspace = true time.workspace = true time_format.workspace = true diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index c086aa508eba25..4265a5760c933f 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1370,7 +1370,7 @@ impl Editor { } } - this.report_editor_event("open", None, cx); + this.report_editor_event("Editor Opened", None, cx); this } @@ -12568,7 +12568,7 @@ impl Editor { fn report_editor_event( &self, - operation: &'static str, + event_type: &'static str, file_extension: Option, cx: &AppContext, ) { @@ -12605,15 +12605,14 @@ impl Editor { .show_inline_completions; let project = project.read(cx); - let telemetry = project.client().telemetry().clone(); - telemetry.report_editor_event( + telemetry::event!( + event_type, file_extension, vim_mode, - operation, copilot_enabled, copilot_enabled_for_language, - project.is_via_ssh(), - ) + is_via_ssh = project.is_via_ssh(), + ); } /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines, diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 298ef5a3f06092..48b7af086bc7b8 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -733,7 +733,7 @@ impl Item for Editor { project: Model, cx: &mut ViewContext, ) -> Task> { - self.report_editor_event("save", None, cx); + self.report_editor_event("Editor Saved", None, cx); let buffers = self.buffer().clone().read(cx).all_buffers(); let buffers = buffers .into_iter() @@ -805,7 +805,7 @@ impl Item for Editor { .path .extension() .map(|a| a.to_string_lossy().to_string()); - self.report_editor_event("save", file_extension, cx); + self.report_editor_event("Editor Saved", file_extension, cx); project.update(cx, |project, cx| project.save_buffer_as(buffer, path, cx)) } diff --git a/crates/extension_host/Cargo.toml b/crates/extension_host/Cargo.toml index 53971ade0a2fe0..b196733596171c 100644 --- a/crates/extension_host/Cargo.toml +++ b/crates/extension_host/Cargo.toml @@ -43,6 +43,7 @@ serde_json.workspace = true serde_json_lenient.workspace = true settings.workspace = true task.workspace = true +telemetry.workspace = true tempfile.workspace = true toml.workspace = true url.workspace = true diff --git a/crates/extension_host/src/extension_host.rs b/crates/extension_host/src/extension_host.rs index 6c965d3d56810a..afe78e49a04592 100644 --- a/crates/extension_host/src/extension_host.rs +++ b/crates/extension_host/src/extension_host.rs @@ -1001,14 +1001,13 @@ impl ExtensionStore { extensions_to_unload.len() - reload_count ); - if let Some(telemetry) = &self.telemetry { - for extension_id in &extensions_to_load { - if let Some(extension) = new_index.extensions.get(extension_id) { - telemetry.report_extension_event( - extension_id.clone(), - extension.manifest.version.clone(), - ); - } + for extension_id in &extensions_to_load { + if let Some(extension) = new_index.extensions.get(extension_id) { + telemetry::event!( + "Extension Loaded", + extension_id, + version = extension.manifest.version + ); } } diff --git a/crates/repl/Cargo.toml b/crates/repl/Cargo.toml index a49958c49e362a..ac22bb52d094f9 100644 --- a/crates/repl/Cargo.toml +++ b/crates/repl/Cargo.toml @@ -43,6 +43,7 @@ serde.workspace = true serde_json.workspace = true settings.workspace = true smol.workspace = true +telemetry.workspace = true terminal.workspace = true terminal_view.workspace = true theme.workspace = true diff --git a/crates/repl/src/repl.rs b/crates/repl/src/repl.rs index 4d11734e296054..f0745aa25c0a36 100644 --- a/crates/repl/src/repl.rs +++ b/crates/repl/src/repl.rs @@ -24,16 +24,15 @@ pub use crate::repl_sessions_ui::{ }; use crate::repl_store::ReplStore; pub use crate::session::Session; -use client::telemetry::Telemetry; pub const KERNEL_DOCS_URL: &str = "https://zed.dev/docs/repl#changing-kernels"; -pub fn init(fs: Arc, telemetry: Arc, cx: &mut AppContext) { +pub fn init(fs: Arc, cx: &mut AppContext) { set_dispatcher(zed_dispatcher(cx)); JupyterSettings::register(cx); ::editor::init_settings(cx); repl_sessions_ui::init(cx); - ReplStore::init(fs, telemetry, cx); + ReplStore::init(fs, cx); } fn zed_dispatcher(cx: &mut AppContext) -> impl Dispatcher { diff --git a/crates/repl/src/repl_editor.rs b/crates/repl/src/repl_editor.rs index 3c203900da56b9..e190dd19111a4e 100644 --- a/crates/repl/src/repl_editor.rs +++ b/crates/repl/src/repl_editor.rs @@ -33,7 +33,6 @@ pub fn assign_kernelspec( }); let fs = store.read(cx).fs().clone(); - let telemetry = store.read(cx).telemetry().clone(); if let Some(session) = store.read(cx).get_session(weak_editor.entity_id()).cloned() { // Drop previous session, start new one @@ -44,8 +43,7 @@ pub fn assign_kernelspec( }); } - let session = cx - .new_view(|cx| Session::new(weak_editor.clone(), fs, telemetry, kernel_specification, cx)); + let session = cx.new_view(|cx| Session::new(weak_editor.clone(), fs, kernel_specification, cx)); weak_editor .update(cx, |_editor, cx| { @@ -105,15 +103,13 @@ pub fn run(editor: WeakView, move_down: bool, cx: &mut WindowContext) -> .ok_or_else(|| anyhow::anyhow!("No kernel found for language: {}", language.name()))?; let fs = store.read(cx).fs().clone(); - let telemetry = store.read(cx).telemetry().clone(); let session = if let Some(session) = store.read(cx).get_session(editor.entity_id()).cloned() { session } else { let weak_editor = editor.downgrade(); - let session = cx - .new_view(|cx| Session::new(weak_editor, fs, telemetry, kernel_specification, cx)); + let session = cx.new_view(|cx| Session::new(weak_editor, fs, kernel_specification, cx)); editor.update(cx, |_editor, cx| { cx.notify(); diff --git a/crates/repl/src/repl_store.rs b/crates/repl/src/repl_store.rs index 763d46ae6d1b86..d51b4787292e00 100644 --- a/crates/repl/src/repl_store.rs +++ b/crates/repl/src/repl_store.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use anyhow::Result; -use client::telemetry::Telemetry; use collections::HashMap; use command_palette_hooks::CommandPaletteFilter; use gpui::{ @@ -28,15 +27,14 @@ pub struct ReplStore { kernel_specifications: Vec, selected_kernel_for_worktree: HashMap, kernel_specifications_for_worktree: HashMap>, - telemetry: Arc, _subscriptions: Vec, } impl ReplStore { const NAMESPACE: &'static str = "repl"; - pub(crate) fn init(fs: Arc, telemetry: Arc, cx: &mut AppContext) { - let store = cx.new_model(move |cx| Self::new(fs, telemetry, cx)); + pub(crate) fn init(fs: Arc, cx: &mut AppContext) { + let store = cx.new_model(move |cx| Self::new(fs, cx)); store .update(cx, |store, cx| store.refresh_kernelspecs(cx)) @@ -49,14 +47,13 @@ impl ReplStore { cx.global::().0.clone() } - pub fn new(fs: Arc, telemetry: Arc, cx: &mut ModelContext) -> Self { + pub fn new(fs: Arc, cx: &mut ModelContext) -> Self { let subscriptions = vec![cx.observe_global::(move |this, cx| { this.set_enabled(JupyterSettings::enabled(cx), cx); })]; let this = Self { fs, - telemetry, enabled: JupyterSettings::enabled(cx), sessions: HashMap::default(), kernel_specifications: Vec::new(), @@ -72,10 +69,6 @@ impl ReplStore { &self.fs } - pub fn telemetry(&self) -> &Arc { - &self.telemetry - } - pub fn is_enabled(&self) -> bool { self.enabled } diff --git a/crates/repl/src/session.rs b/crates/repl/src/session.rs index 0c1dc287ed0a0f..f202ed170478a9 100644 --- a/crates/repl/src/session.rs +++ b/crates/repl/src/session.rs @@ -6,7 +6,6 @@ use crate::{ outputs::{ExecutionStatus, ExecutionView}, KernelStatus, }; -use client::telemetry::Telemetry; use collections::{HashMap, HashSet}; use editor::{ display_map::{ @@ -37,7 +36,6 @@ pub struct Session { pub kernel: Kernel, blocks: HashMap, pub kernel_specification: KernelSpecification, - telemetry: Arc, _buffer_subscription: Subscription, } @@ -194,7 +192,6 @@ impl Session { pub fn new( editor: WeakView, fs: Arc, - telemetry: Arc, kernel_specification: KernelSpecification, cx: &mut ViewContext, ) -> Self { @@ -221,7 +218,6 @@ impl Session { blocks: HashMap::default(), kernel_specification, _buffer_subscription: subscription, - telemetry, }; session.start_kernel(cx); @@ -237,10 +233,11 @@ impl Session { .and_then(|editor| editor.read(cx).working_directory(cx)) .unwrap_or_else(temp_dir); - self.telemetry.report_repl_event( - kernel_language.into(), - KernelStatus::Starting.to_string(), - cx.entity_id().to_string(), + telemetry::event!( + "Kernel Status Changed", + kernel_language, + kernel_status = KernelStatus::Starting.to_string(), + repl_session_id = cx.entity_id().to_string(), ); let session_view = cx.view().clone(); @@ -488,10 +485,11 @@ impl Session { JupyterMessageContent::Status(status) => { self.kernel.set_execution_state(&status.execution_state); - self.telemetry.report_repl_event( - self.kernel_specification.language().into(), - KernelStatus::from(&self.kernel).to_string(), - cx.entity_id().to_string(), + telemetry::event!( + "Kernel Status Changed", + kernel_language = self.kernel_specification.language(), + kernel_status = KernelStatus::from(&self.kernel).to_string(), + repl_session_id = cx.entity_id().to_string(), ); cx.notify(); @@ -540,12 +538,13 @@ impl Session { } let kernel_status = KernelStatus::from(&kernel).to_string(); - let kernel_language = self.kernel_specification.language().into(); + let kernel_language = self.kernel_specification.language(); - self.telemetry.report_repl_event( + telemetry::event!( + "Kernel Status Changed", kernel_language, kernel_status, - cx.entity_id().to_string(), + repl_session_id = cx.entity_id().to_string(), ); self.kernel = kernel; diff --git a/crates/telemetry/Cargo.toml b/crates/telemetry/Cargo.toml new file mode 100644 index 00000000000000..cc524f0ceb5e22 --- /dev/null +++ b/crates/telemetry/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "telemetry" +version = "0.1.0" +edition = "2021" +publish = false +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[lib] +path = "src/telemetry.rs" + +[dependencies] +serde.workspace = true +serde_json.workspace = true +telemetry_events.workspace = true +futures.workspace = true diff --git a/crates/telemetry/LICENSE-GPL b/crates/telemetry/LICENSE-GPL new file mode 120000 index 00000000000000..e0f9dbd5d63fef --- /dev/null +++ b/crates/telemetry/LICENSE-GPL @@ -0,0 +1 @@ +LICENSE-GPL \ No newline at end of file diff --git a/crates/telemetry/src/telemetry.rs b/crates/telemetry/src/telemetry.rs new file mode 100644 index 00000000000000..64e36f4c3d1d61 --- /dev/null +++ b/crates/telemetry/src/telemetry.rs @@ -0,0 +1,57 @@ +//! See [Telemetry in Zed](https://zed.dev/docs/telemetry) for additional information. +use futures::channel::mpsc; +pub use serde_json; +use std::sync::OnceLock; +pub use telemetry_events::FlexibleEvent as Event; + +/// Macro to create telemetry events and send them to the telemetry queue. +/// +/// By convention, the name should be "Noun Verbed", e.g. "Keymap Changed" +/// or "Project Diagnostics Opened". +/// +/// The properties can be any value that implements serde::Serialize. +/// +/// ``` +/// telemetry::event!("Keymap Changed", version = "1.0.0"); +/// telemetry::event!("Documentation Viewed", url, source = "Extension Upsell"); +/// ``` +#[macro_export] +macro_rules! event { + ($name:expr, $($key:ident $(= $value:expr)?),+ $(,)?) => {{ + let event = $crate::Event { + event_type: $name.to_string(), + event_properties: std::collections::HashMap::from([ + $( + (stringify!($key).to_string(), + $crate::serde_json::value::to_value(&$crate::serialize_property!($key $(= $value)?)) + .unwrap_or_else(|_| $crate::serde_json::to_value(&()).unwrap()) + ), + )+ + ]), + }; + $crate::send_event(event); + }}; +} + +#[macro_export] +macro_rules! serialize_property { + ($key:ident) => { + $key + }; + ($key:ident = $value:expr) => { + $value + }; +} + +pub fn send_event(event: Event) { + if let Some(queue) = TELEMETRY_QUEUE.get() { + queue.unbounded_send(event).ok(); + return; + } +} + +pub fn init(tx: mpsc::UnboundedSender) { + TELEMETRY_QUEUE.set(tx).ok(); +} + +static TELEMETRY_QUEUE: OnceLock> = OnceLock::new(); diff --git a/crates/telemetry_events/Cargo.toml b/crates/telemetry_events/Cargo.toml index 01145549b156f7..35a87f46fffb18 100644 --- a/crates/telemetry_events/Cargo.toml +++ b/crates/telemetry_events/Cargo.toml @@ -14,3 +14,4 @@ path = "src/telemetry_events.rs" [dependencies] semantic_version.workspace = true serde.workspace = true +serde_json.workspace = true diff --git a/crates/telemetry_events/src/telemetry_events.rs b/crates/telemetry_events/src/telemetry_events.rs index 0002a169d47288..b7326201713299 100644 --- a/crates/telemetry_events/src/telemetry_events.rs +++ b/crates/telemetry_events/src/telemetry_events.rs @@ -2,7 +2,7 @@ use semantic_version::SemanticVersion; use serde::{Deserialize, Serialize}; -use std::{fmt::Display, sync::Arc, time::Duration}; +use std::{collections::HashMap, fmt::Display, sync::Arc, time::Duration}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct EventRequestBody { @@ -91,6 +91,7 @@ impl Display for AssistantPhase { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(tag = "type")] pub enum Event { + Flexible(FlexibleEvent), Editor(EditorEvent), InlineCompletion(InlineCompletionEvent), InlineCompletionRating(InlineCompletionRatingEvent), @@ -106,6 +107,12 @@ pub enum Event { Repl(ReplEvent), } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct FlexibleEvent { + pub event_type: String, + pub event_properties: HashMap, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct EditorEvent { /// The editor operation performed (open, save) diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 062fff049d1c16..0aee0c85319d1d 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -413,11 +413,7 @@ fn main() { cx, ); assistant_tools::init(cx); - repl::init( - app_state.fs.clone(), - app_state.client.telemetry().clone(), - cx, - ); + repl::init(app_state.fs.clone(), cx); extension_host::init( extension_host_proxy, app_state.fs.clone(), diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 7372ffea1103f5..59d235e3005fdc 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -3496,11 +3496,7 @@ mod tests { ); let prompt_builder = assistant::init(app_state.fs.clone(), app_state.client.clone(), false, cx); - repl::init( - app_state.fs.clone(), - app_state.client.telemetry().clone(), - cx, - ); + repl::init(app_state.fs.clone(), cx); repl::notebook::init(cx); tasks_ui::init(cx); initialize_workspace(app_state.clone(), prompt_builder, cx);