Add opt-out for metric reporting

co-authored-by: kay <kay@zed.dev>
This commit is contained in:
Mikayla Maki 2023-01-10 15:49:54 -08:00
parent 866f0e1344
commit 37a4de1a84
6 changed files with 76 additions and 19 deletions

View file

@ -25,6 +25,7 @@ use postage::watch;
use rand::prelude::*; use rand::prelude::*;
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, PeerId, RequestMessage}; use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, PeerId, RequestMessage};
use serde::Deserialize; use serde::Deserialize;
use settings::{Settings, TelemetrySettings};
use std::{ use std::{
any::TypeId, any::TypeId,
collections::HashMap, collections::HashMap,
@ -423,7 +424,9 @@ impl Client {
})); }));
} }
Status::SignedOut | Status::UpgradeRequired => { Status::SignedOut | Status::UpgradeRequired => {
self.telemetry.set_authenticated_user_info(None, false); let telemetry_settings = cx.read(|cx| cx.global::<Settings>().telemetry());
self.telemetry
.set_authenticated_user_info(None, false, telemetry_settings);
state._reconnect_task.take(); state._reconnect_task.take();
} }
_ => {} _ => {}
@ -706,7 +709,13 @@ impl Client {
credentials = read_credentials_from_keychain(cx); credentials = read_credentials_from_keychain(cx);
read_from_keychain = credentials.is_some(); read_from_keychain = credentials.is_some();
if read_from_keychain { if read_from_keychain {
self.report_event("read credentials from keychain", Default::default()); cx.read(|cx| {
self.report_event(
"read credentials from keychain",
Default::default(),
cx.global::<Settings>().telemetry(),
);
});
} }
} }
if credentials.is_none() { if credentials.is_none() {
@ -997,6 +1006,8 @@ impl Client {
let executor = cx.background(); let executor = cx.background();
let telemetry = self.telemetry.clone(); let telemetry = self.telemetry.clone();
let http = self.http.clone(); let http = self.http.clone();
let metrics_enabled = cx.read(|cx| cx.global::<Settings>().telemetry());
executor.clone().spawn(async move { executor.clone().spawn(async move {
// Generate a pair of asymmetric encryption keys. The public key will be used by the // Generate a pair of asymmetric encryption keys. The public key will be used by the
// zed server to encrypt the user's access token, so that it can'be intercepted by // zed server to encrypt the user's access token, so that it can'be intercepted by
@ -1079,7 +1090,11 @@ impl Client {
.context("failed to decrypt access token")?; .context("failed to decrypt access token")?;
platform.activate(true); platform.activate(true);
telemetry.report_event("authenticate with browser", Default::default()); telemetry.report_event(
"authenticate with browser",
Default::default(),
metrics_enabled,
);
Ok(Credentials { Ok(Credentials {
user_id: user_id.parse()?, user_id: user_id.parse()?,
@ -1287,8 +1302,14 @@ impl Client {
self.telemetry.start(); self.telemetry.start();
} }
pub fn report_event(&self, kind: &str, properties: Value) { pub fn report_event(
self.telemetry.report_event(kind, properties.clone()); &self,
kind: &str,
properties: Value,
telemetry_settings: TelemetrySettings,
) {
self.telemetry
.report_event(kind, properties.clone(), telemetry_settings);
} }
pub fn telemetry_log_file_path(&self) -> Option<PathBuf> { pub fn telemetry_log_file_path(&self) -> Option<PathBuf> {

View file

@ -10,6 +10,7 @@ use lazy_static::lazy_static;
use parking_lot::Mutex; use parking_lot::Mutex;
use serde::Serialize; use serde::Serialize;
use serde_json::json; use serde_json::json;
use settings::TelemetrySettings;
use std::{ use std::{
io::Write, io::Write,
mem, mem,
@ -184,11 +185,18 @@ impl Telemetry {
.detach(); .detach();
} }
/// This method takes the entire TelemetrySettings struct in order to force client code
/// to pull the struct out of the settings global. Do not remove!
pub fn set_authenticated_user_info( pub fn set_authenticated_user_info(
self: &Arc<Self>, self: &Arc<Self>,
metrics_id: Option<String>, metrics_id: Option<String>,
is_staff: bool, is_staff: bool,
telemetry_settings: TelemetrySettings,
) { ) {
if !telemetry_settings.metrics() {
return;
}
let this = self.clone(); let this = self.clone();
let mut state = self.state.lock(); let mut state = self.state.lock();
let device_id = state.device_id.clone(); let device_id = state.device_id.clone();
@ -221,7 +229,16 @@ impl Telemetry {
} }
} }
pub fn report_event(self: &Arc<Self>, kind: &str, properties: Value) { pub fn report_event(
self: &Arc<Self>,
kind: &str,
properties: Value,
telemetry_settings: TelemetrySettings,
) {
if !telemetry_settings.metrics() {
return;
}
let mut state = self.state.lock(); let mut state = self.state.lock();
let event = MixpanelEvent { let event = MixpanelEvent {
event: kind.to_string(), event: kind.to_string(),

View file

@ -5,6 +5,7 @@ use futures::{channel::mpsc, future, AsyncReadExt, Future, StreamExt};
use gpui::{AsyncAppContext, Entity, ImageData, ModelContext, ModelHandle, Task}; use gpui::{AsyncAppContext, Entity, ImageData, ModelContext, ModelHandle, Task};
use postage::{sink::Sink, watch}; use postage::{sink::Sink, watch};
use rpc::proto::{RequestMessage, UsersResponse}; use rpc::proto::{RequestMessage, UsersResponse};
use settings::Settings;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use util::TryFutureExt as _; use util::TryFutureExt as _;
@ -141,14 +142,11 @@ impl UserStore {
let fetch_metrics_id = let fetch_metrics_id =
client.request(proto::GetPrivateUserInfo {}).log_err(); client.request(proto::GetPrivateUserInfo {}).log_err();
let (user, info) = futures::join!(fetch_user, fetch_metrics_id); let (user, info) = futures::join!(fetch_user, fetch_metrics_id);
if let Some(info) = info {
client.telemetry.set_authenticated_user_info( client.telemetry.set_authenticated_user_info(
Some(info.metrics_id.clone()), info.as_ref().map(|info| info.metrics_id.clone()),
info.staff, info.as_ref().map(|info| info.staff).unwrap_or(false),
cx.read(|cx| cx.global::<Settings>().telemetry()),
); );
} else {
client.telemetry.set_authenticated_user_info(None, false);
}
current_user_tx.send(user).await.ok(); current_user_tx.send(user).await.ok();
} }

View file

@ -6087,10 +6087,11 @@ impl Editor {
let extension = Path::new(file.file_name(cx)) let extension = Path::new(file.file_name(cx))
.extension() .extension()
.and_then(|e| e.to_str()); .and_then(|e| e.to_str());
project project.read(cx).client().report_event(
.read(cx) name,
.client() json!({ "File Extension": extension }),
.report_event(name, json!({ "File Extension": extension })); cx.global::<Settings>().telemetry(),
);
} }
} }
} }

View file

@ -62,6 +62,15 @@ pub struct TelemetrySettings {
metrics: Option<bool>, metrics: Option<bool>,
} }
impl TelemetrySettings {
pub fn metrics(&self) -> bool {
self.metrics.unwrap()
}
pub fn diagnostics(&self) -> bool {
self.diagnostics.unwrap()
}
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct FeatureFlags { pub struct FeatureFlags {
pub experimental_themes: bool, pub experimental_themes: bool,
@ -503,6 +512,13 @@ impl Settings {
.unwrap_or_else(|| R::default()) .unwrap_or_else(|| R::default())
} }
pub fn telemetry(&self) -> TelemetrySettings {
TelemetrySettings {
diagnostics: Some(self.telemetry_diagnostics()),
metrics: Some(self.telemetry_metrics()),
}
}
pub fn telemetry_diagnostics(&self) -> bool { pub fn telemetry_diagnostics(&self) -> bool {
self.telemetry_overrides self.telemetry_overrides
.diagnostics .diagnostics

View file

@ -148,7 +148,11 @@ fn main() {
.detach(); .detach();
client.start_telemetry(); client.start_telemetry();
client.report_event("start app", Default::default()); client.report_event(
"start app",
Default::default(),
cx.global::<Settings>().telemetry(),
);
let app_state = Arc::new(AppState { let app_state = Arc::new(AppState {
languages, languages,