Add settings events (#3847)

Adds the infractucture for settings events and specifically tracks theme
settings. Currently, we only take note of the theme at app open and when
the user switches the theme with the theme selector. Changes at the
config file are ignored, as putting code that low leads to a lot of
chances of reporting theme events when the user hasn't done anything.
This change is done in both Zed 1 and Zed 2.

I'll open up a PR on zed.dev and adjust the database accordingly.

Release Notes:

- N/A
This commit is contained in:
Joseph T. Lyons 2024-01-02 17:19:21 -05:00 committed by GitHub
commit 850a9e33e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 12 deletions

2
Cargo.lock generated
View file

@ -9838,6 +9838,7 @@ dependencies = [
name = "theme_selector" name = "theme_selector"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"client",
"editor", "editor",
"feature_flags", "feature_flags",
"fs", "fs",
@ -9858,6 +9859,7 @@ dependencies = [
name = "theme_selector2" name = "theme_selector2"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"client2",
"editor2", "editor2",
"feature_flags2", "feature_flags2",
"fs2", "fs2",

View file

@ -113,6 +113,11 @@ pub enum ClickhouseEvent {
operation: &'static str, operation: &'static str,
milliseconds_since_first_event: i64, milliseconds_since_first_event: i64,
}, },
Setting {
setting: &'static str,
value: String,
milliseconds_since_first_event: i64,
},
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -354,6 +359,21 @@ impl Telemetry {
self.report_clickhouse_event(event, telemetry_settings, immediate_flush) self.report_clickhouse_event(event, telemetry_settings, immediate_flush)
} }
pub fn report_setting_event(
self: &Arc<Self>,
telemetry_settings: TelemetrySettings,
setting: &'static str,
value: String,
) {
let event = ClickhouseEvent::Setting {
setting,
value,
milliseconds_since_first_event: self.milliseconds_since_first_event(),
};
self.report_clickhouse_event(event, telemetry_settings, false)
}
fn milliseconds_since_first_event(&self) -> i64 { fn milliseconds_since_first_event(&self) -> i64 {
let mut state = self.state.lock(); let mut state = self.state.lock();
match state.first_event_datetime { match state.first_event_datetime {

View file

@ -111,6 +111,11 @@ pub enum ClickhouseEvent {
operation: &'static str, operation: &'static str,
milliseconds_since_first_event: i64, milliseconds_since_first_event: i64,
}, },
Setting {
setting: &'static str,
value: String,
milliseconds_since_first_event: i64,
},
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -370,6 +375,21 @@ impl Telemetry {
self.report_clickhouse_event(event, telemetry_settings, immediate_flush) self.report_clickhouse_event(event, telemetry_settings, immediate_flush)
} }
pub fn report_setting_event(
self: &Arc<Self>,
telemetry_settings: TelemetrySettings,
setting: &'static str,
value: String,
) {
let event = ClickhouseEvent::Setting {
setting,
value,
milliseconds_since_first_event: self.milliseconds_since_first_event(),
};
self.report_clickhouse_event(event, telemetry_settings, false)
}
fn milliseconds_since_first_event(&self) -> i64 { fn milliseconds_since_first_event(&self) -> i64 {
let mut state = self.state.lock(); let mut state = self.state.lock();
match state.first_event_datetime { match state.first_event_datetime {

View file

@ -9,6 +9,7 @@ path = "src/theme_selector.rs"
doctest = false doctest = false
[dependencies] [dependencies]
client = { path = "../client" }
editor = { path = "../editor" } editor = { path = "../editor" }
fuzzy = { path = "../fuzzy" } fuzzy = { path = "../fuzzy" }
fs = { path = "../fs" } fs = { path = "../fs" }

View file

@ -1,3 +1,4 @@
use client::{telemetry::Telemetry, TelemetrySettings};
use feature_flags::FeatureFlagAppExt; use feature_flags::FeatureFlagAppExt;
use fs::Fs; use fs::Fs;
use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
@ -19,7 +20,8 @@ pub fn init(cx: &mut AppContext) {
pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) { pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
workspace.toggle_modal(cx, |workspace, cx| { workspace.toggle_modal(cx, |workspace, cx| {
let fs = workspace.app_state().fs.clone(); let fs = workspace.app_state().fs.clone();
cx.add_view(|cx| ThemeSelector::new(ThemeSelectorDelegate::new(fs, cx), cx)) let telemetry = workspace.client().telemetry().clone();
cx.add_view(|cx| ThemeSelector::new(ThemeSelectorDelegate::new(fs, telemetry, cx), cx))
}); });
} }
@ -48,10 +50,15 @@ pub struct ThemeSelectorDelegate {
original_theme: Arc<Theme>, original_theme: Arc<Theme>,
selection_completed: bool, selection_completed: bool,
selected_index: usize, selected_index: usize,
telemetry: Arc<Telemetry>,
} }
impl ThemeSelectorDelegate { impl ThemeSelectorDelegate {
fn new(fs: Arc<dyn Fs>, cx: &mut ViewContext<ThemeSelector>) -> Self { fn new(
fs: Arc<dyn Fs>,
telemetry: Arc<Telemetry>,
cx: &mut ViewContext<ThemeSelector>,
) -> Self {
let original_theme = theme::current(cx).clone(); let original_theme = theme::current(cx).clone();
let staff_mode = cx.is_staff(); let staff_mode = cx.is_staff();
@ -74,6 +81,7 @@ impl ThemeSelectorDelegate {
original_theme: original_theme.clone(), original_theme: original_theme.clone(),
selected_index: 0, selected_index: 0,
selection_completed: false, selection_completed: false,
telemetry,
}; };
this.select_if_matching(&original_theme.meta.name); this.select_if_matching(&original_theme.meta.name);
this this
@ -124,6 +132,11 @@ impl PickerDelegate for ThemeSelectorDelegate {
self.selection_completed = true; self.selection_completed = true;
let theme_name = theme::current(cx).meta.name.clone(); let theme_name = theme::current(cx).meta.name.clone();
let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
self.telemetry
.report_setting_event(telemetry_settings, "theme", theme_name.to_string());
update_settings_file::<ThemeSettings>(self.fs.clone(), cx, |settings| { update_settings_file::<ThemeSettings>(self.fs.clone(), cx, |settings| {
settings.theme = Some(theme_name); settings.theme = Some(theme_name);
}); });

View file

@ -9,17 +9,18 @@ path = "src/theme_selector.rs"
doctest = false doctest = false
[dependencies] [dependencies]
client = { package = "client2", path = "../client2" }
editor = { package = "editor2", path = "../editor2" } editor = { package = "editor2", path = "../editor2" }
fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
fs = { package = "fs2", path = "../fs2" }
gpui = { package = "gpui2", path = "../gpui2" }
ui = { package = "ui2", path = "../ui2" }
picker = { package = "picker2", path = "../picker2" }
theme = { package = "theme2", path = "../theme2" }
settings = { package = "settings2", path = "../settings2" }
feature_flags = { package = "feature_flags2", path = "../feature_flags2" } feature_flags = { package = "feature_flags2", path = "../feature_flags2" }
workspace = { package = "workspace2", path = "../workspace2" } fs = { package = "fs2", path = "../fs2" }
fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
gpui = { package = "gpui2", path = "../gpui2" }
picker = { package = "picker2", path = "../picker2" }
settings = { package = "settings2", path = "../settings2" }
theme = { package = "theme2", path = "../theme2" }
ui = { package = "ui2", path = "../ui2" }
util = { path = "../util" } util = { path = "../util" }
workspace = { package = "workspace2", path = "../workspace2" }
log.workspace = true log.workspace = true
parking_lot.workspace = true parking_lot.workspace = true
postage.workspace = true postage.workspace = true

View file

@ -1,3 +1,4 @@
use client::{telemetry::Telemetry, TelemetrySettings};
use feature_flags::FeatureFlagAppExt; use feature_flags::FeatureFlagAppExt;
use fs::Fs; use fs::Fs;
use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
@ -6,7 +7,7 @@ use gpui::{
VisualContext, WeakView, VisualContext, WeakView,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use settings::{update_settings_file, SettingsStore}; use settings::{update_settings_file, Settings, SettingsStore};
use std::sync::Arc; use std::sync::Arc;
use theme::{Theme, ThemeMeta, ThemeRegistry, ThemeSettings}; use theme::{Theme, ThemeMeta, ThemeRegistry, ThemeSettings};
use ui::{prelude::*, v_stack, ListItem, ListItemSpacing}; use ui::{prelude::*, v_stack, ListItem, ListItemSpacing};
@ -26,9 +27,10 @@ pub fn init(cx: &mut AppContext) {
pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) { pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
let fs = workspace.app_state().fs.clone(); let fs = workspace.app_state().fs.clone();
let telemetry = workspace.client().telemetry().clone();
workspace.toggle_modal(cx, |cx| { workspace.toggle_modal(cx, |cx| {
ThemeSelector::new( ThemeSelector::new(
ThemeSelectorDelegate::new(cx.view().downgrade(), fs, cx), ThemeSelectorDelegate::new(cx.view().downgrade(), fs, telemetry, cx),
cx, cx,
) )
}); });
@ -86,6 +88,7 @@ pub struct ThemeSelectorDelegate {
original_theme: Arc<Theme>, original_theme: Arc<Theme>,
selection_completed: bool, selection_completed: bool,
selected_index: usize, selected_index: usize,
telemetry: Arc<Telemetry>,
view: WeakView<ThemeSelector>, view: WeakView<ThemeSelector>,
} }
@ -93,6 +96,7 @@ impl ThemeSelectorDelegate {
fn new( fn new(
weak_view: WeakView<ThemeSelector>, weak_view: WeakView<ThemeSelector>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
telemetry: Arc<Telemetry>,
cx: &mut ViewContext<ThemeSelector>, cx: &mut ViewContext<ThemeSelector>,
) -> Self { ) -> Self {
let original_theme = cx.theme().clone(); let original_theme = cx.theme().clone();
@ -122,6 +126,7 @@ impl ThemeSelectorDelegate {
original_theme: original_theme.clone(), original_theme: original_theme.clone(),
selected_index: 0, selected_index: 0,
selection_completed: false, selection_completed: false,
telemetry,
view: weak_view, view: weak_view,
}; };
this.select_if_matching(&original_theme.name); this.select_if_matching(&original_theme.name);
@ -175,6 +180,11 @@ impl PickerDelegate for ThemeSelectorDelegate {
self.selection_completed = true; self.selection_completed = true;
let theme_name = cx.theme().name.clone(); let theme_name = cx.theme().name.clone();
let telemetry_settings = TelemetrySettings::get_global(cx).clone();
self.telemetry
.report_setting_event(telemetry_settings, "theme", theme_name.to_string());
update_settings_file::<ThemeSettings>(self.fs.clone(), cx, move |settings| { update_settings_file::<ThemeSettings>(self.fs.clone(), cx, move |settings| {
settings.theme = Some(theme_name.to_string()); settings.theme = Some(theme_name.to_string());
}); });

View file

@ -168,6 +168,11 @@ fn main() {
client.telemetry().start(installation_id, session_id, cx); client.telemetry().start(installation_id, session_id, cx);
let telemetry_settings = *settings::get::<TelemetrySettings>(cx); let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
client.telemetry().report_setting_event(
telemetry_settings,
"theme",
theme::current(cx).meta.name.to_string(),
);
let event_operation = match existing_installation_id_found { let event_operation = match existing_installation_id_found {
Some(false) => "first open", Some(false) => "first open",
_ => "open", _ => "open",

View file

@ -173,6 +173,11 @@ fn main() {
client.telemetry().start(installation_id, session_id, cx); client.telemetry().start(installation_id, session_id, cx);
let telemetry_settings = *client::TelemetrySettings::get_global(cx); let telemetry_settings = *client::TelemetrySettings::get_global(cx);
client.telemetry().report_setting_event(
telemetry_settings,
"theme",
cx.theme().name.to_string(),
);
let event_operation = match existing_installation_id_found { let event_operation = match existing_installation_id_found {
Some(false) => "first open", Some(false) => "first open",
_ => "open", _ => "open",