Skip to content

Commit ca4980d

Browse files
authored
Add system_id (#18040)
This PR adds `system_id` to telemetry, which is contained within a new `global` database (accessible by any release channel of Zed on a single system). This will help us get a more accurate understanding of user count, instead of relying on `installationd_id`, which is different per release channel. This doesn't solve the problem of a user with multiple machines, but it gets us closer. Release Notes: - N/A
1 parent 5e6d181 commit ca4980d

File tree

8 files changed

+184
-62
lines changed

8 files changed

+184
-62
lines changed

crates/client/src/telemetry.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ pub struct Telemetry {
3737

3838
struct TelemetryState {
3939
settings: TelemetrySettings,
40-
metrics_id: Option<Arc<str>>, // Per logged-in user
40+
system_id: Option<Arc<str>>, // Per system
4141
installation_id: Option<Arc<str>>, // Per app installation (different for dev, nightly, preview, and stable)
4242
session_id: Option<String>, // Per app launch
43+
metrics_id: Option<Arc<str>>, // Per logged-in user
4344
release_channel: Option<&'static str>,
4445
architecture: &'static str,
4546
events_queue: Vec<EventWrapper>,
@@ -191,9 +192,10 @@ impl Telemetry {
191192
settings: *TelemetrySettings::get_global(cx),
192193
architecture: env::consts::ARCH,
193194
release_channel,
195+
system_id: None,
194196
installation_id: None,
195-
metrics_id: None,
196197
session_id: None,
198+
metrics_id: None,
197199
events_queue: Vec::new(),
198200
flush_events_task: None,
199201
log_file: None,
@@ -283,11 +285,13 @@ impl Telemetry {
283285

284286
pub fn start(
285287
self: &Arc<Self>,
288+
system_id: Option<String>,
286289
installation_id: Option<String>,
287290
session_id: String,
288291
cx: &mut AppContext,
289292
) {
290293
let mut state = self.state.lock();
294+
state.system_id = system_id.map(|id| id.into());
291295
state.installation_id = installation_id.map(|id| id.into());
292296
state.session_id = Some(session_id);
293297
state.app_version = release_channel::AppVersion::global(cx).to_string();
@@ -637,9 +641,10 @@ impl Telemetry {
637641
let state = this.state.lock();
638642

639643
let request_body = EventRequestBody {
644+
system_id: state.system_id.as_deref().map(Into::into),
640645
installation_id: state.installation_id.as_deref().map(Into::into),
641-
metrics_id: state.metrics_id.as_deref().map(Into::into),
642646
session_id: state.session_id.clone(),
647+
metrics_id: state.metrics_id.as_deref().map(Into::into),
643648
is_staff: state.is_staff,
644649
app_version: state.app_version.clone(),
645650
os_name: state.os_name.clone(),
@@ -711,14 +716,15 @@ mod tests {
711716
Utc.with_ymd_and_hms(1990, 4, 12, 12, 0, 0).unwrap(),
712717
));
713718
let http = FakeHttpClient::with_200_response();
719+
let system_id = Some("system_id".to_string());
714720
let installation_id = Some("installation_id".to_string());
715721
let session_id = "session_id".to_string();
716722

717723
cx.update(|cx| {
718724
let telemetry = Telemetry::new(clock.clone(), http, cx);
719725

720726
telemetry.state.lock().max_queue_size = 4;
721-
telemetry.start(installation_id, session_id, cx);
727+
telemetry.start(system_id, installation_id, session_id, cx);
722728

723729
assert!(is_empty_state(&telemetry));
724730

@@ -796,13 +802,14 @@ mod tests {
796802
Utc.with_ymd_and_hms(1990, 4, 12, 12, 0, 0).unwrap(),
797803
));
798804
let http = FakeHttpClient::with_200_response();
805+
let system_id = Some("system_id".to_string());
799806
let installation_id = Some("installation_id".to_string());
800807
let session_id = "session_id".to_string();
801808

802809
cx.update(|cx| {
803810
let telemetry = Telemetry::new(clock.clone(), http, cx);
804811
telemetry.state.lock().max_queue_size = 4;
805-
telemetry.start(installation_id, session_id, cx);
812+
telemetry.start(system_id, installation_id, session_id, cx);
806813

807814
assert!(is_empty_state(&telemetry));
808815

crates/collab/src/api/events.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ pub async fn post_crash(
149149
installation_id = %installation_id,
150150
description = %description,
151151
backtrace = %summary,
152-
"crash report");
152+
"crash report"
153+
);
153154

154155
if let Some(slack_panics_webhook) = app.config.slack_panics_webhook.clone() {
155156
let payload = slack::WebhookBody::new(|w| {
@@ -627,7 +628,9 @@ where
627628

628629
#[derive(Serialize, Debug, clickhouse::Row)]
629630
pub struct EditorEventRow {
631+
system_id: String,
630632
installation_id: String,
633+
session_id: Option<String>,
631634
metrics_id: String,
632635
operation: String,
633636
app_version: String,
@@ -647,7 +650,6 @@ pub struct EditorEventRow {
647650
historical_event: bool,
648651
architecture: String,
649652
is_staff: Option<bool>,
650-
session_id: Option<String>,
651653
major: Option<i32>,
652654
minor: Option<i32>,
653655
patch: Option<i32>,
@@ -677,9 +679,10 @@ impl EditorEventRow {
677679
os_name: body.os_name.clone(),
678680
os_version: body.os_version.clone().unwrap_or_default(),
679681
architecture: body.architecture.clone(),
682+
system_id: body.system_id.clone().unwrap_or_default(),
680683
installation_id: body.installation_id.clone().unwrap_or_default(),
681-
metrics_id: body.metrics_id.clone().unwrap_or_default(),
682684
session_id: body.session_id.clone(),
685+
metrics_id: body.metrics_id.clone().unwrap_or_default(),
683686
is_staff: body.is_staff,
684687
time: time.timestamp_millis(),
685688
operation: event.operation,
@@ -699,6 +702,7 @@ impl EditorEventRow {
699702
#[derive(Serialize, Debug, clickhouse::Row)]
700703
pub struct InlineCompletionEventRow {
701704
installation_id: String,
705+
session_id: Option<String>,
702706
provider: String,
703707
suggestion_accepted: bool,
704708
app_version: String,
@@ -713,7 +717,6 @@ pub struct InlineCompletionEventRow {
713717
city: String,
714718
time: i64,
715719
is_staff: Option<bool>,
716-
session_id: Option<String>,
717720
major: Option<i32>,
718721
minor: Option<i32>,
719722
patch: Option<i32>,
@@ -879,7 +882,9 @@ impl AssistantEventRow {
879882

880883
#[derive(Debug, clickhouse::Row, Serialize)]
881884
pub struct CpuEventRow {
885+
system_id: Option<String>,
882886
installation_id: Option<String>,
887+
session_id: Option<String>,
883888
is_staff: Option<bool>,
884889
usage_as_percentage: f32,
885890
core_count: u32,
@@ -888,7 +893,6 @@ pub struct CpuEventRow {
888893
os_name: String,
889894
os_version: String,
890895
time: i64,
891-
session_id: Option<String>,
892896
// pub normalized_cpu_usage: f64, MATERIALIZED
893897
major: Option<i32>,
894898
minor: Option<i32>,
@@ -917,6 +921,7 @@ impl CpuEventRow {
917921
release_channel: body.release_channel.clone().unwrap_or_default(),
918922
os_name: body.os_name.clone(),
919923
os_version: body.os_version.clone().unwrap_or_default(),
924+
system_id: body.system_id.clone(),
920925
installation_id: body.installation_id.clone(),
921926
session_id: body.session_id.clone(),
922927
is_staff: body.is_staff,
@@ -940,6 +945,7 @@ pub struct MemoryEventRow {
940945
os_version: String,
941946

942947
// ClientEventBase
948+
system_id: Option<String>,
943949
installation_id: Option<String>,
944950
session_id: Option<String>,
945951
is_staff: Option<bool>,
@@ -971,6 +977,7 @@ impl MemoryEventRow {
971977
release_channel: body.release_channel.clone().unwrap_or_default(),
972978
os_name: body.os_name.clone(),
973979
os_version: body.os_version.clone().unwrap_or_default(),
980+
system_id: body.system_id.clone(),
974981
installation_id: body.installation_id.clone(),
975982
session_id: body.session_id.clone(),
976983
is_staff: body.is_staff,
@@ -994,6 +1001,7 @@ pub struct AppEventRow {
9941001
os_version: String,
9951002

9961003
// ClientEventBase
1004+
system_id: Option<String>,
9971005
installation_id: Option<String>,
9981006
session_id: Option<String>,
9991007
is_staff: Option<bool>,
@@ -1024,6 +1032,7 @@ impl AppEventRow {
10241032
release_channel: body.release_channel.clone().unwrap_or_default(),
10251033
os_name: body.os_name.clone(),
10261034
os_version: body.os_version.clone().unwrap_or_default(),
1035+
system_id: body.system_id.clone(),
10271036
installation_id: body.installation_id.clone(),
10281037
session_id: body.session_id.clone(),
10291038
is_staff: body.is_staff,
@@ -1046,6 +1055,7 @@ pub struct SettingEventRow {
10461055
os_version: String,
10471056

10481057
// ClientEventBase
1058+
system_id: Option<String>,
10491059
installation_id: Option<String>,
10501060
session_id: Option<String>,
10511061
is_staff: Option<bool>,
@@ -1076,6 +1086,7 @@ impl SettingEventRow {
10761086
release_channel: body.release_channel.clone().unwrap_or_default(),
10771087
os_name: body.os_name.clone(),
10781088
os_version: body.os_version.clone().unwrap_or_default(),
1089+
system_id: body.system_id.clone(),
10791090
installation_id: body.installation_id.clone(),
10801091
session_id: body.session_id.clone(),
10811092
is_staff: body.is_staff,
@@ -1099,6 +1110,7 @@ pub struct ExtensionEventRow {
10991110
os_version: String,
11001111

11011112
// ClientEventBase
1113+
system_id: Option<String>,
11021114
installation_id: Option<String>,
11031115
session_id: Option<String>,
11041116
is_staff: Option<bool>,
@@ -1134,6 +1146,7 @@ impl ExtensionEventRow {
11341146
release_channel: body.release_channel.clone().unwrap_or_default(),
11351147
os_name: body.os_name.clone(),
11361148
os_version: body.os_version.clone().unwrap_or_default(),
1149+
system_id: body.system_id.clone(),
11371150
installation_id: body.installation_id.clone(),
11381151
session_id: body.session_id.clone(),
11391152
is_staff: body.is_staff,
@@ -1224,6 +1237,7 @@ pub struct EditEventRow {
12241237
os_version: String,
12251238

12261239
// ClientEventBase
1240+
system_id: Option<String>,
12271241
installation_id: Option<String>,
12281242
// Note: This column name has a typo in the ClickHouse table.
12291243
#[serde(rename = "sesssion_id")]
@@ -1261,6 +1275,7 @@ impl EditEventRow {
12611275
release_channel: body.release_channel.clone().unwrap_or_default(),
12621276
os_name: body.os_name.clone(),
12631277
os_version: body.os_version.clone().unwrap_or_default(),
1278+
system_id: body.system_id.clone(),
12641279
installation_id: body.installation_id.clone(),
12651280
session_id: body.session_id.clone(),
12661281
is_staff: body.is_staff,

crates/db/src/db.rs

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,14 @@ pub use smol;
1111
pub use sqlez;
1212
pub use sqlez_macros;
1313

14-
use release_channel::ReleaseChannel;
1514
pub use release_channel::RELEASE_CHANNEL;
1615
use sqlez::domain::Migrator;
1716
use sqlez::thread_safe_connection::ThreadSafeConnection;
1817
use sqlez_macros::sql;
19-
use std::env;
2018
use std::future::Future;
2119
use std::path::Path;
22-
use std::sync::atomic::{AtomicBool, Ordering};
23-
use std::sync::LazyLock;
20+
use std::sync::{atomic::Ordering, LazyLock};
21+
use std::{env, sync::atomic::AtomicBool};
2422
use util::{maybe, ResultExt};
2523

2624
const CONNECTION_INITIALIZE_QUERY: &str = sql!(
@@ -47,16 +45,12 @@ pub static ALL_FILE_DB_FAILED: LazyLock<AtomicBool> = LazyLock::new(|| AtomicBoo
4745
/// This will retry a couple times if there are failures. If opening fails once, the db directory
4846
/// is moved to a backup folder and a new one is created. If that fails, a shared in memory db is created.
4947
/// In either case, static variables are set so that the user can be notified.
50-
pub async fn open_db<M: Migrator + 'static>(
51-
db_dir: &Path,
52-
release_channel: &ReleaseChannel,
53-
) -> ThreadSafeConnection<M> {
48+
pub async fn open_db<M: Migrator + 'static>(db_dir: &Path, scope: &str) -> ThreadSafeConnection<M> {
5449
if *ZED_STATELESS {
5550
return open_fallback_db().await;
5651
}
5752

58-
let release_channel_name = release_channel.dev_name();
59-
let main_db_dir = db_dir.join(Path::new(&format!("0-{}", release_channel_name)));
53+
let main_db_dir = db_dir.join(format!("0-{}", scope));
6054

6155
let connection = maybe!(async {
6256
smol::fs::create_dir_all(&main_db_dir)
@@ -118,7 +112,7 @@ pub async fn open_test_db<M: Migrator>(db_name: &str) -> ThreadSafeConnection<M>
118112
/// Implements a basic DB wrapper for a given domain
119113
#[macro_export]
120114
macro_rules! define_connection {
121-
(pub static ref $id:ident: $t:ident<()> = $migrations:expr;) => {
115+
(pub static ref $id:ident: $t:ident<()> = $migrations:expr; $($global:ident)?) => {
122116
pub struct $t($crate::sqlez::thread_safe_connection::ThreadSafeConnection<$t>);
123117

124118
impl ::std::ops::Deref for $t {
@@ -139,18 +133,23 @@ macro_rules! define_connection {
139133
}
140134
}
141135

142-
use std::sync::LazyLock;
143136
#[cfg(any(test, feature = "test-support"))]
144-
pub static $id: LazyLock<$t> = LazyLock::new(|| {
137+
pub static $id: std::sync::LazyLock<$t> = std::sync::LazyLock::new(|| {
145138
$t($crate::smol::block_on($crate::open_test_db(stringify!($id))))
146139
});
147140

148141
#[cfg(not(any(test, feature = "test-support")))]
149-
pub static $id: LazyLock<$t> = LazyLock::new(|| {
150-
$t($crate::smol::block_on($crate::open_db($crate::database_dir(), &$crate::RELEASE_CHANNEL)))
142+
pub static $id: std::sync::LazyLock<$t> = std::sync::LazyLock::new(|| {
143+
let db_dir = $crate::database_dir();
144+
let scope = if false $(|| stringify!($global) == "global")? {
145+
"global"
146+
} else {
147+
$crate::RELEASE_CHANNEL.dev_name()
148+
};
149+
$t($crate::smol::block_on($crate::open_db(db_dir, scope)))
151150
});
152151
};
153-
(pub static ref $id:ident: $t:ident<$($d:ty),+> = $migrations:expr;) => {
152+
(pub static ref $id:ident: $t:ident<$($d:ty),+> = $migrations:expr; $($global:ident)?) => {
154153
pub struct $t($crate::sqlez::thread_safe_connection::ThreadSafeConnection<( $($d),+, $t )>);
155154

156155
impl ::std::ops::Deref for $t {
@@ -178,7 +177,13 @@ macro_rules! define_connection {
178177

179178
#[cfg(not(any(test, feature = "test-support")))]
180179
pub static $id: std::sync::LazyLock<$t> = std::sync::LazyLock::new(|| {
181-
$t($crate::smol::block_on($crate::open_db($crate::database_dir(), &$crate::RELEASE_CHANNEL)))
180+
let db_dir = $crate::database_dir();
181+
let scope = if false $(|| stringify!($global) == "global")? {
182+
"global"
183+
} else {
184+
$crate::RELEASE_CHANNEL.dev_name()
185+
};
186+
$t($crate::smol::block_on($crate::open_db(db_dir, scope)))
182187
});
183188
};
184189
}
@@ -225,7 +230,11 @@ mod tests {
225230
.prefix("DbTests")
226231
.tempdir()
227232
.unwrap();
228-
let _bad_db = open_db::<BadDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
233+
let _bad_db = open_db::<BadDB>(
234+
tempdir.path(),
235+
&release_channel::ReleaseChannel::Dev.dev_name(),
236+
)
237+
.await;
229238
}
230239

231240
/// Test that DB exists but corrupted (causing recreate)
@@ -262,13 +271,19 @@ mod tests {
262271
.tempdir()
263272
.unwrap();
264273
{
265-
let corrupt_db =
266-
open_db::<CorruptedDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
274+
let corrupt_db = open_db::<CorruptedDB>(
275+
tempdir.path(),
276+
&release_channel::ReleaseChannel::Dev.dev_name(),
277+
)
278+
.await;
267279
assert!(corrupt_db.persistent());
268280
}
269281

270-
let good_db =
271-
open_db::<GoodDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
282+
let good_db = open_db::<GoodDB>(
283+
tempdir.path(),
284+
&release_channel::ReleaseChannel::Dev.dev_name(),
285+
)
286+
.await;
272287
assert!(
273288
good_db.select_row::<usize>("SELECT * FROM test2").unwrap()()
274289
.unwrap()
@@ -311,8 +326,11 @@ mod tests {
311326
.unwrap();
312327
{
313328
// Setup the bad database
314-
let corrupt_db =
315-
open_db::<CorruptedDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
329+
let corrupt_db = open_db::<CorruptedDB>(
330+
tempdir.path(),
331+
&release_channel::ReleaseChannel::Dev.dev_name(),
332+
)
333+
.await;
316334
assert!(corrupt_db.persistent());
317335
}
318336

@@ -323,7 +341,7 @@ mod tests {
323341
let guard = thread::spawn(move || {
324342
let good_db = smol::block_on(open_db::<GoodDB>(
325343
tmp_path.as_path(),
326-
&release_channel::ReleaseChannel::Dev,
344+
&release_channel::ReleaseChannel::Dev.dev_name(),
327345
));
328346
assert!(
329347
good_db.select_row::<usize>("SELECT * FROM test2").unwrap()()

0 commit comments

Comments
 (0)