telemetry_events.rs

  1//! See [Telemetry in Zed](https://zed.dev/docs/telemetry) for additional information.
  2
  3use language::LanguageName;
  4use semantic_version::SemanticVersion;
  5use serde::{Deserialize, Serialize};
  6use std::{fmt::Display, sync::Arc, time::Duration};
  7
  8#[derive(Serialize, Deserialize, Debug)]
  9pub struct EventRequestBody {
 10    /// Identifier unique to each system Zed is installed on
 11    pub system_id: Option<String>,
 12    /// Identifier unique to each Zed installation (differs for stable, preview, dev)
 13    pub installation_id: Option<String>,
 14    /// Identifier unique to each logged in Zed user (randomly generated on first sign in)
 15    /// Identifier unique to each Zed session (differs for each time you open Zed)
 16    pub session_id: Option<String>,
 17    pub metrics_id: Option<String>,
 18    /// True for Zed staff, otherwise false
 19    pub is_staff: Option<bool>,
 20    /// Zed version number
 21    pub app_version: String,
 22    pub os_name: String,
 23    pub os_version: Option<String>,
 24    pub architecture: String,
 25    /// Zed release channel (stable, preview, dev)
 26    pub release_channel: Option<String>,
 27    pub events: Vec<EventWrapper>,
 28}
 29
 30impl EventRequestBody {
 31    pub fn semver(&self) -> Option<SemanticVersion> {
 32        self.app_version.parse().ok()
 33    }
 34}
 35
 36#[derive(Serialize, Deserialize, Debug)]
 37pub struct EventWrapper {
 38    pub signed_in: bool,
 39    /// Duration between this event's timestamp and the timestamp of the first event in the current batch
 40    pub milliseconds_since_first_event: i64,
 41    /// The event itself
 42    #[serde(flatten)]
 43    pub event: Event,
 44}
 45
 46#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 47#[serde(rename_all = "snake_case")]
 48pub enum AssistantKind {
 49    Panel,
 50    Inline,
 51}
 52impl Display for AssistantKind {
 53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 54        write!(
 55            f,
 56            "{}",
 57            match self {
 58                Self::Panel => "panel",
 59                Self::Inline => "inline",
 60            }
 61        )
 62    }
 63}
 64
 65#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
 66#[serde(rename_all = "snake_case")]
 67pub enum AssistantPhase {
 68    #[default]
 69    Response,
 70    Invoked,
 71    Accepted,
 72    Rejected,
 73}
 74
 75impl Display for AssistantPhase {
 76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 77        write!(
 78            f,
 79            "{}",
 80            match self {
 81                Self::Response => "response",
 82                Self::Invoked => "invoked",
 83                Self::Accepted => "accepted",
 84                Self::Rejected => "rejected",
 85            }
 86        )
 87    }
 88}
 89
 90#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 91#[serde(tag = "type")]
 92pub enum Event {
 93    Editor(EditorEvent),
 94    InlineCompletion(InlineCompletionEvent),
 95    Call(CallEvent),
 96    Assistant(AssistantEvent),
 97    Cpu(CpuEvent),
 98    Memory(MemoryEvent),
 99    App(AppEvent),
100    Setting(SettingEvent),
101    Extension(ExtensionEvent),
102    Edit(EditEvent),
103    Action(ActionEvent),
104    Repl(ReplEvent),
105}
106
107#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
108pub struct EditorEvent {
109    /// The editor operation performed (open, save)
110    pub operation: String,
111    /// The extension of the file that was opened or saved
112    pub file_extension: Option<String>,
113    /// Whether the user is in vim mode or not
114    pub vim_mode: bool,
115    /// Whether the user has copilot enabled or not
116    pub copilot_enabled: bool,
117    /// Whether the user has copilot enabled for the language of the file opened or saved
118    pub copilot_enabled_for_language: bool,
119    /// Whether the client is opening/saving a local file or a remote file via SSH
120    #[serde(default)]
121    pub is_via_ssh: bool,
122}
123
124#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
125pub struct InlineCompletionEvent {
126    /// Provider of the completion suggestion (e.g. copilot, supermaven)
127    pub provider: String,
128    pub suggestion_accepted: bool,
129    pub file_extension: Option<String>,
130}
131
132#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
133pub struct CallEvent {
134    /// Operation performed: invite/join call; begin/end screenshare; share/unshare project; etc
135    pub operation: String,
136    pub room_id: Option<u64>,
137    pub channel_id: Option<u64>,
138}
139
140#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
141pub struct AssistantEvent {
142    /// Unique random identifier for each assistant tab (None for inline assist)
143    pub conversation_id: Option<String>,
144    /// The kind of assistant (Panel, Inline)
145    pub kind: AssistantKind,
146    #[serde(default)]
147    pub phase: AssistantPhase,
148    /// Name of the AI model used (gpt-4o, claude-3-5-sonnet, etc)
149    pub model: String,
150    pub model_provider: String,
151    pub response_latency: Option<Duration>,
152    pub error_message: Option<String>,
153    pub language_name: Option<LanguageName>,
154}
155
156#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
157pub struct CpuEvent {
158    pub usage_as_percentage: f32,
159    pub core_count: u32,
160}
161
162#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
163pub struct MemoryEvent {
164    pub memory_in_bytes: u64,
165    pub virtual_memory_in_bytes: u64,
166}
167
168#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
169pub struct ActionEvent {
170    pub source: String,
171    pub action: String,
172}
173
174#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
175pub struct EditEvent {
176    pub duration: i64,
177    pub environment: String,
178    /// Whether the edits occurred locally or remotely via SSH
179    #[serde(default)]
180    pub is_via_ssh: bool,
181}
182
183#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
184pub struct SettingEvent {
185    pub setting: String,
186    pub value: String,
187}
188
189#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
190pub struct ExtensionEvent {
191    pub extension_id: Arc<str>,
192    pub version: Arc<str>,
193}
194
195#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
196pub struct AppEvent {
197    pub operation: String,
198}
199
200#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
201pub struct ReplEvent {
202    pub kernel_language: String,
203    pub kernel_status: String,
204    pub repl_session_id: String,
205}
206
207#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
208pub struct BacktraceFrame {
209    pub ip: usize,
210    pub symbol_addr: usize,
211    pub base: Option<usize>,
212    pub symbols: Vec<String>,
213}
214
215#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
216pub struct HangReport {
217    pub backtrace: Vec<BacktraceFrame>,
218    pub app_version: Option<SemanticVersion>,
219    pub os_name: String,
220    pub os_version: Option<String>,
221    pub architecture: String,
222    /// Identifier unique to each Zed installation (differs for stable, preview, dev)
223    pub installation_id: Option<String>,
224}
225
226#[derive(Serialize, Deserialize)]
227pub struct LocationData {
228    pub file: String,
229    pub line: u32,
230}
231
232#[derive(Serialize, Deserialize)]
233pub struct Panic {
234    /// The name of the thread that panicked
235    pub thread: String,
236    /// The panic message
237    pub payload: String,
238    /// The location of the panic (file, line number)
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub location_data: Option<LocationData>,
241    pub backtrace: Vec<String>,
242    /// Zed version number
243    pub app_version: String,
244    /// Zed release channel (stable, preview, dev)
245    pub release_channel: String,
246    pub os_name: String,
247    pub os_version: Option<String>,
248    pub architecture: String,
249    /// The time the panic occurred (UNIX millisecond timestamp)
250    pub panicked_on: i64,
251    /// Identifier unique to each system Zed is installed on
252    #[serde(skip_serializing_if = "Option::is_none")]
253    pub system_id: Option<String>,
254    /// Identifier unique to each Zed installation (differs for stable, preview, dev)
255    #[serde(skip_serializing_if = "Option::is_none")]
256    pub installation_id: Option<String>,
257    /// Identifier unique to each Zed session (differs for each time you open Zed)
258    pub session_id: String,
259}
260
261#[derive(Serialize, Deserialize)]
262pub struct PanicRequest {
263    pub panic: Panic,
264}