1#![allow(clippy::trivially_copy_pass_by_ref)]
8
9use std::borrow::Cow;
10use std::cmp;
11use std::fmt;
12use std::iter::FromIterator;
13use std::net::{AddrParseError, IpAddr};
14use std::ops;
15use std::str;
16
17use ::debugid::DebugId;
18use chrono::{DateTime, Utc};
19use serde::Serializer;
20use serde::{Deserialize, Serialize};
21use thiserror::Error;
22use url::Url;
23use uuid::Uuid;
24
25use crate::utils::ts_seconds_float;
26
27pub use super::envelope::*;
28pub use super::session::*;
29
30pub mod value {
32 pub use serde_json::value::{from_value, to_value, Index, Map, Number, Value};
33}
34
35pub mod map {
37 pub use std::collections::btree_map::{BTreeMap as Map, *};
38}
39
40pub mod debugid {
42 pub use debugid::{BreakpadFormat, DebugId, ParseDebugIdError};
43}
44
45pub use self::value::Value;
47
48pub use self::map::Map;
50
51#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
58pub struct Values<T> {
59 pub values: Vec<T>,
61}
62
63impl<T> Values<T> {
64 pub fn new() -> Values<T> {
66 Values { values: Vec::new() }
67 }
68
69 pub fn is_empty(&self) -> bool {
71 self.values.is_empty()
72 }
73}
74
75impl<T> Default for Values<T> {
76 fn default() -> Self {
77 Values::new()
79 }
80}
81
82impl<T> From<Vec<T>> for Values<T> {
83 fn from(values: Vec<T>) -> Self {
84 Values { values }
85 }
86}
87
88impl<T> AsRef<[T]> for Values<T> {
89 fn as_ref(&self) -> &[T] {
90 &self.values
91 }
92}
93
94impl<T> AsMut<Vec<T>> for Values<T> {
95 fn as_mut(&mut self) -> &mut Vec<T> {
96 &mut self.values
97 }
98}
99
100impl<T> ops::Deref for Values<T> {
101 type Target = [T];
102
103 fn deref(&self) -> &Self::Target {
104 &self.values
105 }
106}
107
108impl<T> ops::DerefMut for Values<T> {
109 fn deref_mut(&mut self) -> &mut Self::Target {
110 &mut self.values
111 }
112}
113
114impl<T> FromIterator<T> for Values<T> {
115 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
116 Vec::<T>::from_iter(iter).into()
117 }
118}
119
120impl<T> Extend<T> for Values<T> {
121 fn extend<I>(&mut self, iter: I)
122 where
123 I: IntoIterator<Item = T>,
124 {
125 self.values.extend(iter)
126 }
127}
128
129impl<'a, T> IntoIterator for &'a mut Values<T> {
130 type Item = <&'a mut Vec<T> as IntoIterator>::Item;
131 type IntoIter = <&'a mut Vec<T> as IntoIterator>::IntoIter;
132
133 fn into_iter(self) -> Self::IntoIter {
134 self.values.iter_mut()
135 }
136}
137
138impl<'a, T> IntoIterator for &'a Values<T> {
139 type Item = <&'a Vec<T> as IntoIterator>::Item;
140 type IntoIter = <&'a Vec<T> as IntoIterator>::IntoIter;
141
142 fn into_iter(self) -> Self::IntoIter {
143 self.values.iter()
144 }
145}
146
147impl<T> IntoIterator for Values<T> {
148 type Item = <Vec<T> as IntoIterator>::Item;
149 type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
150
151 fn into_iter(self) -> Self::IntoIter {
152 self.values.into_iter()
153 }
154}
155
156#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
161pub struct LogEntry {
162 pub message: String,
164 #[serde(default, skip_serializing_if = "Vec::is_empty")]
166 pub params: Vec<Value>,
167}
168
169#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
171pub struct Frame {
172 #[serde(default, skip_serializing_if = "Option::is_none")]
177 pub function: Option<String>,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
184 pub symbol: Option<String>,
185 #[serde(default, skip_serializing_if = "Option::is_none")]
190 pub module: Option<String>,
191 #[serde(default, skip_serializing_if = "Option::is_none")]
196 pub package: Option<String>,
197 #[serde(default, skip_serializing_if = "Option::is_none")]
199 pub filename: Option<String>,
200 #[serde(default, skip_serializing_if = "Option::is_none")]
202 pub abs_path: Option<String>,
203 #[serde(default, skip_serializing_if = "Option::is_none")]
205 pub lineno: Option<u64>,
206 #[serde(default, skip_serializing_if = "Option::is_none")]
208 pub colno: Option<u64>,
209 #[serde(default, skip_serializing_if = "Vec::is_empty")]
211 pub pre_context: Vec<String>,
212 #[serde(default, skip_serializing_if = "Option::is_none")]
214 pub context_line: Option<String>,
215 #[serde(default, skip_serializing_if = "Vec::is_empty")]
217 pub post_context: Vec<String>,
218 #[serde(default, skip_serializing_if = "Option::is_none")]
220 pub in_app: Option<bool>,
221 #[serde(default, skip_serializing_if = "Map::is_empty")]
223 pub vars: Map<String, Value>,
224 #[serde(default, skip_serializing_if = "Option::is_none")]
226 pub image_addr: Option<Addr>,
227 #[serde(default, skip_serializing_if = "Option::is_none")]
229 pub instruction_addr: Option<Addr>,
230 #[serde(default, skip_serializing_if = "Option::is_none")]
232 pub symbol_addr: Option<Addr>,
233}
234
235#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
237pub struct TemplateInfo {
238 #[serde(default, skip_serializing_if = "Option::is_none")]
240 pub filename: Option<String>,
241 #[serde(default, skip_serializing_if = "Option::is_none")]
243 pub abs_path: Option<String>,
244 #[serde(default, skip_serializing_if = "Option::is_none")]
246 pub lineno: Option<u64>,
247 #[serde(default, skip_serializing_if = "Option::is_none")]
249 pub colno: Option<u64>,
250 #[serde(default, skip_serializing_if = "Vec::is_empty")]
252 pub pre_context: Vec<String>,
253 #[serde(default, skip_serializing_if = "Option::is_none")]
255 pub context_line: Option<String>,
256 #[serde(default, skip_serializing_if = "Vec::is_empty")]
258 pub post_context: Vec<String>,
259}
260
261#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
263pub struct Stacktrace {
264 #[serde(default)]
266 pub frames: Vec<Frame>,
267 #[serde(default, skip_serializing_if = "Option::is_none")]
269 pub frames_omitted: Option<(u64, u64)>,
270 #[serde(default, skip_serializing_if = "Map::is_empty")]
272 pub registers: Map<String, RegVal>,
273}
274
275impl Stacktrace {
276 pub fn from_frames_reversed(mut frames: Vec<Frame>) -> Option<Stacktrace> {
278 if frames.is_empty() {
279 None
280 } else {
281 frames.reverse();
282 Some(Stacktrace {
283 frames,
284 ..Default::default()
285 })
286 }
287 }
288}
289
290#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
292#[serde(untagged)]
293pub enum ThreadId {
294 Int(u64),
296 String(String),
298}
299
300impl Default for ThreadId {
301 fn default() -> ThreadId {
302 ThreadId::Int(0)
303 }
304}
305
306impl<'a> From<&'a str> for ThreadId {
307 fn from(id: &'a str) -> ThreadId {
308 ThreadId::String(id.to_string())
309 }
310}
311
312impl From<String> for ThreadId {
313 fn from(id: String) -> ThreadId {
314 ThreadId::String(id)
315 }
316}
317
318impl From<i64> for ThreadId {
319 fn from(id: i64) -> ThreadId {
320 ThreadId::Int(id as u64)
321 }
322}
323
324impl From<i32> for ThreadId {
325 fn from(id: i32) -> ThreadId {
326 ThreadId::Int(id as u64)
327 }
328}
329
330impl From<u32> for ThreadId {
331 fn from(id: u32) -> ThreadId {
332 ThreadId::Int(id as u64)
333 }
334}
335
336impl From<u16> for ThreadId {
337 fn from(id: u16) -> ThreadId {
338 ThreadId::Int(id as u64)
339 }
340}
341
342impl fmt::Display for ThreadId {
343 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344 match *self {
345 ThreadId::Int(i) => write!(f, "{}", i),
346 ThreadId::String(ref s) => write!(f, "{}", s),
347 }
348 }
349}
350
351#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
353pub struct Addr(pub u64);
354
355impl Addr {
356 pub fn is_null(&self) -> bool {
358 self.0 == 0
359 }
360}
361
362impl_hex_serde!(Addr, u64);
363
364impl From<u64> for Addr {
365 fn from(addr: u64) -> Addr {
366 Addr(addr)
367 }
368}
369
370impl From<i32> for Addr {
371 fn from(addr: i32) -> Addr {
372 Addr(addr as u64)
373 }
374}
375
376impl From<u32> for Addr {
377 fn from(addr: u32) -> Addr {
378 Addr(addr as u64)
379 }
380}
381
382impl From<usize> for Addr {
383 fn from(addr: usize) -> Addr {
384 Addr(addr as u64)
385 }
386}
387
388impl<T> From<*const T> for Addr {
389 fn from(addr: *const T) -> Addr {
390 Addr(addr as u64)
391 }
392}
393
394impl<T> From<*mut T> for Addr {
395 fn from(addr: *mut T) -> Addr {
396 Addr(addr as u64)
397 }
398}
399
400impl Into<u64> for Addr {
401 fn into(self) -> u64 {
402 self.0
403 }
404}
405
406fn is_false(value: &bool) -> bool {
407 !*value
408}
409
410#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
412pub struct RegVal(pub u64);
413
414impl_hex_serde!(RegVal, u64);
415
416impl From<u64> for RegVal {
417 fn from(addr: u64) -> RegVal {
418 RegVal(addr)
419 }
420}
421
422impl From<i32> for RegVal {
423 fn from(addr: i32) -> RegVal {
424 RegVal(addr as u64)
425 }
426}
427
428impl From<u32> for RegVal {
429 fn from(addr: u32) -> RegVal {
430 RegVal(addr as u64)
431 }
432}
433
434impl From<usize> for RegVal {
435 fn from(addr: usize) -> RegVal {
436 RegVal(addr as u64)
437 }
438}
439
440impl<T> From<*const T> for RegVal {
441 fn from(addr: *const T) -> RegVal {
442 RegVal(addr as u64)
443 }
444}
445
446impl<T> From<*mut T> for RegVal {
447 fn from(addr: *mut T) -> RegVal {
448 RegVal(addr as u64)
449 }
450}
451
452impl Into<u64> for RegVal {
453 fn into(self) -> u64 {
454 self.0
455 }
456}
457
458#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
460pub struct Thread {
461 #[serde(default, skip_serializing_if = "Option::is_none")]
463 pub id: Option<ThreadId>,
464 #[serde(default, skip_serializing_if = "Option::is_none")]
466 pub name: Option<String>,
467 #[serde(default, skip_serializing_if = "Option::is_none")]
470 pub stacktrace: Option<Stacktrace>,
471 #[serde(default, skip_serializing_if = "Option::is_none")]
473 pub raw_stacktrace: Option<Stacktrace>,
474 #[serde(default, skip_serializing_if = "is_false")]
476 pub crashed: bool,
477 #[serde(default, skip_serializing_if = "is_false")]
480 pub current: bool,
481}
482
483#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
485pub struct CError {
486 pub number: i32,
488 #[serde(default, skip_serializing_if = "Option::is_none")]
490 pub name: Option<String>,
491}
492
493impl From<i32> for CError {
494 fn from(number: i32) -> CError {
495 CError { number, name: None }
496 }
497}
498
499impl Into<i32> for CError {
500 fn into(self) -> i32 {
501 self.number
502 }
503}
504
505#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
507pub struct MachException {
508 pub exception: i32,
510 pub code: u64,
512 pub subcode: u64,
514 #[serde(default, skip_serializing_if = "Option::is_none")]
516 pub name: Option<String>,
517}
518
519#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
521pub struct PosixSignal {
522 pub number: i32,
524 #[serde(default, skip_serializing_if = "Option::is_none")]
526 pub code: Option<i32>,
527 #[serde(default, skip_serializing_if = "Option::is_none")]
529 pub name: Option<String>,
530 #[serde(default, skip_serializing_if = "Option::is_none")]
532 pub code_name: Option<String>,
533}
534
535impl From<i32> for PosixSignal {
536 fn from(number: i32) -> PosixSignal {
537 PosixSignal {
538 number,
539 code: None,
540 name: None,
541 code_name: None,
542 }
543 }
544}
545
546impl From<(i32, i32)> for PosixSignal {
547 fn from(tuple: (i32, i32)) -> PosixSignal {
548 let (number, code) = tuple;
549 PosixSignal {
550 number,
551 code: Some(code),
552 name: None,
553 code_name: None,
554 }
555 }
556}
557
558impl Into<i32> for PosixSignal {
559 fn into(self) -> i32 {
560 self.number
561 }
562}
563
564#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
566pub struct MechanismMeta {
567 #[serde(default, skip_serializing_if = "Option::is_none")]
569 pub errno: Option<CError>,
570 #[serde(default, skip_serializing_if = "Option::is_none")]
572 pub signal: Option<PosixSignal>,
573 #[serde(default, skip_serializing_if = "Option::is_none")]
575 pub mach_exception: Option<MachException>,
576}
577
578impl MechanismMeta {
579 fn is_empty(&self) -> bool {
580 self.errno.is_none() && self.signal.is_none() && self.mach_exception.is_none()
581 }
582}
583
584#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
586pub struct Mechanism {
587 #[serde(rename = "type")]
589 pub ty: String,
590 #[serde(default, skip_serializing_if = "Option::is_none")]
592 pub description: Option<String>,
593 #[serde(default, skip_serializing_if = "Option::is_none")]
595 pub help_link: Option<Url>,
596 #[serde(default, skip_serializing_if = "Option::is_none")]
598 pub handled: Option<bool>,
599 #[serde(default, skip_serializing_if = "Option::is_none")]
601 pub synthetic: Option<bool>,
602 #[serde(default, skip_serializing_if = "Map::is_empty")]
604 pub data: Map<String, Value>,
605 #[serde(default, skip_serializing_if = "MechanismMeta::is_empty")]
607 pub meta: MechanismMeta,
608}
609
610#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
612pub struct Exception {
613 #[serde(rename = "type")]
615 pub ty: String,
616 #[serde(skip_serializing_if = "Option::is_none")]
618 pub value: Option<String>,
619 #[serde(default, skip_serializing_if = "Option::is_none")]
621 pub module: Option<String>,
622 #[serde(default, skip_serializing_if = "Option::is_none")]
624 pub stacktrace: Option<Stacktrace>,
625 #[serde(default, skip_serializing_if = "Option::is_none")]
627 pub raw_stacktrace: Option<Stacktrace>,
628 #[serde(default, skip_serializing_if = "Option::is_none")]
630 pub thread_id: Option<ThreadId>,
631 #[serde(default, skip_serializing_if = "Option::is_none")]
633 pub mechanism: Option<Mechanism>,
634}
635
636#[derive(Debug, Error)]
638#[error("invalid level")]
639pub struct ParseLevelError;
640
641#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
643pub enum Level {
644 Debug,
646 Info,
648 Warning,
650 Error,
652 Fatal,
654}
655
656impl Default for Level {
657 fn default() -> Level {
658 Level::Info
659 }
660}
661
662impl str::FromStr for Level {
663 type Err = ParseLevelError;
664
665 fn from_str(string: &str) -> Result<Level, Self::Err> {
666 Ok(match string {
667 "debug" => Level::Debug,
668 "info" | "log" => Level::Info,
669 "warning" => Level::Warning,
670 "error" => Level::Error,
671 "fatal" => Level::Fatal,
672 _ => return Err(ParseLevelError),
673 })
674 }
675}
676
677impl fmt::Display for Level {
678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679 match *self {
680 Level::Debug => write!(f, "debug"),
681 Level::Info => write!(f, "info"),
682 Level::Warning => write!(f, "warning"),
683 Level::Error => write!(f, "error"),
684 Level::Fatal => write!(f, "fatal"),
685 }
686 }
687}
688
689impl Level {
690 pub fn is_debug(&self) -> bool {
692 *self == Level::Debug
693 }
694
695 pub fn is_info(&self) -> bool {
697 *self == Level::Info
698 }
699
700 pub fn is_warning(&self) -> bool {
702 *self == Level::Warning
703 }
704
705 pub fn is_error(&self) -> bool {
707 *self == Level::Error
708 }
709
710 pub fn is_fatal(&self) -> bool {
712 *self == Level::Fatal
713 }
714}
715
716impl_str_serde!(Level);
717
718mod breadcrumb {
719 use super::*;
720
721 pub fn default_timestamp() -> DateTime<Utc> {
722 Utc::now()
723 }
724
725 pub fn default_type() -> String {
726 "default".to_string()
727 }
728
729 pub fn is_default_type(ty: &str) -> bool {
730 ty == "default"
731 }
732
733 pub fn default_level() -> Level {
734 Level::Info
735 }
736}
737
738#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
740pub struct Breadcrumb {
741 #[serde(default = "breadcrumb::default_timestamp", with = "ts_seconds_float")]
743 pub timestamp: DateTime<Utc>,
744 #[serde(
746 rename = "type",
747 default = "breadcrumb::default_type",
748 skip_serializing_if = "breadcrumb::is_default_type"
749 )]
750 pub ty: String,
751 #[serde(default, skip_serializing_if = "Option::is_none")]
753 pub category: Option<String>,
754 #[serde(
757 default = "breadcrumb::default_level",
758 skip_serializing_if = "Level::is_info"
759 )]
760 pub level: Level,
761 #[serde(default, skip_serializing_if = "Option::is_none")]
763 pub message: Option<String>,
764 #[serde(default, skip_serializing_if = "Map::is_empty")]
766 pub data: Map<String, Value>,
767}
768
769impl Default for Breadcrumb {
770 fn default() -> Breadcrumb {
771 Breadcrumb {
772 timestamp: breadcrumb::default_timestamp(),
773 ty: breadcrumb::default_type(),
774 category: Default::default(),
775 level: breadcrumb::default_level(),
776 message: Default::default(),
777 data: Default::default(),
778 }
779 }
780}
781
782#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
784pub enum IpAddress {
785 Auto,
787 Exact(IpAddr),
789}
790
791impl PartialEq<IpAddr> for IpAddress {
792 fn eq(&self, other: &IpAddr) -> bool {
793 match *self {
794 IpAddress::Auto => false,
795 IpAddress::Exact(ref addr) => addr == other,
796 }
797 }
798}
799
800impl cmp::PartialOrd<IpAddr> for IpAddress {
801 fn partial_cmp(&self, other: &IpAddr) -> Option<cmp::Ordering> {
802 match *self {
803 IpAddress::Auto => None,
804 IpAddress::Exact(ref addr) => addr.partial_cmp(other),
805 }
806 }
807}
808
809impl Default for IpAddress {
810 fn default() -> IpAddress {
811 IpAddress::Auto
812 }
813}
814
815impl fmt::Display for IpAddress {
816 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
817 match *self {
818 IpAddress::Auto => write!(f, "{{{{auto}}}}"),
819 IpAddress::Exact(ref addr) => write!(f, "{}", addr),
820 }
821 }
822}
823
824impl From<IpAddr> for IpAddress {
825 fn from(addr: IpAddr) -> IpAddress {
826 IpAddress::Exact(addr)
827 }
828}
829
830impl str::FromStr for IpAddress {
831 type Err = AddrParseError;
832
833 fn from_str(string: &str) -> Result<IpAddress, AddrParseError> {
834 match string {
835 "{{auto}}" => Ok(IpAddress::Auto),
836 other => other.parse().map(IpAddress::Exact),
837 }
838 }
839}
840
841impl_str_serde!(IpAddress);
842
843#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
845pub struct User {
846 #[serde(default, skip_serializing_if = "Option::is_none")]
848 pub id: Option<String>,
849 #[serde(default, skip_serializing_if = "Option::is_none")]
851 pub email: Option<String>,
852 #[serde(default, skip_serializing_if = "Option::is_none")]
854 pub ip_address: Option<IpAddress>,
855 #[serde(default, skip_serializing_if = "Option::is_none")]
857 pub username: Option<String>,
858 #[serde(flatten)]
860 pub other: Map<String, Value>,
861}
862
863#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
865pub struct Request {
866 #[serde(default, skip_serializing_if = "Option::is_none")]
868 pub url: Option<Url>,
869 #[serde(default, skip_serializing_if = "Option::is_none")]
871 pub method: Option<String>,
872 #[serde(default, skip_serializing_if = "Option::is_none")]
875 pub data: Option<String>,
876 #[serde(default, skip_serializing_if = "Option::is_none")]
878 pub query_string: Option<String>,
879 #[serde(default, skip_serializing_if = "Option::is_none")]
881 pub cookies: Option<String>,
882 #[serde(default, skip_serializing_if = "Map::is_empty")]
884 pub headers: Map<String, String>,
885 #[serde(default, skip_serializing_if = "Map::is_empty")]
887 pub env: Map<String, String>,
888}
889
890#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
895pub struct SystemSdkInfo {
896 pub sdk_name: String,
898 pub version_major: u32,
900 pub version_minor: u32,
902 pub version_patchlevel: u32,
904}
905
906#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
908#[serde(rename_all = "snake_case", tag = "type")]
909pub enum DebugImage {
910 Apple(AppleDebugImage),
913 Symbolic(SymbolicDebugImage),
915 Proguard(ProguardDebugImage),
917}
918
919impl DebugImage {
920 pub fn type_name(&self) -> &str {
922 match *self {
923 DebugImage::Apple(..) => "apple",
924 DebugImage::Symbolic(..) => "symbolic",
925 DebugImage::Proguard(..) => "proguard",
926 }
927 }
928}
929
930macro_rules! into_debug_image {
931 ($kind:ident, $ty:ty) => {
932 impl From<$ty> for DebugImage {
933 fn from(data: $ty) -> DebugImage {
934 DebugImage::$kind(data)
935 }
936 }
937 };
938}
939
940#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
942pub struct AppleDebugImage {
943 pub name: String,
945 pub arch: Option<String>,
947 pub cpu_type: Option<u32>,
949 pub cpu_subtype: Option<u32>,
951 pub image_addr: Addr,
953 pub image_size: u64,
955 #[serde(default, skip_serializing_if = "Addr::is_null")]
957 pub image_vmaddr: Addr,
958 pub uuid: Uuid,
960}
961
962#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
964pub struct SymbolicDebugImage {
965 pub name: String,
967 pub arch: Option<String>,
969 pub image_addr: Addr,
971 pub image_size: u64,
973 #[serde(default, skip_serializing_if = "Addr::is_null")]
975 pub image_vmaddr: Addr,
976 pub id: DebugId,
978}
979
980#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
982pub struct ProguardDebugImage {
983 pub uuid: Uuid,
985}
986
987into_debug_image!(Apple, AppleDebugImage);
988into_debug_image!(Symbolic, SymbolicDebugImage);
989into_debug_image!(Proguard, ProguardDebugImage);
990
991#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
993pub struct DebugMeta {
994 #[serde(default, skip_serializing_if = "Option::is_none")]
996 pub sdk_info: Option<SystemSdkInfo>,
997 #[serde(default, skip_serializing_if = "Vec::is_empty")]
999 pub images: Vec<DebugImage>,
1000}
1001
1002impl DebugMeta {
1003 pub fn is_empty(&self) -> bool {
1007 self.sdk_info.is_none() && self.images.is_empty()
1008 }
1009}
1010
1011#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1013pub struct ClientSdkInfo {
1014 pub name: String,
1016 pub version: String,
1018 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1020 pub integrations: Vec<String>,
1021 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1023 pub packages: Vec<ClientSdkPackage>,
1024}
1025
1026#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1028pub struct ClientSdkPackage {
1029 pub name: String,
1031 pub version: String,
1033}
1034
1035#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1040#[serde(rename_all = "snake_case", tag = "type")]
1041#[non_exhaustive]
1042pub enum Context {
1043 Device(Box<DeviceContext>),
1045 Os(Box<OsContext>),
1047 Runtime(Box<RuntimeContext>),
1049 App(Box<AppContext>),
1051 Browser(Box<BrowserContext>),
1053 Trace(Box<TraceContext>),
1055 #[serde(rename = "unknown")]
1057 Other(Map<String, Value>),
1058}
1059
1060impl Context {
1061 pub fn type_name(&self) -> &str {
1063 match *self {
1064 Context::Device(..) => "device",
1065 Context::Os(..) => "os",
1066 Context::Runtime(..) => "runtime",
1067 Context::App(..) => "app",
1068 Context::Browser(..) => "browser",
1069 Context::Trace(..) => "trace",
1070 Context::Other(..) => "unknown",
1071 }
1072 }
1073}
1074
1075#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
1077#[serde(rename_all = "lowercase")]
1078pub enum Orientation {
1079 Portrait,
1081 Landscape,
1083}
1084
1085#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1087pub struct DeviceContext {
1088 #[serde(default, skip_serializing_if = "Option::is_none")]
1090 pub name: Option<String>,
1091 #[serde(default, skip_serializing_if = "Option::is_none")]
1093 pub family: Option<String>,
1094 #[serde(default, skip_serializing_if = "Option::is_none")]
1096 pub model: Option<String>,
1097 #[serde(default, skip_serializing_if = "Option::is_none")]
1099 pub model_id: Option<String>,
1100 #[serde(default, skip_serializing_if = "Option::is_none")]
1102 pub arch: Option<String>,
1103 #[serde(default, skip_serializing_if = "Option::is_none")]
1105 pub battery_level: Option<f32>,
1106 #[serde(default, skip_serializing_if = "Option::is_none")]
1108 pub orientation: Option<Orientation>,
1109 #[serde(default, skip_serializing_if = "Option::is_none")]
1111 pub simulator: Option<bool>,
1112 #[serde(default, skip_serializing_if = "Option::is_none")]
1114 pub memory_size: Option<u64>,
1115 #[serde(default, skip_serializing_if = "Option::is_none")]
1117 pub free_memory: Option<u64>,
1118 #[serde(default, skip_serializing_if = "Option::is_none")]
1120 pub usable_memory: Option<u64>,
1121 #[serde(default, skip_serializing_if = "Option::is_none")]
1123 pub storage_size: Option<u64>,
1124 #[serde(default, skip_serializing_if = "Option::is_none")]
1126 pub free_storage: Option<u64>,
1127 #[serde(default, skip_serializing_if = "Option::is_none")]
1129 pub external_storage_size: Option<u64>,
1130 #[serde(default, skip_serializing_if = "Option::is_none")]
1132 pub external_free_storage: Option<u64>,
1133 #[serde(default, skip_serializing_if = "Option::is_none")]
1135 pub boot_time: Option<DateTime<Utc>>,
1136 #[serde(default, skip_serializing_if = "Option::is_none")]
1138 pub timezone: Option<String>,
1139 #[serde(flatten)]
1141 pub other: Map<String, Value>,
1142}
1143
1144#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1146pub struct OsContext {
1147 #[serde(default, skip_serializing_if = "Option::is_none")]
1149 pub name: Option<String>,
1150 #[serde(default, skip_serializing_if = "Option::is_none")]
1152 pub version: Option<String>,
1153 #[serde(default, skip_serializing_if = "Option::is_none")]
1155 pub build: Option<String>,
1156 #[serde(default, skip_serializing_if = "Option::is_none")]
1158 pub kernel_version: Option<String>,
1159 #[serde(default, skip_serializing_if = "Option::is_none")]
1161 pub rooted: Option<bool>,
1162 #[serde(flatten)]
1164 pub other: Map<String, Value>,
1165}
1166
1167#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1169pub struct RuntimeContext {
1170 #[serde(default, skip_serializing_if = "Option::is_none")]
1172 pub name: Option<String>,
1173 #[serde(default, skip_serializing_if = "Option::is_none")]
1175 pub version: Option<String>,
1176 #[serde(flatten)]
1178 pub other: Map<String, Value>,
1179}
1180
1181#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1183pub struct AppContext {
1184 #[serde(default, skip_serializing_if = "Option::is_none")]
1186 pub app_start_time: Option<DateTime<Utc>>,
1187 #[serde(default, skip_serializing_if = "Option::is_none")]
1189 pub device_app_hash: Option<String>,
1190 #[serde(default, skip_serializing_if = "Option::is_none")]
1192 pub build_type: Option<String>,
1193 #[serde(default, skip_serializing_if = "Option::is_none")]
1195 pub app_identifier: Option<String>,
1196 #[serde(default, skip_serializing_if = "Option::is_none")]
1198 pub app_name: Option<String>,
1199 #[serde(default, skip_serializing_if = "Option::is_none")]
1201 pub app_version: Option<String>,
1202 #[serde(default, skip_serializing_if = "Option::is_none")]
1204 pub app_build: Option<String>,
1205 #[serde(flatten)]
1207 pub other: Map<String, Value>,
1208}
1209
1210#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1212pub struct BrowserContext {
1213 #[serde(default, skip_serializing_if = "Option::is_none")]
1215 pub name: Option<String>,
1216 #[serde(default, skip_serializing_if = "Option::is_none")]
1218 pub version: Option<String>,
1219 #[serde(flatten)]
1221 pub other: Map<String, Value>,
1222}
1223
1224#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1226pub struct TraceContext {
1227 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
1229 pub span_id: Uuid,
1230 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
1232 pub trace_id: Uuid,
1233 #[serde(default, skip_serializing_if = "Option::is_none")]
1235 pub parent_span_id: Option<String>,
1236 #[serde(default, skip_serializing_if = "Option::is_none")]
1238 pub op: Option<String>,
1239 #[serde(default, skip_serializing_if = "Option::is_none")]
1241 pub description: Option<String>,
1242 #[serde(default, skip_serializing_if = "Option::is_none")]
1244 pub status: Option<String>,
1245}
1246
1247macro_rules! into_context {
1248 ($kind:ident, $ty:ty) => {
1249 impl From<$ty> for Context {
1250 fn from(data: $ty) -> Self {
1251 Context::$kind(Box::new(data))
1252 }
1253 }
1254 };
1255}
1256
1257into_context!(App, AppContext);
1258into_context!(Device, DeviceContext);
1259into_context!(Os, OsContext);
1260into_context!(Runtime, RuntimeContext);
1261into_context!(Browser, BrowserContext);
1262into_context!(Trace, TraceContext);
1263
1264mod event {
1265 use super::*;
1266
1267 pub fn default_id() -> Uuid {
1268 Uuid::new_v4()
1269 }
1270
1271 pub fn serialize_id<S: Serializer>(uuid: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
1272 serializer.serialize_some(&uuid.to_simple_ref().to_string())
1273 }
1274
1275 pub fn default_level() -> Level {
1276 Level::Error
1277 }
1278
1279 pub fn default_platform() -> Cow<'static, str> {
1280 Cow::Borrowed("other")
1281 }
1282
1283 pub fn is_default_platform(value: &str) -> bool {
1284 value == "other"
1285 }
1286
1287 static DEFAULT_FINGERPRINT: &[Cow<'static, str>] = &[Cow::Borrowed("{{ default }}")];
1288
1289 pub fn default_fingerprint<'a>() -> Cow<'a, [Cow<'a, str>]> {
1290 Cow::Borrowed(DEFAULT_FINGERPRINT)
1291 }
1292
1293 #[allow(clippy::ptr_arg)]
1294 pub fn is_default_fingerprint<'a>(fp: &[Cow<'a, str>]) -> bool {
1295 fp.len() == 1 && ((&fp)[0] == "{{ default }}" || (&fp)[0] == "{{default}}")
1296 }
1297
1298 pub fn default_timestamp() -> DateTime<Utc> {
1299 Utc::now()
1300 }
1301}
1302
1303#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1305pub struct Event<'a> {
1306 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
1308 pub event_id: Uuid,
1309 #[serde(
1311 default = "event::default_level",
1312 skip_serializing_if = "Level::is_error"
1313 )]
1314 pub level: Level,
1315 #[serde(
1317 default = "event::default_fingerprint",
1318 skip_serializing_if = "event::is_default_fingerprint"
1319 )]
1320 pub fingerprint: Cow<'a, [Cow<'a, str>]>,
1321 #[serde(default, skip_serializing_if = "Option::is_none")]
1323 pub culprit: Option<String>,
1324 #[serde(default, skip_serializing_if = "Option::is_none")]
1326 pub transaction: Option<String>,
1327 #[serde(default, skip_serializing_if = "Option::is_none")]
1329 pub message: Option<String>,
1330 #[serde(default, skip_serializing_if = "Option::is_none")]
1333 pub logentry: Option<LogEntry>,
1334 #[serde(default, skip_serializing_if = "Option::is_none")]
1336 pub logger: Option<String>,
1337 #[serde(default, skip_serializing_if = "Map::is_empty")]
1339 pub modules: Map<String, String>,
1340 #[serde(
1342 default = "event::default_platform",
1343 skip_serializing_if = "event::is_default_platform"
1344 )]
1345 pub platform: Cow<'a, str>,
1346 #[serde(default = "event::default_timestamp", with = "ts_seconds_float")]
1350 pub timestamp: DateTime<Utc>,
1351 #[serde(default, skip_serializing_if = "Option::is_none")]
1353 pub server_name: Option<Cow<'a, str>>,
1354 #[serde(default, skip_serializing_if = "Option::is_none")]
1356 pub release: Option<Cow<'a, str>>,
1357 #[serde(default, skip_serializing_if = "Option::is_none")]
1359 pub dist: Option<Cow<'a, str>>,
1360 #[serde(default, skip_serializing_if = "Option::is_none")]
1362 pub environment: Option<Cow<'a, str>>,
1363 #[serde(default, skip_serializing_if = "Option::is_none")]
1365 pub user: Option<User>,
1366 #[serde(default, skip_serializing_if = "Option::is_none")]
1368 pub request: Option<Request>,
1369 #[serde(default, skip_serializing_if = "Map::is_empty")]
1371 pub contexts: Map<String, Context>,
1372 #[serde(default, skip_serializing_if = "Values::is_empty")]
1374 pub breadcrumbs: Values<Breadcrumb>,
1375 #[serde(default, skip_serializing_if = "Values::is_empty")]
1377 pub exception: Values<Exception>,
1378 #[serde(default, skip_serializing_if = "Option::is_none")]
1380 pub stacktrace: Option<Stacktrace>,
1381 #[serde(default, skip_serializing_if = "Option::is_none")]
1383 pub template: Option<TemplateInfo>,
1384 #[serde(default, skip_serializing_if = "Values::is_empty")]
1386 pub threads: Values<Thread>,
1387 #[serde(default, skip_serializing_if = "Map::is_empty")]
1389 pub tags: Map<String, String>,
1390 #[serde(default, skip_serializing_if = "Map::is_empty")]
1392 pub extra: Map<String, Value>,
1393 #[serde(default, skip_serializing_if = "DebugMeta::is_empty")]
1395 pub debug_meta: Cow<'a, DebugMeta>,
1396 #[serde(default, skip_serializing_if = "Option::is_none")]
1398 pub sdk: Option<Cow<'a, ClientSdkInfo>>,
1399}
1400
1401impl<'a> Default for Event<'a> {
1402 fn default() -> Self {
1403 Event {
1404 event_id: event::default_id(),
1405 level: event::default_level(),
1406 fingerprint: event::default_fingerprint(),
1407 culprit: Default::default(),
1408 transaction: Default::default(),
1409 message: Default::default(),
1410 logentry: Default::default(),
1411 logger: Default::default(),
1412 modules: Default::default(),
1413 platform: event::default_platform(),
1414 timestamp: event::default_timestamp(),
1415 server_name: Default::default(),
1416 release: Default::default(),
1417 dist: Default::default(),
1418 environment: Default::default(),
1419 user: Default::default(),
1420 request: Default::default(),
1421 contexts: Default::default(),
1422 breadcrumbs: Default::default(),
1423 exception: Default::default(),
1424 stacktrace: Default::default(),
1425 template: Default::default(),
1426 threads: Default::default(),
1427 tags: Default::default(),
1428 extra: Default::default(),
1429 debug_meta: Default::default(),
1430 sdk: Default::default(),
1431 }
1432 }
1433}
1434
1435impl<'a> Event<'a> {
1436 pub fn new() -> Event<'a> {
1438 Default::default()
1439 }
1440
1441 pub fn into_owned(self) -> Event<'static> {
1443 Event {
1444 event_id: self.event_id,
1445 level: self.level,
1446 fingerprint: Cow::Owned(
1447 self.fingerprint
1448 .iter()
1449 .map(|x| Cow::Owned(x.to_string()))
1450 .collect(),
1451 ),
1452 culprit: self.culprit,
1453 transaction: self.transaction,
1454 message: self.message,
1455 logentry: self.logentry,
1456 logger: self.logger,
1457 modules: self.modules,
1458 platform: Cow::Owned(self.platform.into_owned()),
1459 timestamp: self.timestamp,
1460 server_name: self.server_name.map(|x| Cow::Owned(x.into_owned())),
1461 release: self.release.map(|x| Cow::Owned(x.into_owned())),
1462 dist: self.dist.map(|x| Cow::Owned(x.into_owned())),
1463 environment: self.environment.map(|x| Cow::Owned(x.into_owned())),
1464 user: self.user,
1465 request: self.request,
1466 contexts: self.contexts,
1467 breadcrumbs: self.breadcrumbs,
1468 exception: self.exception,
1469 stacktrace: self.stacktrace,
1470 template: self.template,
1471 threads: self.threads,
1472 tags: self.tags,
1473 extra: self.extra,
1474 debug_meta: Cow::Owned(self.debug_meta.into_owned()),
1475 sdk: self.sdk.map(|x| Cow::Owned(x.into_owned())),
1476 }
1477 }
1478}
1479
1480impl<'a> fmt::Display for Event<'a> {
1481 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1482 write!(f, "Event(id: {}, ts: {})", self.event_id, self.timestamp)
1483 }
1484}
1485
1486#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1488pub struct Span {
1489 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
1491 pub span_id: Uuid,
1492 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
1494 pub trace_id: Uuid,
1495 #[serde(default, skip_serializing_if = "Option::is_none")]
1497 pub parent_span_id: Option<String>,
1498 #[serde(default, skip_serializing_if = "Option::is_none")]
1500 pub same_process_as_parent: Option<bool>,
1501 #[serde(default, skip_serializing_if = "Option::is_none")]
1503 pub op: Option<String>,
1504 #[serde(default, skip_serializing_if = "Option::is_none")]
1507 pub description: Option<String>,
1508 #[serde(default, skip_serializing_if = "Option::is_none")]
1510 pub timestamp: Option<DateTime<Utc>>,
1511 #[serde(default = "event::default_timestamp", with = "ts_seconds_float")]
1513 pub start_timestamp: DateTime<Utc>,
1514 #[serde(default, skip_serializing_if = "Option::is_none")]
1516 pub status: Option<String>,
1517 #[serde(default, skip_serializing_if = "Map::is_empty")]
1519 pub tags: Map<String, String>,
1520 #[serde(default, skip_serializing_if = "Map::is_empty")]
1522 pub data: Map<String, Value>,
1523}
1524
1525impl Default for Span {
1526 fn default() -> Self {
1527 Span {
1528 span_id: event::default_id(),
1529 trace_id: event::default_id(),
1530 timestamp: Default::default(),
1531 tags: Default::default(),
1532 start_timestamp: event::default_timestamp(),
1533 description: Default::default(),
1534 status: Default::default(),
1535 parent_span_id: Default::default(),
1536 same_process_as_parent: Default::default(),
1537 op: Default::default(),
1538 data: Default::default(),
1539 }
1540 }
1541}
1542
1543impl Span {
1544 pub fn new() -> Span {
1546 Default::default()
1547 }
1548
1549 pub fn finish(&mut self) {
1551 self.timestamp = Some(Utc::now());
1552 }
1553}
1554
1555impl fmt::Display for Span {
1556 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1557 write!(
1558 f,
1559 "Span(id: {}, ts: {})",
1560 self.span_id, self.start_timestamp
1561 )
1562 }
1563}
1564
1565#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1567pub struct Transaction<'a> {
1568 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
1570 pub event_id: Uuid,
1571 #[serde(default, skip_serializing_if = "Option::is_none")]
1573 pub name: Option<String>,
1574 #[serde(default, skip_serializing_if = "Map::is_empty")]
1576 pub tags: Map<String, String>,
1577 #[serde(default, skip_serializing_if = "Option::is_none")]
1579 pub sdk: Option<Cow<'a, ClientSdkInfo>>,
1580 #[serde(
1582 default = "event::default_platform",
1583 skip_serializing_if = "event::is_default_platform"
1584 )]
1585 pub platform: Cow<'a, str>,
1586 #[serde(default, skip_serializing_if = "Option::is_none")]
1588 pub timestamp: Option<DateTime<Utc>>,
1589 #[serde(default = "event::default_timestamp", with = "ts_seconds_float")]
1591 pub start_timestamp: DateTime<Utc>,
1592 pub spans: Vec<Span>,
1594 #[serde(default, skip_serializing_if = "Map::is_empty")]
1596 pub contexts: Map<String, Context>,
1597}
1598
1599impl<'a> Default for Transaction<'a> {
1600 fn default() -> Self {
1601 Transaction {
1602 event_id: event::default_id(),
1603 name: Default::default(),
1604 tags: Default::default(),
1605 sdk: Default::default(),
1606 platform: event::default_platform(),
1607 timestamp: Default::default(),
1608 start_timestamp: event::default_timestamp(),
1609 spans: Default::default(),
1610 contexts: Default::default(),
1611 }
1612 }
1613}
1614
1615impl<'a> Transaction<'a> {
1616 pub fn new() -> Transaction<'a> {
1618 Default::default()
1619 }
1620
1621 pub fn into_owned(self) -> Transaction<'static> {
1623 Transaction {
1624 event_id: self.event_id,
1625 name: self.name,
1626 tags: self.tags,
1627 sdk: self.sdk.map(|x| Cow::Owned(x.into_owned())),
1628 platform: Cow::Owned(self.platform.into_owned()),
1629 timestamp: self.timestamp,
1630 start_timestamp: self.start_timestamp,
1631 spans: self.spans,
1632 contexts: self.contexts,
1633 }
1634 }
1635
1636 pub fn finish(&mut self) {
1638 self.timestamp = Some(Utc::now());
1639 }
1640}
1641
1642impl<'a> fmt::Display for Transaction<'a> {
1643 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1644 write!(
1645 f,
1646 "Transaction(id: {}, ts: {})",
1647 self.event_id, self.start_timestamp
1648 )
1649 }
1650}