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}