telemetry_events.rs

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