socorro_cli/models/
processed_crash.rs1use super::StackFrame;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Serialize, Deserialize)]
5pub struct ProcessedCrash {
6 pub uuid: String,
7 #[serde(default)]
8 pub signature: Option<String>,
9 #[serde(default)]
10 pub product: Option<String>,
11 #[serde(default)]
12 pub version: Option<String>,
13 #[serde(default)]
14 pub os_name: Option<String>,
15 #[serde(default)]
16 pub os_version: Option<String>,
17
18 #[serde(default)]
19 pub crash_info: Option<CrashInfo>,
20 #[serde(default)]
21 pub moz_crash_reason: Option<String>,
22 #[serde(default)]
23 pub abort_message: Option<String>,
24
25 #[serde(default)]
26 pub android_model: Option<String>,
27 #[serde(default)]
28 pub android_version: Option<String>,
29
30 #[serde(default)]
31 pub crashing_thread: Option<usize>,
32 #[serde(default)]
33 pub threads: Option<Vec<Thread>>,
34 #[serde(default)]
35 pub json_dump: Option<serde_json::Value>,
36}
37
38#[derive(Debug, Serialize, Deserialize)]
39pub struct CrashInfo {
40 #[serde(rename = "type")]
41 pub crash_type: Option<String>,
42 pub address: Option<String>,
43 pub crashing_thread: Option<usize>,
44}
45
46#[derive(Debug, Serialize, Deserialize)]
47pub struct Thread {
48 pub thread: Option<usize>,
49 pub thread_name: Option<String>,
50 pub frames: Vec<StackFrame>,
51}
52
53#[derive(Debug, Clone)]
54pub struct ThreadSummary {
55 pub thread_index: usize,
56 pub thread_name: Option<String>,
57 pub frames: Vec<StackFrame>,
58 pub is_crashing: bool,
59}
60
61#[derive(Debug)]
62pub struct CrashSummary {
63 pub crash_id: String,
64 pub signature: String,
65 pub reason: Option<String>,
66 pub address: Option<String>,
67 pub moz_crash_reason: Option<String>,
68 pub abort_message: Option<String>,
69
70 pub product: String,
71 pub version: String,
72 pub platform: String,
73
74 pub android_version: Option<String>,
75 pub android_model: Option<String>,
76
77 pub crashing_thread_name: Option<String>,
78 pub frames: Vec<StackFrame>,
79 pub all_threads: Vec<ThreadSummary>,
80}
81
82impl ProcessedCrash {
83 pub fn to_summary(&self, depth: usize, all_threads: bool) -> CrashSummary {
84 let crashing_thread_idx = self
85 .crashing_thread
86 .or_else(|| self.crash_info.as_ref().and_then(|ci| ci.crashing_thread))
87 .or_else(|| {
88 self.json_dump.as_ref().and_then(|jd| {
89 jd.get("crashing_thread")
90 .and_then(|v| v.as_u64())
91 .map(|v| v as usize)
92 })
93 });
94
95 let json_dump_threads: Option<Vec<Thread>> = self
96 .json_dump
97 .as_ref()
98 .and_then(|jd| jd.get("threads"))
99 .and_then(|t| serde_json::from_value(t.clone()).ok());
100
101 let threads_data = self.threads.as_ref().or(json_dump_threads.as_ref());
102
103 let (thread_name, frames, thread_summaries) = if let Some(threads) = threads_data {
104 let mut all_thread_summaries = Vec::new();
105
106 if all_threads {
107 for (idx, thread) in threads.iter().enumerate() {
108 let frames: Vec<StackFrame> =
109 thread.frames.iter().take(depth).cloned().collect();
110 all_thread_summaries.push(ThreadSummary {
111 thread_index: idx,
112 thread_name: thread.thread_name.clone(),
113 frames,
114 is_crashing: Some(idx) == crashing_thread_idx,
115 });
116 }
117 }
118
119 if let Some(idx) = crashing_thread_idx {
120 if let Some(thread) = threads.get(idx) {
121 let frames: Vec<StackFrame> =
122 thread.frames.iter().take(depth).cloned().collect();
123 (thread.thread_name.clone(), frames, all_thread_summaries)
124 } else {
125 (None, Vec::new(), all_thread_summaries)
126 }
127 } else {
128 (None, Vec::new(), all_thread_summaries)
129 }
130 } else {
131 (None, Vec::new(), Vec::new())
132 };
133
134 let json_dump_crash_info: Option<CrashInfo> = self
135 .json_dump
136 .as_ref()
137 .and_then(|jd| jd.get("crash_info"))
138 .and_then(|ci| serde_json::from_value(ci.clone()).ok());
139
140 let crash_info = self.crash_info.as_ref().or(json_dump_crash_info.as_ref());
141
142 CrashSummary {
143 crash_id: self.uuid.clone(),
144 signature: self
145 .signature
146 .clone()
147 .unwrap_or_else(|| "Unknown".to_string()),
148 reason: crash_info.and_then(|ci| ci.crash_type.clone()),
149 address: crash_info.and_then(|ci| ci.address.clone()),
150 moz_crash_reason: self.moz_crash_reason.clone(),
151 abort_message: self.abort_message.clone(),
152 product: self
153 .product
154 .clone()
155 .unwrap_or_else(|| "Unknown".to_string()),
156 version: self
157 .version
158 .clone()
159 .unwrap_or_else(|| "Unknown".to_string()),
160 platform: format!(
161 "{}{}",
162 self.os_name.as_deref().unwrap_or("Unknown"),
163 self.os_version
164 .as_ref()
165 .map(|v| format!(" {}", v))
166 .unwrap_or_default()
167 ),
168 android_version: self.android_version.clone(),
169 android_model: self.android_model.clone(),
170 crashing_thread_name: thread_name,
171 frames,
172 all_threads: thread_summaries,
173 }
174 }
175}