1use std::borrow::Cow;
9use std::cmp;
10use std::convert::TryFrom;
11use std::fmt;
12use std::iter::FromIterator;
13use std::net::{AddrParseError, IpAddr};
14use std::ops;
15use std::str;
16use std::time::SystemTime;
17
18use self::debugid::{CodeId, DebugId};
19use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
20use thiserror::Error;
21
22pub use url::Url;
23pub use uuid::Uuid;
24
25use crate::utils::{display_from_str_opt, ts_rfc3339_opt, ts_seconds_float};
26
27pub use self::client_report::Report as ClientReport;
28pub use super::attachment::*;
29pub use super::envelope::*;
30pub use super::monitor::*;
31pub use super::session::*;
32pub use super::unit::Unit;
33
34pub mod client_report {
38 pub use super::super::client_report::{Category, Item, ItemLoss, LossSource, Reason, Report};
39}
40
41pub mod value {
43 pub use serde_json::value::{from_value, to_value, Index, Map, Number, Value};
44}
45
46pub mod map {
48 pub use std::collections::btree_map::{BTreeMap as Map, *};
49}
50
51pub mod debugid {
53 pub use debugid::{BreakpadFormat, CodeId, DebugId, ParseDebugIdError};
54}
55
56pub use self::value::Value;
58
59pub use self::map::Map;
61
62#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
69pub struct Values<T> {
70 pub values: Vec<T>,
72}
73
74impl<T> Values<T> {
75 pub fn new() -> Values<T> {
77 Values { values: Vec::new() }
78 }
79
80 pub fn is_empty(&self) -> bool {
82 self.values.is_empty()
83 }
84}
85
86impl<T> Default for Values<T> {
87 fn default() -> Self {
88 Values::new()
90 }
91}
92
93impl<T> From<Vec<T>> for Values<T> {
94 fn from(values: Vec<T>) -> Self {
95 Values { values }
96 }
97}
98
99impl<T> AsRef<[T]> for Values<T> {
100 fn as_ref(&self) -> &[T] {
101 &self.values
102 }
103}
104
105impl<T> AsMut<Vec<T>> for Values<T> {
106 fn as_mut(&mut self) -> &mut Vec<T> {
107 &mut self.values
108 }
109}
110
111impl<T> ops::Deref for Values<T> {
112 type Target = [T];
113
114 fn deref(&self) -> &Self::Target {
115 &self.values
116 }
117}
118
119impl<T> ops::DerefMut for Values<T> {
120 fn deref_mut(&mut self) -> &mut Self::Target {
121 &mut self.values
122 }
123}
124
125impl<T> FromIterator<T> for Values<T> {
126 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
127 Vec::<T>::from_iter(iter).into()
128 }
129}
130
131impl<T> Extend<T> for Values<T> {
132 fn extend<I>(&mut self, iter: I)
133 where
134 I: IntoIterator<Item = T>,
135 {
136 self.values.extend(iter)
137 }
138}
139
140impl<'a, T> IntoIterator for &'a mut Values<T> {
141 type Item = <&'a mut Vec<T> as IntoIterator>::Item;
142 type IntoIter = <&'a mut Vec<T> as IntoIterator>::IntoIter;
143
144 fn into_iter(self) -> Self::IntoIter {
145 self.values.iter_mut()
146 }
147}
148
149impl<'a, T> IntoIterator for &'a Values<T> {
150 type Item = <&'a Vec<T> as IntoIterator>::Item;
151 type IntoIter = <&'a Vec<T> as IntoIterator>::IntoIter;
152
153 fn into_iter(self) -> Self::IntoIter {
154 self.values.iter()
155 }
156}
157
158impl<T> IntoIterator for Values<T> {
159 type Item = <Vec<T> as IntoIterator>::Item;
160 type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
161
162 fn into_iter(self) -> Self::IntoIter {
163 self.values.into_iter()
164 }
165}
166
167#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
172pub struct LogEntry {
173 pub message: String,
175 #[serde(default, skip_serializing_if = "Vec::is_empty")]
177 pub params: Vec<Value>,
178}
179
180#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
182pub struct Frame {
183 #[serde(default, skip_serializing_if = "Option::is_none")]
188 pub function: Option<String>,
189 #[serde(default, skip_serializing_if = "Option::is_none")]
195 pub symbol: Option<String>,
196 #[serde(default, skip_serializing_if = "Option::is_none")]
201 pub module: Option<String>,
202 #[serde(default, skip_serializing_if = "Option::is_none")]
207 pub package: Option<String>,
208 #[serde(default, skip_serializing_if = "Option::is_none")]
210 pub filename: Option<String>,
211 #[serde(default, skip_serializing_if = "Option::is_none")]
213 pub abs_path: Option<String>,
214 #[serde(default, skip_serializing_if = "Option::is_none")]
216 pub lineno: Option<u64>,
217 #[serde(default, skip_serializing_if = "Option::is_none")]
219 pub colno: Option<u64>,
220 #[serde(default, skip_serializing_if = "Vec::is_empty")]
222 pub pre_context: Vec<String>,
223 #[serde(default, skip_serializing_if = "Option::is_none")]
225 pub context_line: Option<String>,
226 #[serde(default, skip_serializing_if = "Vec::is_empty")]
228 pub post_context: Vec<String>,
229 #[serde(default, skip_serializing_if = "Option::is_none")]
231 pub in_app: Option<bool>,
232 #[serde(default, skip_serializing_if = "Map::is_empty")]
234 pub vars: Map<String, Value>,
235 #[serde(default, skip_serializing_if = "Option::is_none")]
237 pub image_addr: Option<Addr>,
238 #[serde(default, skip_serializing_if = "Option::is_none")]
240 pub instruction_addr: Option<Addr>,
241 #[serde(default, skip_serializing_if = "Option::is_none")]
243 pub symbol_addr: Option<Addr>,
244 #[serde(default, skip_serializing_if = "Option::is_none")]
250 pub addr_mode: Option<String>,
251}
252
253#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
255pub struct TemplateInfo {
256 #[serde(default, skip_serializing_if = "Option::is_none")]
258 pub filename: Option<String>,
259 #[serde(default, skip_serializing_if = "Option::is_none")]
261 pub abs_path: Option<String>,
262 #[serde(default, skip_serializing_if = "Option::is_none")]
264 pub lineno: Option<u64>,
265 #[serde(default, skip_serializing_if = "Option::is_none")]
267 pub colno: Option<u64>,
268 #[serde(default, skip_serializing_if = "Vec::is_empty")]
270 pub pre_context: Vec<String>,
271 #[serde(default, skip_serializing_if = "Option::is_none")]
273 pub context_line: Option<String>,
274 #[serde(default, skip_serializing_if = "Vec::is_empty")]
276 pub post_context: Vec<String>,
277}
278
279#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
281pub struct Stacktrace {
282 #[serde(default)]
284 pub frames: Vec<Frame>,
285 #[serde(default, skip_serializing_if = "Option::is_none")]
287 pub frames_omitted: Option<(u64, u64)>,
288 #[serde(default, skip_serializing_if = "Map::is_empty")]
290 pub registers: Map<String, RegVal>,
291}
292
293impl Stacktrace {
294 pub fn from_frames_reversed(mut frames: Vec<Frame>) -> Option<Stacktrace> {
296 if frames.is_empty() {
297 None
298 } else {
299 frames.reverse();
300 Some(Stacktrace {
301 frames,
302 ..Default::default()
303 })
304 }
305 }
306}
307
308#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
310#[serde(untagged)]
311pub enum ThreadId {
312 Int(u64),
314 String(String),
316}
317
318impl Default for ThreadId {
319 fn default() -> ThreadId {
320 ThreadId::Int(0)
321 }
322}
323
324impl<'a> From<&'a str> for ThreadId {
325 fn from(id: &'a str) -> ThreadId {
326 ThreadId::String(id.to_string())
327 }
328}
329
330impl From<String> for ThreadId {
331 fn from(id: String) -> ThreadId {
332 ThreadId::String(id)
333 }
334}
335
336impl From<i64> for ThreadId {
337 fn from(id: i64) -> ThreadId {
338 ThreadId::Int(id as u64)
339 }
340}
341
342impl From<i32> for ThreadId {
343 fn from(id: i32) -> ThreadId {
344 ThreadId::Int(id as u64)
345 }
346}
347
348impl From<u32> for ThreadId {
349 fn from(id: u32) -> ThreadId {
350 ThreadId::Int(id as u64)
351 }
352}
353
354impl From<u16> for ThreadId {
355 fn from(id: u16) -> ThreadId {
356 ThreadId::Int(id as u64)
357 }
358}
359
360impl fmt::Display for ThreadId {
361 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
362 match *self {
363 ThreadId::Int(i) => write!(f, "{i}"),
364 ThreadId::String(ref s) => write!(f, "{s}"),
365 }
366 }
367}
368
369#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
371pub struct Addr(pub u64);
372
373impl Addr {
374 pub fn is_null(&self) -> bool {
376 self.0 == 0
377 }
378}
379
380impl_hex_serde!(Addr, u64);
381
382impl From<u64> for Addr {
383 fn from(addr: u64) -> Addr {
384 Addr(addr)
385 }
386}
387
388impl From<i32> for Addr {
389 fn from(addr: i32) -> Addr {
390 Addr(addr as u64)
391 }
392}
393
394impl From<u32> for Addr {
395 fn from(addr: u32) -> Addr {
396 Addr(addr as u64)
397 }
398}
399
400impl From<usize> for Addr {
401 fn from(addr: usize) -> Addr {
402 Addr(addr as u64)
403 }
404}
405
406impl<T> From<*const T> for Addr {
407 fn from(addr: *const T) -> Addr {
408 Addr(addr as u64)
409 }
410}
411
412impl<T> From<*mut T> for Addr {
413 fn from(addr: *mut T) -> Addr {
414 Addr(addr as u64)
415 }
416}
417
418impl From<Addr> for u64 {
419 fn from(addr: Addr) -> Self {
420 addr.0
421 }
422}
423
424fn is_false(value: &bool) -> bool {
425 !*value
426}
427
428#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
430pub struct RegVal(pub u64);
431
432impl_hex_serde!(RegVal, u64);
433
434impl From<u64> for RegVal {
435 fn from(addr: u64) -> RegVal {
436 RegVal(addr)
437 }
438}
439
440impl From<i32> for RegVal {
441 fn from(addr: i32) -> RegVal {
442 RegVal(addr as u64)
443 }
444}
445
446impl From<u32> for RegVal {
447 fn from(addr: u32) -> RegVal {
448 RegVal(addr as u64)
449 }
450}
451
452impl From<usize> for RegVal {
453 fn from(addr: usize) -> RegVal {
454 RegVal(addr as u64)
455 }
456}
457
458impl<T> From<*const T> for RegVal {
459 fn from(addr: *const T) -> RegVal {
460 RegVal(addr as u64)
461 }
462}
463
464impl<T> From<*mut T> for RegVal {
465 fn from(addr: *mut T) -> RegVal {
466 RegVal(addr as u64)
467 }
468}
469
470impl From<RegVal> for u64 {
471 fn from(reg: RegVal) -> Self {
472 reg.0
473 }
474}
475
476#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
478pub struct Thread {
479 #[serde(default, skip_serializing_if = "Option::is_none")]
481 pub id: Option<ThreadId>,
482 #[serde(default, skip_serializing_if = "Option::is_none")]
484 pub name: Option<String>,
485 #[serde(default, skip_serializing_if = "Option::is_none")]
488 pub stacktrace: Option<Stacktrace>,
489 #[serde(default, skip_serializing_if = "Option::is_none")]
491 pub raw_stacktrace: Option<Stacktrace>,
492 #[serde(default, skip_serializing_if = "is_false")]
494 pub crashed: bool,
495 #[serde(default, skip_serializing_if = "is_false")]
498 pub current: bool,
499}
500
501#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
503pub struct CError {
504 pub number: i32,
506 #[serde(default, skip_serializing_if = "Option::is_none")]
508 pub name: Option<String>,
509}
510
511impl From<i32> for CError {
512 fn from(number: i32) -> CError {
513 CError { number, name: None }
514 }
515}
516
517impl From<CError> for i32 {
518 fn from(err: CError) -> Self {
519 err.number
520 }
521}
522
523#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
525pub struct MachException {
526 pub exception: i32,
528 pub code: u64,
530 pub subcode: u64,
532 #[serde(default, skip_serializing_if = "Option::is_none")]
534 pub name: Option<String>,
535}
536
537#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
539pub struct PosixSignal {
540 pub number: i32,
542 #[serde(default, skip_serializing_if = "Option::is_none")]
544 pub code: Option<i32>,
545 #[serde(default, skip_serializing_if = "Option::is_none")]
547 pub name: Option<String>,
548 #[serde(default, skip_serializing_if = "Option::is_none")]
550 pub code_name: Option<String>,
551}
552
553impl From<i32> for PosixSignal {
554 fn from(number: i32) -> PosixSignal {
555 PosixSignal {
556 number,
557 code: None,
558 name: None,
559 code_name: None,
560 }
561 }
562}
563
564impl From<(i32, i32)> for PosixSignal {
565 fn from(tuple: (i32, i32)) -> PosixSignal {
566 let (number, code) = tuple;
567 PosixSignal {
568 number,
569 code: Some(code),
570 name: None,
571 code_name: None,
572 }
573 }
574}
575
576impl From<PosixSignal> for i32 {
577 fn from(sig: PosixSignal) -> Self {
578 sig.number
579 }
580}
581
582#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
584pub struct MechanismMeta {
585 #[serde(default, skip_serializing_if = "Option::is_none")]
587 pub errno: Option<CError>,
588 #[serde(default, skip_serializing_if = "Option::is_none")]
590 pub signal: Option<PosixSignal>,
591 #[serde(default, skip_serializing_if = "Option::is_none")]
593 pub mach_exception: Option<MachException>,
594}
595
596impl MechanismMeta {
597 fn is_empty(&self) -> bool {
598 self.errno.is_none() && self.signal.is_none() && self.mach_exception.is_none()
599 }
600}
601
602#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
604pub struct Mechanism {
605 #[serde(rename = "type")]
607 pub ty: String,
608 #[serde(default, skip_serializing_if = "Option::is_none")]
610 pub description: Option<String>,
611 #[serde(default, skip_serializing_if = "Option::is_none")]
613 pub help_link: Option<Url>,
614 #[serde(default, skip_serializing_if = "Option::is_none")]
616 pub handled: Option<bool>,
617 #[serde(default, skip_serializing_if = "Option::is_none")]
619 pub synthetic: Option<bool>,
620 #[serde(default, skip_serializing_if = "Map::is_empty")]
622 pub data: Map<String, Value>,
623 #[serde(default, skip_serializing_if = "MechanismMeta::is_empty")]
625 pub meta: MechanismMeta,
626}
627
628#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
630pub struct Exception {
631 #[serde(rename = "type")]
633 pub ty: String,
634 #[serde(skip_serializing_if = "Option::is_none")]
636 pub value: Option<String>,
637 #[serde(default, skip_serializing_if = "Option::is_none")]
639 pub module: Option<String>,
640 #[serde(default, skip_serializing_if = "Option::is_none")]
642 pub stacktrace: Option<Stacktrace>,
643 #[serde(default, skip_serializing_if = "Option::is_none")]
645 pub raw_stacktrace: Option<Stacktrace>,
646 #[serde(default, skip_serializing_if = "Option::is_none")]
648 pub thread_id: Option<ThreadId>,
649 #[serde(default, skip_serializing_if = "Option::is_none")]
651 pub mechanism: Option<Mechanism>,
652}
653
654#[derive(Debug, Error)]
656#[error("invalid level")]
657pub struct ParseLevelError;
658
659#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
661pub enum Level {
662 Debug,
664 #[default]
666 Info,
667 Warning,
669 Error,
671 Fatal,
673}
674
675impl str::FromStr for Level {
676 type Err = ParseLevelError;
677
678 fn from_str(string: &str) -> Result<Level, Self::Err> {
679 Ok(match string {
680 "debug" => Level::Debug,
681 "info" | "log" => Level::Info,
682 "warning" => Level::Warning,
683 "error" => Level::Error,
684 "fatal" => Level::Fatal,
685 _ => return Err(ParseLevelError),
686 })
687 }
688}
689
690impl fmt::Display for Level {
691 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
692 match *self {
693 Level::Debug => write!(f, "debug"),
694 Level::Info => write!(f, "info"),
695 Level::Warning => write!(f, "warning"),
696 Level::Error => write!(f, "error"),
697 Level::Fatal => write!(f, "fatal"),
698 }
699 }
700}
701
702impl Level {
703 pub fn is_debug(&self) -> bool {
705 *self == Level::Debug
706 }
707
708 pub fn is_info(&self) -> bool {
710 *self == Level::Info
711 }
712
713 pub fn is_warning(&self) -> bool {
715 *self == Level::Warning
716 }
717
718 pub fn is_error(&self) -> bool {
720 *self == Level::Error
721 }
722
723 pub fn is_fatal(&self) -> bool {
725 *self == Level::Fatal
726 }
727}
728
729impl_str_serde!(Level);
730
731mod breadcrumb {
732 use super::*;
733
734 pub fn default_type() -> String {
735 "default".to_string()
736 }
737
738 pub fn is_default_type(ty: &str) -> bool {
739 ty == "default"
740 }
741
742 pub fn default_level() -> Level {
743 Level::Info
744 }
745}
746
747#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
749pub struct Breadcrumb {
750 #[serde(default = "SystemTime::now", with = "ts_seconds_float")]
752 pub timestamp: SystemTime,
753 #[serde(
755 rename = "type",
756 default = "breadcrumb::default_type",
757 skip_serializing_if = "breadcrumb::is_default_type"
758 )]
759 pub ty: String,
760 #[serde(default, skip_serializing_if = "Option::is_none")]
762 pub category: Option<String>,
763 #[serde(
766 default = "breadcrumb::default_level",
767 skip_serializing_if = "Level::is_info"
768 )]
769 pub level: Level,
770 #[serde(default, skip_serializing_if = "Option::is_none")]
772 pub message: Option<String>,
773 #[serde(default, skip_serializing_if = "Map::is_empty")]
775 pub data: Map<String, Value>,
776}
777
778impl Default for Breadcrumb {
779 fn default() -> Breadcrumb {
780 Breadcrumb {
781 timestamp: SystemTime::now(),
782 ty: breadcrumb::default_type(),
783 category: Default::default(),
784 level: breadcrumb::default_level(),
785 message: Default::default(),
786 data: Default::default(),
787 }
788 }
789}
790
791#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
793pub enum IpAddress {
794 #[default]
796 Auto,
797 Exact(IpAddr),
799}
800
801impl PartialEq<IpAddr> for IpAddress {
802 fn eq(&self, other: &IpAddr) -> bool {
803 match *self {
804 IpAddress::Auto => false,
805 IpAddress::Exact(ref addr) => addr == other,
806 }
807 }
808}
809
810impl cmp::PartialOrd<IpAddr> for IpAddress {
811 fn partial_cmp(&self, other: &IpAddr) -> Option<cmp::Ordering> {
812 match *self {
813 IpAddress::Auto => None,
814 IpAddress::Exact(ref addr) => addr.partial_cmp(other),
815 }
816 }
817}
818
819impl fmt::Display for IpAddress {
820 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
821 match *self {
822 IpAddress::Auto => write!(f, "{{{{auto}}}}"),
823 IpAddress::Exact(ref addr) => write!(f, "{addr}"),
824 }
825 }
826}
827
828impl From<IpAddr> for IpAddress {
829 fn from(addr: IpAddr) -> IpAddress {
830 IpAddress::Exact(addr)
831 }
832}
833
834impl str::FromStr for IpAddress {
835 type Err = AddrParseError;
836
837 fn from_str(string: &str) -> Result<IpAddress, AddrParseError> {
838 match string {
839 "{{auto}}" => Ok(IpAddress::Auto),
840 other => other.parse().map(IpAddress::Exact),
841 }
842 }
843}
844
845impl_str_serde!(IpAddress);
846
847#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
849pub struct User {
850 #[serde(default, skip_serializing_if = "Option::is_none")]
852 pub id: Option<String>,
853 #[serde(default, skip_serializing_if = "Option::is_none")]
855 pub email: Option<String>,
856 #[serde(default, skip_serializing_if = "Option::is_none")]
858 pub ip_address: Option<IpAddress>,
859 #[serde(default, skip_serializing_if = "Option::is_none")]
861 pub username: Option<String>,
862 #[serde(flatten)]
864 pub other: Map<String, Value>,
865}
866
867#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
869pub struct Request {
870 #[serde(default, skip_serializing_if = "Option::is_none")]
872 pub url: Option<Url>,
873 #[serde(default, skip_serializing_if = "Option::is_none")]
875 pub method: Option<String>,
876 #[serde(default, skip_serializing_if = "Option::is_none")]
879 pub data: Option<String>,
880 #[serde(default, skip_serializing_if = "Option::is_none")]
882 pub query_string: Option<String>,
883 #[serde(default, skip_serializing_if = "Option::is_none")]
885 pub cookies: Option<String>,
886 #[serde(default, skip_serializing_if = "Map::is_empty")]
888 pub headers: Map<String, String>,
889 #[serde(default, skip_serializing_if = "Map::is_empty")]
891 pub env: Map<String, String>,
892}
893
894#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
899pub struct SystemSdkInfo {
900 pub sdk_name: String,
902 pub version_major: u32,
904 pub version_minor: u32,
906 pub version_patchlevel: u32,
908}
909
910#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
912#[serde(rename_all = "snake_case", tag = "type")]
913pub enum DebugImage {
914 Apple(AppleDebugImage),
917 Symbolic(SymbolicDebugImage),
919 Proguard(ProguardDebugImage),
921 Wasm(WasmDebugImage),
924}
925
926impl DebugImage {
927 pub fn type_name(&self) -> &str {
929 match *self {
930 DebugImage::Apple(..) => "apple",
931 DebugImage::Symbolic(..) => "symbolic",
932 DebugImage::Proguard(..) => "proguard",
933 DebugImage::Wasm(..) => "wasm",
934 }
935 }
936}
937
938macro_rules! into_debug_image {
939 ($kind:ident, $ty:ty) => {
940 impl From<$ty> for DebugImage {
941 fn from(data: $ty) -> DebugImage {
942 DebugImage::$kind(data)
943 }
944 }
945 };
946}
947
948#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
950pub struct AppleDebugImage {
951 pub name: String,
953 pub arch: Option<String>,
955 pub cpu_type: Option<u32>,
957 pub cpu_subtype: Option<u32>,
959 pub image_addr: Addr,
961 pub image_size: u64,
963 #[serde(default, skip_serializing_if = "Addr::is_null")]
965 pub image_vmaddr: Addr,
966 pub uuid: Uuid,
968}
969
970#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
972pub struct SymbolicDebugImage {
973 pub name: String,
978 pub arch: Option<String>,
980 pub image_addr: Addr,
984 pub image_size: u64,
988 #[serde(default, skip_serializing_if = "Addr::is_null")]
996 pub image_vmaddr: Addr,
997 pub id: DebugId,
1001
1002 #[serde(default, skip_serializing_if = "Option::is_none")]
1004 pub code_id: Option<CodeId>,
1005 #[serde(default, skip_serializing_if = "Option::is_none")]
1007 pub debug_file: Option<String>,
1008}
1009
1010#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1012pub struct ProguardDebugImage {
1013 pub uuid: Uuid,
1015}
1016
1017#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1019pub struct WasmDebugImage {
1020 pub name: String,
1022 pub debug_id: Uuid,
1024 #[serde(default, skip_serializing_if = "Option::is_none")]
1029 pub debug_file: Option<String>,
1030 #[serde(default, skip_serializing_if = "Option::is_none")]
1033 pub code_id: Option<String>,
1034 pub code_file: String,
1037}
1038
1039into_debug_image!(Apple, AppleDebugImage);
1040into_debug_image!(Symbolic, SymbolicDebugImage);
1041into_debug_image!(Proguard, ProguardDebugImage);
1042into_debug_image!(Wasm, WasmDebugImage);
1043
1044#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
1046pub struct DebugMeta {
1047 #[serde(default, skip_serializing_if = "Option::is_none")]
1049 pub sdk_info: Option<SystemSdkInfo>,
1050 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1052 pub images: Vec<DebugImage>,
1053}
1054
1055impl DebugMeta {
1056 pub fn is_empty(&self) -> bool {
1060 self.sdk_info.is_none() && self.images.is_empty()
1061 }
1062}
1063
1064#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1066pub struct ClientSdkInfo {
1067 pub name: String,
1069 pub version: String,
1071 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1073 pub integrations: Vec<String>,
1074 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1076 pub packages: Vec<ClientSdkPackage>,
1077}
1078
1079#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1081pub struct ClientSdkPackage {
1082 pub name: String,
1084 pub version: String,
1086}
1087
1088#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1093#[serde(rename_all = "snake_case", tag = "type")]
1094#[non_exhaustive]
1095pub enum Context {
1096 Device(Box<DeviceContext>),
1098 Os(Box<OsContext>),
1100 Runtime(Box<RuntimeContext>),
1102 App(Box<AppContext>),
1104 Browser(Box<BrowserContext>),
1106 Trace(Box<TraceContext>),
1108 Gpu(Box<GpuContext>),
1110 Otel(Box<OtelContext>),
1112 Response(Box<ResponseContext>),
1114 #[serde(rename = "unknown")]
1116 Other(Map<String, Value>),
1117}
1118
1119impl Context {
1120 pub fn type_name(&self) -> &str {
1122 match *self {
1123 Context::Device(..) => "device",
1124 Context::Os(..) => "os",
1125 Context::Runtime(..) => "runtime",
1126 Context::App(..) => "app",
1127 Context::Browser(..) => "browser",
1128 Context::Trace(..) => "trace",
1129 Context::Gpu(..) => "gpu",
1130 Context::Otel(..) => "otel",
1131 Context::Response(..) => "response",
1132 Context::Other(..) => "unknown",
1133 }
1134 }
1135}
1136
1137#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
1139#[serde(rename_all = "lowercase")]
1140pub enum Orientation {
1141 Portrait,
1143 Landscape,
1145}
1146
1147#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1149pub struct DeviceContext {
1150 #[serde(default, skip_serializing_if = "Option::is_none")]
1152 pub name: Option<String>,
1153 #[serde(default, skip_serializing_if = "Option::is_none")]
1155 pub family: Option<String>,
1156 #[serde(default, skip_serializing_if = "Option::is_none")]
1158 pub model: Option<String>,
1159 #[serde(default, skip_serializing_if = "Option::is_none")]
1161 pub model_id: Option<String>,
1162 #[serde(default, skip_serializing_if = "Option::is_none")]
1164 pub arch: Option<String>,
1165 #[serde(default, skip_serializing_if = "Option::is_none")]
1167 pub battery_level: Option<f32>,
1168 #[serde(default, skip_serializing_if = "Option::is_none")]
1170 pub orientation: Option<Orientation>,
1171 #[serde(default, skip_serializing_if = "Option::is_none")]
1173 pub simulator: Option<bool>,
1174 #[serde(default, skip_serializing_if = "Option::is_none")]
1176 pub memory_size: Option<u64>,
1177 #[serde(default, skip_serializing_if = "Option::is_none")]
1179 pub free_memory: Option<u64>,
1180 #[serde(default, skip_serializing_if = "Option::is_none")]
1182 pub usable_memory: Option<u64>,
1183 #[serde(default, skip_serializing_if = "Option::is_none")]
1185 pub storage_size: Option<u64>,
1186 #[serde(default, skip_serializing_if = "Option::is_none")]
1188 pub free_storage: Option<u64>,
1189 #[serde(default, skip_serializing_if = "Option::is_none")]
1191 pub external_storage_size: Option<u64>,
1192 #[serde(default, skip_serializing_if = "Option::is_none")]
1194 pub external_free_storage: Option<u64>,
1195 #[serde(
1197 default,
1198 skip_serializing_if = "Option::is_none",
1199 with = "ts_rfc3339_opt"
1200 )]
1201 pub boot_time: Option<SystemTime>,
1202 #[serde(default, skip_serializing_if = "Option::is_none")]
1204 pub timezone: Option<String>,
1205 #[serde(flatten)]
1207 pub other: Map<String, Value>,
1208}
1209
1210#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1212pub struct OsContext {
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(default, skip_serializing_if = "Option::is_none")]
1221 pub build: Option<String>,
1222 #[serde(default, skip_serializing_if = "Option::is_none")]
1224 pub kernel_version: Option<String>,
1225 #[serde(default, skip_serializing_if = "Option::is_none")]
1227 pub rooted: Option<bool>,
1228 #[serde(flatten)]
1230 pub other: Map<String, Value>,
1231}
1232
1233#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1235pub struct RuntimeContext {
1236 #[serde(default, skip_serializing_if = "Option::is_none")]
1238 pub name: Option<String>,
1239 #[serde(default, skip_serializing_if = "Option::is_none")]
1241 pub version: Option<String>,
1242 #[serde(flatten)]
1244 pub other: Map<String, Value>,
1245}
1246
1247#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1249pub struct AppContext {
1250 #[serde(
1252 default,
1253 skip_serializing_if = "Option::is_none",
1254 with = "ts_rfc3339_opt"
1255 )]
1256 pub app_start_time: Option<SystemTime>,
1257 #[serde(default, skip_serializing_if = "Option::is_none")]
1259 pub device_app_hash: Option<String>,
1260 #[serde(default, skip_serializing_if = "Option::is_none")]
1262 pub build_type: Option<String>,
1263 #[serde(default, skip_serializing_if = "Option::is_none")]
1265 pub app_identifier: Option<String>,
1266 #[serde(default, skip_serializing_if = "Option::is_none")]
1268 pub app_name: Option<String>,
1269 #[serde(default, skip_serializing_if = "Option::is_none")]
1271 pub app_version: Option<String>,
1272 #[serde(default, skip_serializing_if = "Option::is_none")]
1274 pub app_build: Option<String>,
1275 #[serde(flatten)]
1277 pub other: Map<String, Value>,
1278}
1279
1280#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1282pub struct BrowserContext {
1283 #[serde(default, skip_serializing_if = "Option::is_none")]
1285 pub name: Option<String>,
1286 #[serde(default, skip_serializing_if = "Option::is_none")]
1288 pub version: Option<String>,
1289 #[serde(flatten)]
1291 pub other: Map<String, Value>,
1292}
1293
1294#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1296pub struct GpuContext {
1297 pub name: String,
1299 #[serde(default, skip_serializing_if = "Option::is_none")]
1301 pub version: Option<String>,
1302 #[serde(default, skip_serializing_if = "Option::is_none")]
1304 pub driver_version: Option<String>,
1305 #[serde(default, skip_serializing_if = "Option::is_none")]
1307 pub id: Option<String>,
1308 #[serde(default, skip_serializing_if = "Option::is_none")]
1310 pub vendor_id: Option<String>,
1311 #[serde(default, skip_serializing_if = "Option::is_none")]
1313 pub vendor_name: Option<String>,
1314 #[serde(default, skip_serializing_if = "Option::is_none")]
1316 pub memory_size: Option<u32>,
1317 #[serde(default, skip_serializing_if = "Option::is_none")]
1319 pub api_type: Option<String>,
1320 #[serde(default, skip_serializing_if = "Option::is_none")]
1322 pub multi_threaded_rendering: Option<bool>,
1323 #[serde(default, skip_serializing_if = "Option::is_none")]
1325 pub npot_support: Option<bool>,
1326 #[serde(default, skip_serializing_if = "Option::is_none")]
1328 pub max_texture_size: Option<u32>,
1329 #[serde(default, skip_serializing_if = "Option::is_none")]
1332 pub graphics_shader_level: Option<String>,
1333 #[serde(default, skip_serializing_if = "Option::is_none")]
1335 pub supports_draw_call_instancing: Option<bool>,
1336 #[serde(default, skip_serializing_if = "Option::is_none")]
1338 pub supports_ray_tracing: Option<bool>,
1339 #[serde(default, skip_serializing_if = "Option::is_none")]
1341 pub supports_compute_shaders: Option<bool>,
1342 #[serde(default, skip_serializing_if = "Option::is_none")]
1344 pub supports_geometry_shaders: Option<bool>,
1345 #[serde(flatten)]
1347 pub other: Map<String, Value>,
1348}
1349
1350#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1352pub struct OtelContext {
1353 #[serde(default, skip_serializing_if = "Map::is_empty")]
1356 pub attributes: Map<String, Value>,
1357 #[serde(default, skip_serializing_if = "Map::is_empty")]
1360 pub resource: Map<String, Value>,
1361 #[serde(flatten)]
1363 pub other: Map<String, Value>,
1364}
1365
1366#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1368pub struct ResponseContext {
1369 #[serde(default, skip_serializing_if = "Option::is_none")]
1371 pub cookies: Option<String>,
1372 #[serde(default, skip_serializing_if = "Map::is_empty")]
1377 pub headers: Map<String, String>,
1378 #[serde(default, skip_serializing_if = "Option::is_none")]
1380 pub status_code: Option<u64>,
1381 #[serde(default, skip_serializing_if = "Option::is_none")]
1383 pub body_size: Option<u64>,
1384 #[serde(default, skip_serializing_if = "Option::is_none")]
1386 pub data: Option<Value>,
1387}
1388
1389#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash)]
1391#[serde(try_from = "String", into = "String")]
1392pub struct SpanId([u8; 8]);
1393
1394impl Default for SpanId {
1395 fn default() -> Self {
1396 Self(rand::random())
1397 }
1398}
1399
1400impl fmt::Display for SpanId {
1401 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1402 write!(fmt, "{}", hex::encode(self.0))
1403 }
1404}
1405
1406impl fmt::Debug for SpanId {
1407 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1408 write!(fmt, "SpanId({self})")
1409 }
1410}
1411
1412impl From<SpanId> for String {
1413 fn from(span_id: SpanId) -> Self {
1414 span_id.to_string()
1415 }
1416}
1417
1418impl str::FromStr for SpanId {
1419 type Err = hex::FromHexError;
1420
1421 fn from_str(input: &str) -> Result<Self, Self::Err> {
1422 let mut buf = [0; 8];
1423 hex::decode_to_slice(input, &mut buf)?;
1424 Ok(Self(buf))
1425 }
1426}
1427
1428impl TryFrom<String> for SpanId {
1429 type Error = hex::FromHexError;
1430
1431 fn try_from(value: String) -> Result<Self, Self::Error> {
1432 value.parse()
1433 }
1434}
1435
1436impl From<[u8; 8]> for SpanId {
1437 fn from(value: [u8; 8]) -> Self {
1438 Self(value)
1439 }
1440}
1441
1442#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash)]
1444#[serde(try_from = "String", into = "String")]
1445pub struct TraceId([u8; 16]);
1446
1447impl Default for TraceId {
1448 fn default() -> Self {
1449 Self(rand::random())
1450 }
1451}
1452
1453impl fmt::Display for TraceId {
1454 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1455 write!(fmt, "{}", hex::encode(self.0))
1456 }
1457}
1458
1459impl fmt::Debug for TraceId {
1460 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1461 write!(fmt, "TraceId({self})")
1462 }
1463}
1464
1465impl From<TraceId> for String {
1466 fn from(trace_id: TraceId) -> Self {
1467 trace_id.to_string()
1468 }
1469}
1470
1471impl str::FromStr for TraceId {
1472 type Err = hex::FromHexError;
1473
1474 fn from_str(input: &str) -> Result<Self, Self::Err> {
1475 let mut buf = [0; 16];
1476 hex::decode_to_slice(input, &mut buf)?;
1477 Ok(Self(buf))
1478 }
1479}
1480
1481impl TryFrom<String> for TraceId {
1482 type Error = hex::FromHexError;
1483
1484 fn try_from(value: String) -> Result<Self, Self::Error> {
1485 value.parse()
1486 }
1487}
1488
1489impl From<[u8; 16]> for TraceId {
1490 fn from(value: [u8; 16]) -> Self {
1491 Self(value)
1492 }
1493}
1494
1495#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1497pub struct TraceContext {
1498 #[serde(default)]
1500 pub span_id: SpanId,
1501 #[serde(default)]
1503 pub trace_id: TraceId,
1504 #[serde(default, skip_serializing_if = "Option::is_none")]
1506 pub parent_span_id: Option<SpanId>,
1507 #[serde(default, skip_serializing_if = "Option::is_none")]
1509 pub op: Option<String>,
1510 #[serde(default, skip_serializing_if = "Option::is_none")]
1512 pub description: Option<String>,
1513 #[serde(default, skip_serializing_if = "Option::is_none")]
1515 pub status: Option<SpanStatus>,
1516 #[serde(default, skip_serializing_if = "Option::is_none")]
1519 pub origin: Option<String>,
1520 #[serde(default, skip_serializing_if = "Map::is_empty")]
1522 pub data: Map<String, Value>,
1523}
1524
1525macro_rules! into_context {
1526 ($kind:ident, $ty:ty) => {
1527 impl From<$ty> for Context {
1528 fn from(data: $ty) -> Self {
1529 Context::$kind(Box::new(data))
1530 }
1531 }
1532 };
1533}
1534
1535into_context!(App, AppContext);
1536into_context!(Device, DeviceContext);
1537into_context!(Os, OsContext);
1538into_context!(Runtime, RuntimeContext);
1539into_context!(Browser, BrowserContext);
1540into_context!(Trace, TraceContext);
1541into_context!(Gpu, GpuContext);
1542into_context!(Otel, OtelContext);
1543into_context!(Response, ResponseContext);
1544
1545const INFERABLE_CONTEXTS: &[&str] = &[
1546 "device", "os", "runtime", "app", "browser", "trace", "gpu", "otel", "response",
1547];
1548
1549struct ContextsVisitor;
1550
1551impl<'de> de::Visitor<'de> for ContextsVisitor {
1552 type Value = Map<String, Context>;
1553
1554 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1555 formatter.write_str("contexts object")
1556 }
1557
1558 fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
1559 where
1560 A: de::MapAccess<'de>,
1561 {
1562 let mut map: Map<String, Context> = Map::new();
1563
1564 while let Some((key, mut value)) = access.next_entry::<String, Value>()? {
1565 let typed_value = value
1566 .as_object_mut()
1567 .map(|ctx| {
1568 if !ctx.contains_key("type") {
1569 let type_key = if INFERABLE_CONTEXTS.contains(&key.as_str()) {
1570 key.clone().into()
1571 } else {
1572 Value::String("unknown".into())
1573 };
1574 ctx.insert(String::from("type"), type_key);
1575 }
1576 ctx.to_owned()
1577 })
1578 .ok_or_else(|| de::Error::custom("expected valid `context` object"))?;
1579
1580 match serde_json::from_value(serde_json::to_value(typed_value).unwrap()) {
1581 Ok(context) => {
1582 map.insert(key, context);
1583 }
1584 Err(e) => return Err(de::Error::custom(e.to_string())),
1585 }
1586 }
1587
1588 Ok(map)
1589 }
1590}
1591
1592fn deserialize_contexts<'de, D>(deserializer: D) -> Result<Map<String, Context>, D::Error>
1593where
1594 D: Deserializer<'de>,
1595{
1596 deserializer.deserialize_map(ContextsVisitor {})
1597}
1598
1599mod event {
1600 use super::*;
1601
1602 pub fn default_id() -> Uuid {
1603 crate::random_uuid()
1604 }
1605
1606 pub fn serialize_id<S: Serializer>(uuid: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
1607 serializer.serialize_some(&uuid.as_simple().to_string())
1608 }
1609
1610 pub fn default_level() -> Level {
1611 Level::Error
1612 }
1613
1614 pub fn default_platform() -> Cow<'static, str> {
1615 Cow::Borrowed("other")
1616 }
1617
1618 pub fn is_default_platform(value: &str) -> bool {
1619 value == "other"
1620 }
1621
1622 static DEFAULT_FINGERPRINT: &[Cow<'static, str>] = &[Cow::Borrowed("{{ default }}")];
1623
1624 pub fn default_fingerprint<'a>() -> Cow<'a, [Cow<'a, str>]> {
1625 Cow::Borrowed(DEFAULT_FINGERPRINT)
1626 }
1627
1628 pub fn is_default_fingerprint(fp: &[Cow<'_, str>]) -> bool {
1629 fp.len() == 1 && ((fp)[0] == "{{ default }}" || (fp)[0] == "{{default}}")
1630 }
1631}
1632
1633#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1635pub struct Event<'a> {
1636 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
1638 pub event_id: Uuid,
1639 #[serde(
1641 default = "event::default_level",
1642 skip_serializing_if = "Level::is_error"
1643 )]
1644 pub level: Level,
1645 #[serde(
1647 default = "event::default_fingerprint",
1648 skip_serializing_if = "event::is_default_fingerprint"
1649 )]
1650 pub fingerprint: Cow<'a, [Cow<'a, str>]>,
1651 #[serde(default, skip_serializing_if = "Option::is_none")]
1653 pub culprit: Option<String>,
1654 #[serde(default, skip_serializing_if = "Option::is_none")]
1656 pub transaction: Option<String>,
1657 #[serde(default, skip_serializing_if = "Option::is_none")]
1659 pub message: Option<String>,
1660 #[serde(default, skip_serializing_if = "Option::is_none")]
1663 pub logentry: Option<LogEntry>,
1664 #[serde(default, skip_serializing_if = "Option::is_none")]
1666 pub logger: Option<String>,
1667 #[serde(default, skip_serializing_if = "Map::is_empty")]
1669 pub modules: Map<String, String>,
1670 #[serde(
1672 default = "event::default_platform",
1673 skip_serializing_if = "event::is_default_platform"
1674 )]
1675 pub platform: Cow<'a, str>,
1676 #[serde(default = "SystemTime::now", with = "ts_seconds_float")]
1680 pub timestamp: SystemTime,
1681 #[serde(default, skip_serializing_if = "Option::is_none")]
1683 pub server_name: Option<Cow<'a, str>>,
1684 #[serde(default, skip_serializing_if = "Option::is_none")]
1686 pub release: Option<Cow<'a, str>>,
1687 #[serde(default, skip_serializing_if = "Option::is_none")]
1689 pub dist: Option<Cow<'a, str>>,
1690 #[serde(default, skip_serializing_if = "Option::is_none")]
1692 pub environment: Option<Cow<'a, str>>,
1693 #[serde(default, skip_serializing_if = "Option::is_none")]
1695 pub user: Option<User>,
1696 #[serde(default, skip_serializing_if = "Option::is_none")]
1698 pub request: Option<Request>,
1699 #[serde(
1701 default,
1702 skip_serializing_if = "Map::is_empty",
1703 deserialize_with = "deserialize_contexts"
1704 )]
1705 pub contexts: Map<String, Context>,
1706 #[serde(default, skip_serializing_if = "Values::is_empty")]
1708 pub breadcrumbs: Values<Breadcrumb>,
1709 #[serde(default, skip_serializing_if = "Values::is_empty")]
1711 pub exception: Values<Exception>,
1712 #[serde(default, skip_serializing_if = "Option::is_none")]
1714 pub stacktrace: Option<Stacktrace>,
1715 #[serde(default, skip_serializing_if = "Option::is_none")]
1717 pub template: Option<TemplateInfo>,
1718 #[serde(default, skip_serializing_if = "Values::is_empty")]
1720 pub threads: Values<Thread>,
1721 #[serde(default, skip_serializing_if = "Map::is_empty")]
1723 pub tags: Map<String, String>,
1724 #[serde(default, skip_serializing_if = "Map::is_empty")]
1726 pub extra: Map<String, Value>,
1727 #[serde(default, skip_serializing_if = "DebugMeta::is_empty")]
1729 pub debug_meta: Cow<'a, DebugMeta>,
1730 #[serde(default, skip_serializing_if = "Option::is_none")]
1732 pub sdk: Option<Cow<'a, ClientSdkInfo>>,
1733}
1734
1735impl Default for Event<'_> {
1736 fn default() -> Self {
1737 Event {
1738 event_id: event::default_id(),
1739 level: event::default_level(),
1740 fingerprint: event::default_fingerprint(),
1741 culprit: Default::default(),
1742 transaction: Default::default(),
1743 message: Default::default(),
1744 logentry: Default::default(),
1745 logger: Default::default(),
1746 modules: Default::default(),
1747 platform: event::default_platform(),
1748 timestamp: SystemTime::now(),
1749 server_name: Default::default(),
1750 release: Default::default(),
1751 dist: Default::default(),
1752 environment: Default::default(),
1753 user: Default::default(),
1754 request: Default::default(),
1755 contexts: Default::default(),
1756 breadcrumbs: Default::default(),
1757 exception: Default::default(),
1758 stacktrace: Default::default(),
1759 template: Default::default(),
1760 threads: Default::default(),
1761 tags: Default::default(),
1762 extra: Default::default(),
1763 debug_meta: Default::default(),
1764 sdk: Default::default(),
1765 }
1766 }
1767}
1768
1769impl<'a> Event<'a> {
1770 pub fn new() -> Event<'a> {
1772 Default::default()
1773 }
1774
1775 pub fn into_owned(self) -> Event<'static> {
1777 Event {
1778 event_id: self.event_id,
1779 level: self.level,
1780 fingerprint: Cow::Owned(
1781 self.fingerprint
1782 .iter()
1783 .map(|x| Cow::Owned(x.to_string()))
1784 .collect(),
1785 ),
1786 culprit: self.culprit,
1787 transaction: self.transaction,
1788 message: self.message,
1789 logentry: self.logentry,
1790 logger: self.logger,
1791 modules: self.modules,
1792 platform: Cow::Owned(self.platform.into_owned()),
1793 timestamp: self.timestamp,
1794 server_name: self.server_name.map(|x| Cow::Owned(x.into_owned())),
1795 release: self.release.map(|x| Cow::Owned(x.into_owned())),
1796 dist: self.dist.map(|x| Cow::Owned(x.into_owned())),
1797 environment: self.environment.map(|x| Cow::Owned(x.into_owned())),
1798 user: self.user,
1799 request: self.request,
1800 contexts: self.contexts,
1801 breadcrumbs: self.breadcrumbs,
1802 exception: self.exception,
1803 stacktrace: self.stacktrace,
1804 template: self.template,
1805 threads: self.threads,
1806 tags: self.tags,
1807 extra: self.extra,
1808 debug_meta: Cow::Owned(self.debug_meta.into_owned()),
1809 sdk: self.sdk.map(|x| Cow::Owned(x.into_owned())),
1810 }
1811 }
1812}
1813
1814impl fmt::Display for Event<'_> {
1815 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1816 write!(
1817 f,
1818 "Event(id: {}, ts: {})",
1819 self.event_id,
1820 crate::utils::to_rfc3339(&self.timestamp)
1821 )
1822 }
1823}
1824
1825#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1827pub struct Span {
1828 #[serde(default)]
1830 pub span_id: SpanId,
1831 #[serde(default)]
1833 pub trace_id: TraceId,
1834 #[serde(default, skip_serializing_if = "Option::is_none")]
1836 pub parent_span_id: Option<SpanId>,
1837 #[serde(default, skip_serializing_if = "Option::is_none")]
1839 pub same_process_as_parent: Option<bool>,
1840 #[serde(default, skip_serializing_if = "Option::is_none")]
1842 pub op: Option<String>,
1843 #[serde(default, skip_serializing_if = "Option::is_none")]
1846 pub description: Option<String>,
1847 #[serde(
1849 default,
1850 skip_serializing_if = "Option::is_none",
1851 with = "ts_rfc3339_opt"
1852 )]
1853 pub timestamp: Option<SystemTime>,
1854 #[serde(default = "SystemTime::now", with = "ts_seconds_float")]
1856 pub start_timestamp: SystemTime,
1857 #[serde(default, skip_serializing_if = "Option::is_none")]
1859 pub status: Option<SpanStatus>,
1860 #[serde(default, skip_serializing_if = "Map::is_empty")]
1862 pub tags: Map<String, String>,
1863 #[serde(default, skip_serializing_if = "Map::is_empty")]
1865 pub data: Map<String, Value>,
1866}
1867
1868impl Default for Span {
1869 fn default() -> Self {
1870 Span {
1871 span_id: Default::default(),
1872 trace_id: Default::default(),
1873 timestamp: Default::default(),
1874 tags: Default::default(),
1875 start_timestamp: SystemTime::now(),
1876 description: Default::default(),
1877 status: Default::default(),
1878 parent_span_id: Default::default(),
1879 same_process_as_parent: Default::default(),
1880 op: Default::default(),
1881 data: Default::default(),
1882 }
1883 }
1884}
1885
1886impl Span {
1887 pub fn new() -> Span {
1889 Default::default()
1890 }
1891
1892 pub fn finish_with_timestamp(&mut self, timestamp: SystemTime) {
1894 self.timestamp = Some(timestamp);
1895 }
1896
1897 pub fn finish(&mut self) {
1899 self.timestamp = Some(SystemTime::now());
1900 }
1901}
1902
1903impl fmt::Display for Span {
1904 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1905 write!(
1906 f,
1907 "Span(id: {}, ts: {})",
1908 self.span_id,
1909 crate::utils::to_rfc3339(&self.start_timestamp)
1910 )
1911 }
1912}
1913
1914#[derive(Debug, Error)]
1916#[error("invalid status")]
1917pub struct ParseStatusError;
1918
1919#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
1921#[non_exhaustive]
1922pub enum SpanStatus {
1923 #[serde(rename = "ok")]
1925 Ok,
1926 #[serde(rename = "deadline_exceeded")]
1928 DeadlineExceeded,
1929 #[serde(rename = "unauthenticated")]
1931 Unauthenticated,
1932 #[serde(rename = "permission_denied")]
1934 PermissionDenied,
1935 #[serde(rename = "not_found")]
1937 NotFound,
1938 #[serde(rename = "resource_exhausted")]
1940 ResourceExhausted,
1941 #[serde(rename = "invalid_argument")]
1943 InvalidArgument,
1944 #[serde(rename = "unimplemented")]
1946 Unimplemented,
1947 #[serde(rename = "unavailable")]
1949 Unavailable,
1950 #[serde(rename = "internal_error")]
1952 InternalError,
1953 #[serde(rename = "unknown_error")]
1955 UnknownError,
1956 #[serde(rename = "cancelled")]
1958 Cancelled,
1959 #[serde(rename = "already_exists")]
1961 AlreadyExists,
1962 #[serde(rename = "failed_precondition")]
1964 FailedPrecondition,
1965 #[serde(rename = "aborted")]
1967 Aborted,
1968 #[serde(rename = "out_of_range")]
1970 OutOfRange,
1971 #[serde(rename = "data_loss")]
1973 DataLoss,
1974}
1975
1976impl str::FromStr for SpanStatus {
1977 type Err = ParseStatusError;
1978
1979 fn from_str(s: &str) -> Result<SpanStatus, Self::Err> {
1980 Ok(match s {
1981 "ok" => SpanStatus::Ok,
1982 "deadline_exceeded" => SpanStatus::DeadlineExceeded,
1983 "unauthenticated" => SpanStatus::Unauthenticated,
1984 "permission_denied" => SpanStatus::PermissionDenied,
1985 "not_found" => SpanStatus::NotFound,
1986 "resource_exhausted" => SpanStatus::ResourceExhausted,
1987 "invalid_argument" => SpanStatus::InvalidArgument,
1988 "unimplemented" => SpanStatus::Unimplemented,
1989 "unavailable" => SpanStatus::Unavailable,
1990 "internal_error" => SpanStatus::InternalError,
1991 "unknown_error" => SpanStatus::UnknownError,
1992 "cancelled" => SpanStatus::Cancelled,
1993 "already_exists" => SpanStatus::AlreadyExists,
1994 "failed_precondition" => SpanStatus::FailedPrecondition,
1995 "aborted" => SpanStatus::Aborted,
1996 "out_of_range" => SpanStatus::OutOfRange,
1997 "data_loss" => SpanStatus::DataLoss,
1998 _ => return Err(ParseStatusError),
1999 })
2000 }
2001}
2002
2003impl fmt::Display for SpanStatus {
2004 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2005 match self {
2006 SpanStatus::Ok => write!(f, "ok"),
2007 SpanStatus::DeadlineExceeded => write!(f, "deadline_exceeded"),
2008 SpanStatus::Unauthenticated => write!(f, "unauthenticated"),
2009 SpanStatus::PermissionDenied => write!(f, "permission_denied"),
2010 SpanStatus::NotFound => write!(f, "not_found"),
2011 SpanStatus::ResourceExhausted => write!(f, "resource_exhausted"),
2012 SpanStatus::InvalidArgument => write!(f, "invalid_argument"),
2013 SpanStatus::Unimplemented => write!(f, "unimplemented"),
2014 SpanStatus::Unavailable => write!(f, "unavailable"),
2015 SpanStatus::InternalError => write!(f, "internal_error"),
2016 SpanStatus::UnknownError => write!(f, "unknown_error"),
2017 SpanStatus::Cancelled => write!(f, "cancelled"),
2018 SpanStatus::AlreadyExists => write!(f, "already_exists"),
2019 SpanStatus::FailedPrecondition => write!(f, "failed_precondition"),
2020 SpanStatus::Aborted => write!(f, "aborted"),
2021 SpanStatus::OutOfRange => write!(f, "out_of_range"),
2022 SpanStatus::DataLoss => write!(f, "data_loss"),
2023 }
2024 }
2025}
2026
2027#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
2029pub struct Transaction<'a> {
2030 #[serde(default = "event::default_id", serialize_with = "event::serialize_id")]
2032 pub event_id: Uuid,
2033 #[serde(
2035 rename = "transaction",
2036 default,
2037 skip_serializing_if = "Option::is_none"
2038 )]
2039 pub name: Option<String>,
2040 #[serde(default, skip_serializing_if = "Option::is_none")]
2042 pub release: Option<Cow<'a, str>>,
2043 #[serde(default, skip_serializing_if = "Option::is_none")]
2045 pub environment: Option<Cow<'a, str>>,
2046 #[serde(default, skip_serializing_if = "Option::is_none")]
2048 pub user: Option<User>,
2049 #[serde(default, skip_serializing_if = "Map::is_empty")]
2051 pub tags: Map<String, String>,
2052 #[serde(default, skip_serializing_if = "Map::is_empty")]
2054 pub extra: Map<String, Value>,
2055 #[serde(default, skip_serializing_if = "Option::is_none")]
2057 pub sdk: Option<Cow<'a, ClientSdkInfo>>,
2058 #[serde(
2060 default = "event::default_platform",
2061 skip_serializing_if = "event::is_default_platform"
2062 )]
2063 pub platform: Cow<'a, str>,
2064 #[serde(
2066 default,
2067 skip_serializing_if = "Option::is_none",
2068 with = "ts_rfc3339_opt"
2069 )]
2070 pub timestamp: Option<SystemTime>,
2071 #[serde(default = "SystemTime::now", with = "ts_seconds_float")]
2073 pub start_timestamp: SystemTime,
2074 pub spans: Vec<Span>,
2076 #[serde(
2078 default,
2079 skip_serializing_if = "Map::is_empty",
2080 deserialize_with = "deserialize_contexts"
2081 )]
2082 pub contexts: Map<String, Context>,
2083 #[serde(default, skip_serializing_if = "Option::is_none")]
2085 pub request: Option<Request>,
2086 #[serde(default, skip_serializing_if = "Option::is_none")]
2088 pub server_name: Option<Cow<'a, str>>,
2089}
2090
2091impl Default for Transaction<'_> {
2092 fn default() -> Self {
2093 Transaction {
2094 event_id: event::default_id(),
2095 name: Default::default(),
2096 user: Default::default(),
2097 tags: Default::default(),
2098 extra: Default::default(),
2099 release: Default::default(),
2100 environment: Default::default(),
2101 sdk: Default::default(),
2102 platform: event::default_platform(),
2103 timestamp: Default::default(),
2104 start_timestamp: SystemTime::now(),
2105 spans: Default::default(),
2106 contexts: Default::default(),
2107 request: Default::default(),
2108 server_name: Default::default(),
2109 }
2110 }
2111}
2112
2113impl<'a> Transaction<'a> {
2114 pub fn new() -> Transaction<'a> {
2116 Default::default()
2117 }
2118
2119 pub fn into_owned(self) -> Transaction<'static> {
2121 Transaction {
2122 event_id: self.event_id,
2123 name: self.name,
2124 user: self.user,
2125 tags: self.tags,
2126 extra: self.extra,
2127 release: self.release.map(|x| Cow::Owned(x.into_owned())),
2128 environment: self.environment.map(|x| Cow::Owned(x.into_owned())),
2129 sdk: self.sdk.map(|x| Cow::Owned(x.into_owned())),
2130 platform: Cow::Owned(self.platform.into_owned()),
2131 timestamp: self.timestamp,
2132 start_timestamp: self.start_timestamp,
2133 spans: self.spans,
2134 contexts: self.contexts,
2135 request: self.request,
2136 server_name: self.server_name.map(|x| Cow::Owned(x.into_owned())),
2137 }
2138 }
2139
2140 pub fn finish(&mut self) {
2142 self.timestamp = Some(SystemTime::now());
2143 }
2144
2145 pub fn finish_with_timestamp(&mut self, timestamp: SystemTime) {
2147 self.timestamp = Some(timestamp);
2148 }
2149}
2150
2151impl fmt::Display for Transaction<'_> {
2152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2153 write!(
2154 f,
2155 "Transaction(id: {}, ts: {})",
2156 self.event_id,
2157 crate::utils::to_rfc3339(&self.start_timestamp)
2158 )
2159 }
2160}
2161
2162#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
2164pub struct Log {
2165 pub level: LogLevel,
2167 pub body: String,
2169 #[serde(default, skip_serializing_if = "Option::is_none")]
2171 pub trace_id: Option<TraceId>,
2172 #[serde(with = "ts_seconds_float")]
2174 pub timestamp: SystemTime,
2175 #[serde(default, skip_serializing_if = "Option::is_none")]
2177 pub severity_number: Option<LogSeverityNumber>,
2178 #[serde(default, skip_serializing_if = "Map::is_empty")]
2180 pub attributes: Map<String, LogAttribute>,
2181}
2182
2183#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
2186#[serde(rename_all = "lowercase")]
2187pub enum LogLevel {
2188 Trace,
2190 Debug,
2192 Info,
2194 Warn,
2196 Error,
2198 Fatal,
2200}
2201
2202#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
2205pub struct LogSeverityNumber(u8);
2206
2207impl LogSeverityNumber {
2208 pub const MIN: u8 = 1;
2210 pub const MAX: u8 = 24;
2212}
2213
2214impl TryFrom<u8> for LogSeverityNumber {
2215 type Error = String;
2216
2217 fn try_from(value: u8) -> Result<Self, Self::Error> {
2218 if (LogSeverityNumber::MIN..=LogSeverityNumber::MAX).contains(&value) {
2219 Ok(Self(value))
2220 } else {
2221 Err(format!(
2222 "Log severity number must be between {} and {}",
2223 LogSeverityNumber::MIN,
2224 LogSeverityNumber::MAX
2225 ))
2226 }
2227 }
2228}
2229
2230#[derive(Clone, Debug, PartialEq)]
2232pub struct LogAttribute(pub Value);
2233
2234impl<T> From<T> for LogAttribute
2235where
2236 Value: From<T>,
2237{
2238 fn from(value: T) -> Self {
2239 Self(Value::from(value))
2240 }
2241}
2242
2243impl Serialize for LogAttribute {
2244 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2245 where
2246 S: serde::Serializer,
2247 {
2248 use serde::ser::SerializeStruct;
2249 let mut state = serializer.serialize_struct("LogAttribute", 2)?;
2250
2251 match &self.0 {
2252 Value::String(s) => {
2253 state.serialize_field("value", s.as_str())?;
2254 state.serialize_field("type", "string")?;
2255 }
2256 Value::Number(n) => {
2257 if let Some(i) = n.as_i64() {
2258 state.serialize_field("value", &i)?;
2259 state.serialize_field("type", "integer")?;
2260 } else if let Some(u) = n.as_u64() {
2261 state.serialize_field("value", &u.to_string())?;
2263 state.serialize_field("type", "string")?;
2264 } else if let Some(f) = n.as_f64() {
2265 state.serialize_field("value", &f)?;
2266 state.serialize_field("type", "double")?;
2267 } else {
2268 state.serialize_field("value", &n.to_string())?;
2270 state.serialize_field("type", "string")?;
2271 }
2272 }
2273 Value::Bool(b) => {
2274 state.serialize_field("value", &b)?;
2275 state.serialize_field("type", "boolean")?;
2276 }
2277 _ => {
2279 state.serialize_field("value", &self.0.to_string())?;
2280 state.serialize_field("type", "string")?;
2281 }
2282 }
2283
2284 state.end()
2285 }
2286}
2287
2288impl<'de> Deserialize<'de> for LogAttribute {
2289 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2290 where
2291 D: serde::Deserializer<'de>,
2292 {
2293 use serde::de::{self, MapAccess, Visitor};
2294 use std::fmt;
2295
2296 struct LogAttributeVisitor;
2297
2298 impl<'de> Visitor<'de> for LogAttributeVisitor {
2299 type Value = LogAttribute;
2300
2301 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2302 formatter.write_str("a LogAttribute with value and type fields")
2303 }
2304
2305 fn visit_map<V>(self, mut map: V) -> Result<LogAttribute, V::Error>
2306 where
2307 V: MapAccess<'de>,
2308 {
2309 let mut value: Option<serde_json::Value> = None;
2310 let mut type_str: Option<String> = None;
2311
2312 while let Some(key) = map.next_key::<String>()? {
2313 match key.as_str() {
2314 "value" => {
2315 if value.is_some() {
2316 return Err(de::Error::duplicate_field("value"));
2317 }
2318 value = Some(map.next_value()?);
2319 }
2320 "type" => {
2321 if type_str.is_some() {
2322 return Err(de::Error::duplicate_field("type"));
2323 }
2324 type_str = Some(map.next_value()?);
2325 }
2326 _ => {
2327 let _: serde_json::Value = map.next_value()?;
2329 }
2330 }
2331 }
2332
2333 let value = value.ok_or_else(|| de::Error::missing_field("value"))?;
2334 let type_str = type_str.ok_or_else(|| de::Error::missing_field("type"))?;
2335
2336 match type_str.as_str() {
2337 "string" => {
2338 if !value.is_string() {
2339 return Err(de::Error::custom(
2340 "type is 'string' but value is not a string",
2341 ));
2342 }
2343 }
2344 "integer" => {
2345 if !value.is_i64() {
2346 return Err(de::Error::custom(
2347 "type is 'integer' but value is not an integer",
2348 ));
2349 }
2350 }
2351 "double" => {
2352 if !value.is_f64() {
2353 return Err(de::Error::custom(
2354 "type is 'double' but value is not a double",
2355 ));
2356 }
2357 }
2358 "boolean" => {
2359 if !value.is_boolean() {
2360 return Err(de::Error::custom(
2361 "type is 'boolean' but value is not a boolean",
2362 ));
2363 }
2364 }
2365 _ => {
2366 return Err(de::Error::custom(format!(
2367 "expected type to be 'string' | 'integer' | 'double' | 'boolean', found {type_str}"
2368 )))
2369 }
2370 }
2371
2372 Ok(LogAttribute(value))
2373 }
2374 }
2375
2376 deserializer.deserialize_map(LogAttributeVisitor)
2377 }
2378}
2379
2380#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
2382#[serde(rename_all = "lowercase")]
2383pub enum MetricType {
2384 Counter,
2386 Gauge,
2388 Distribution,
2390}
2391
2392#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
2396pub struct Metric {
2397 pub r#type: MetricType,
2399 pub name: Cow<'static, str>,
2401 pub value: f64,
2403 #[serde(with = "ts_seconds_float")]
2405 pub timestamp: SystemTime,
2406 pub trace_id: TraceId,
2408 #[serde(default, skip_serializing_if = "Option::is_none")]
2410 pub span_id: Option<SpanId>,
2411 #[serde(default, skip_serializing_if = "Option::is_none")]
2413 pub unit: Option<Unit>,
2414 #[serde(default, skip_serializing_if = "Map::is_empty")]
2416 pub attributes: Map<Cow<'static, str>, LogAttribute>,
2417}
2418
2419#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
2421pub struct OrganizationId(u64);
2422
2423impl From<u64> for OrganizationId {
2424 fn from(value: u64) -> Self {
2425 Self(value)
2426 }
2427}
2428
2429impl std::str::FromStr for OrganizationId {
2430 type Err = std::num::ParseIntError;
2431
2432 fn from_str(s: &str) -> Result<Self, Self::Err> {
2433 s.parse().map(Self)
2434 }
2435}
2436
2437impl std::fmt::Display for OrganizationId {
2438 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2439 write!(f, "{}", self.0)
2440 }
2441}
2442
2443#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
2445pub struct SampleRand(f64);
2446
2447#[derive(Debug, Error)]
2449pub enum InvalidSampleRandError {
2450 #[error("failed to parse f64: {0}")]
2452 InvalidFloat(#[from] std::num::ParseFloatError),
2453
2454 #[error("sample rand value out of admissible interval [0.0, 1.0)")]
2457 OutOfRange,
2458}
2459
2460impl TryFrom<f64> for SampleRand {
2461 type Error = InvalidSampleRandError;
2462
2463 fn try_from(value: f64) -> Result<Self, Self::Error> {
2464 if !(0.0..1.0).contains(&value) {
2465 return Err(InvalidSampleRandError::OutOfRange);
2466 }
2467 Ok(Self(value))
2468 }
2469}
2470
2471impl std::str::FromStr for SampleRand {
2472 type Err = InvalidSampleRandError;
2473
2474 fn from_str(s: &str) -> Result<Self, Self::Err> {
2475 let x: f64 = s.parse().map_err(InvalidSampleRandError::InvalidFloat)?;
2476 Self::try_from(x)
2477 }
2478}
2479
2480impl std::fmt::Display for SampleRand {
2481 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2482 if self.0 >= 0.9999995 {
2486 write!(f, "0.999999")
2487 } else {
2488 write!(f, "{:.6}", self.0)
2489 }
2490 }
2491}
2492
2493#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
2501pub struct DynamicSamplingContext {
2502 #[serde(default, skip_serializing_if = "Option::is_none")]
2505 trace_id: Option<TraceId>,
2506 #[serde(default, skip_serializing_if = "Option::is_none")]
2507 public_key: Option<String>,
2508 #[serde(
2509 default,
2510 skip_serializing_if = "Option::is_none",
2511 with = "display_from_str_opt"
2512 )]
2513 sample_rate: Option<f32>,
2514 #[serde(
2516 default,
2517 skip_serializing_if = "Option::is_none",
2518 with = "display_from_str_opt"
2519 )]
2520 sample_rand: Option<SampleRand>,
2521 #[serde(
2522 default,
2523 skip_serializing_if = "Option::is_none",
2524 with = "display_from_str_opt"
2525 )]
2526 sampled: Option<bool>,
2527 #[serde(default, skip_serializing_if = "Option::is_none")]
2528 release: Option<String>,
2529 #[serde(default, skip_serializing_if = "Option::is_none")]
2530 environment: Option<String>,
2531 #[serde(default, skip_serializing_if = "Option::is_none")]
2532 transaction: Option<String>,
2533 #[serde(
2534 default,
2535 skip_serializing_if = "Option::is_none",
2536 with = "display_from_str_opt"
2537 )]
2538 org_id: Option<OrganizationId>,
2539}
2540
2541impl DynamicSamplingContext {
2542 pub fn new() -> Self {
2544 Default::default()
2545 }
2546
2547 #[must_use]
2549 pub fn with_trace_id(mut self, trace_id: TraceId) -> Self {
2550 self.trace_id = Some(trace_id);
2551 self
2552 }
2553
2554 #[must_use]
2556 pub fn with_public_key(mut self, public_key: String) -> Self {
2557 self.public_key = Some(public_key);
2558 self
2559 }
2560
2561 #[must_use]
2563 pub fn with_sample_rate(mut self, sample_rate: f32) -> Self {
2564 self.sample_rate = Some(sample_rate);
2565 self
2566 }
2567
2568 #[must_use]
2570 pub fn with_sample_rand(mut self, sample_rand: SampleRand) -> Self {
2571 self.sample_rand = Some(sample_rand);
2572 self
2573 }
2574
2575 #[must_use]
2577 pub fn with_sampled(mut self, sampled: bool) -> Self {
2578 self.sampled = Some(sampled);
2579 self
2580 }
2581
2582 #[must_use]
2584 pub fn with_release(mut self, release: String) -> Self {
2585 self.release = Some(release);
2586 self
2587 }
2588
2589 #[must_use]
2591 pub fn with_environment(mut self, environment: String) -> Self {
2592 self.environment = Some(environment);
2593 self
2594 }
2595
2596 #[must_use]
2598 pub fn with_transaction(mut self, transaction: String) -> Self {
2599 self.transaction = Some(transaction);
2600 self
2601 }
2602
2603 #[must_use]
2605 pub fn with_org_id(mut self, org_id: OrganizationId) -> Self {
2606 self.org_id = Some(org_id);
2607 self
2608 }
2609}