1//! See [Telemetry in Zed](https://zed.dev/docs/telemetry) for additional information.
2
3use semantic_version::SemanticVersion;
4use serde::{Deserialize, Serialize};
5use std::{fmt::Display, sync::Arc, time::Duration};
6
7#[derive(Serialize, Deserialize, Debug)]
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)]
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}
51impl Display for AssistantKind {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 write!(
54 f,
55 "{}",
56 match self {
57 Self::Panel => "panel",
58 Self::Inline => "inline",
59 }
60 )
61 }
62}
63
64#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
65#[serde(rename_all = "snake_case")]
66pub enum AssistantPhase {
67 #[default]
68 Response,
69 Invoked,
70 Accepted,
71 Rejected,
72}
73
74impl Display for AssistantPhase {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 write!(
77 f,
78 "{}",
79 match self {
80 Self::Response => "response",
81 Self::Invoked => "invoked",
82 Self::Accepted => "accepted",
83 Self::Rejected => "rejected",
84 }
85 )
86 }
87}
88
89#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
90#[serde(tag = "type")]
91pub enum Event {
92 Editor(EditorEvent),
93 Copilot(CopilotEvent), // Needed for clients sending old copilot_event types
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}
120
121/// Deprecated since Zed v0.137.0 (2024-05-29). Replaced by InlineCompletionEvent.
122// Needed for clients sending old copilot_event types
123#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
124pub struct CopilotEvent {
125 pub suggestion_id: Option<String>,
126 pub suggestion_accepted: bool,
127 pub file_extension: Option<String>,
128}
129
130#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
131pub struct InlineCompletionEvent {
132 /// Provider of the completion suggestion (e.g. copilot, supermaven)
133 pub provider: String,
134 pub suggestion_accepted: bool,
135 pub file_extension: Option<String>,
136}
137
138#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
139pub struct CallEvent {
140 /// Operation performed: invite/join call; begin/end screenshare; share/unshare project; etc
141 pub operation: String,
142 pub room_id: Option<u64>,
143 pub channel_id: Option<u64>,
144}
145
146#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
147pub struct AssistantEvent {
148 /// Unique random identifier for each assistant tab (None for inline assist)
149 pub conversation_id: Option<String>,
150 /// The kind of assistant (Panel, Inline)
151 pub kind: AssistantKind,
152 #[serde(default)]
153 pub phase: AssistantPhase,
154 /// Name of the AI model used (gpt-4o, claude-3-5-sonnet, etc)
155 pub model: String,
156 pub response_latency: Option<Duration>,
157 pub error_message: Option<String>,
158}
159
160#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
161pub struct CpuEvent {
162 pub usage_as_percentage: f32,
163 pub core_count: u32,
164}
165
166#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
167pub struct MemoryEvent {
168 pub memory_in_bytes: u64,
169 pub virtual_memory_in_bytes: u64,
170}
171
172#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
173pub struct ActionEvent {
174 pub source: String,
175 pub action: String,
176}
177
178#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
179pub struct EditEvent {
180 pub duration: i64,
181 pub environment: String,
182}
183
184#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
185pub struct SettingEvent {
186 pub setting: String,
187 pub value: String,
188}
189
190#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
191pub struct ExtensionEvent {
192 pub extension_id: Arc<str>,
193 pub version: Arc<str>,
194}
195
196#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
197pub struct AppEvent {
198 pub operation: String,
199}
200
201#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
202pub struct ReplEvent {
203 pub kernel_language: String,
204 pub kernel_status: String,
205 pub repl_session_id: String,
206}
207
208#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
209pub struct BacktraceFrame {
210 pub ip: usize,
211 pub symbol_addr: usize,
212 pub base: Option<usize>,
213 pub symbols: Vec<String>,
214}
215
216#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
217pub struct HangReport {
218 pub backtrace: Vec<BacktraceFrame>,
219 pub app_version: Option<SemanticVersion>,
220 pub os_name: String,
221 pub os_version: Option<String>,
222 pub architecture: String,
223 /// Identifier unique to each Zed installation (differs for stable, preview, dev)
224 pub installation_id: Option<String>,
225}
226
227#[derive(Serialize, Deserialize)]
228pub struct LocationData {
229 pub file: String,
230 pub line: u32,
231}
232
233#[derive(Serialize, Deserialize)]
234pub struct Panic {
235 /// The name of the thread that panicked
236 pub thread: String,
237 /// The panic message
238 pub payload: String,
239 /// The location of the panic (file, line number)
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub location_data: Option<LocationData>,
242 pub backtrace: Vec<String>,
243 /// Zed version number
244 pub app_version: String,
245 /// Zed release channel (stable, preview, dev)
246 pub release_channel: String,
247 pub os_name: String,
248 pub os_version: Option<String>,
249 pub architecture: String,
250 /// The time the panic occurred (UNIX millisecond timestamp)
251 pub panicked_on: i64,
252 /// Identifier unique to each system Zed is installed on
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub system_id: Option<String>,
255 /// Identifier unique to each Zed installation (differs for stable, preview, dev)
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub installation_id: Option<String>,
258 /// Identifier unique to each Zed session (differs for each time you open Zed)
259 pub session_id: String,
260}
261
262#[derive(Serialize, Deserialize)]
263pub struct PanicRequest {
264 pub panic: Panic,
265}