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, 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 #[serde(skip_serializing_if = "Option::is_none")]
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, Clone)]
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 InlineTerminal,
52}
53impl Display for AssistantKind {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 write!(
56 f,
57 "{}",
58 match self {
59 Self::Panel => "panel",
60 Self::Inline => "inline",
61 Self::InlineTerminal => "inline_terminal",
62 }
63 )
64 }
65}
66
67#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
68#[serde(rename_all = "snake_case")]
69pub enum AssistantPhase {
70 #[default]
71 Response,
72 Invoked,
73 Accepted,
74 Rejected,
75}
76
77impl Display for AssistantPhase {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 write!(
80 f,
81 "{}",
82 match self {
83 Self::Response => "response",
84 Self::Invoked => "invoked",
85 Self::Accepted => "accepted",
86 Self::Rejected => "rejected",
87 }
88 )
89 }
90}
91
92#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
93#[serde(tag = "type")]
94pub enum Event {
95 Flexible(FlexibleEvent),
96}
97
98#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
99pub struct FlexibleEvent {
100 pub event_type: String,
101 pub event_properties: HashMap<String, serde_json::Value>,
102}
103
104#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
105pub enum EditPredictionRating {
106 Positive,
107 Negative,
108}
109
110#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
111pub struct AssistantEventData {
112 /// Unique random identifier for each assistant tab (None for inline assist)
113 pub conversation_id: Option<String>,
114 /// Server-generated message ID (only supported for some providers)
115 pub message_id: Option<String>,
116 /// The kind of assistant (Panel, Inline)
117 pub kind: AssistantKind,
118 #[serde(default)]
119 pub phase: AssistantPhase,
120 /// Name of the AI model used (gpt-4o, claude-3-5-sonnet, etc)
121 pub model: String,
122 pub model_provider: String,
123 pub response_latency: Option<Duration>,
124 pub error_message: Option<String>,
125 pub language_name: Option<String>,
126}
127
128#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
129pub struct BacktraceFrame {
130 pub ip: usize,
131 pub symbol_addr: usize,
132 pub base: Option<usize>,
133 pub symbols: Vec<String>,
134}
135
136#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
137pub struct HangReport {
138 pub backtrace: Vec<BacktraceFrame>,
139 pub app_version: Option<SemanticVersion>,
140 pub os_name: String,
141 pub os_version: Option<String>,
142 pub architecture: String,
143 /// Identifier unique to each Zed installation (differs for stable, preview, dev)
144 pub installation_id: Option<String>,
145}
146
147#[derive(Serialize, Deserialize, Clone, Debug)]
148pub struct LocationData {
149 pub file: String,
150 pub line: u32,
151}
152
153#[derive(Serialize, Deserialize, Clone, Debug)]
154pub struct Panic {
155 /// The name of the thread that panicked
156 pub thread: String,
157 /// The panic message
158 pub payload: String,
159 /// The location of the panic (file, line number)
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub location_data: Option<LocationData>,
162 pub backtrace: Vec<String>,
163 /// Zed version number
164 pub app_version: String,
165 /// The Git commit SHA that Zed was built at.
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub app_commit_sha: Option<String>,
168 /// Zed release channel (stable, preview, dev)
169 pub release_channel: String,
170 pub target: Option<String>,
171 pub os_name: String,
172 pub os_version: Option<String>,
173 pub architecture: String,
174 /// The time the panic occurred (UNIX millisecond timestamp)
175 pub panicked_on: i64,
176 /// Identifier unique to each system Zed is installed on
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub system_id: Option<String>,
179 /// Identifier unique to each Zed installation (differs for stable, preview, dev)
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub installation_id: Option<String>,
182 /// Identifier unique to each Zed session (differs for each time you open Zed)
183 pub session_id: String,
184}
185
186#[derive(Serialize, Deserialize)]
187pub struct PanicRequest {
188 pub panic: Panic,
189}