From bdcbb8a3ab56640e2025c7b4beb9ca8de15837d8 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Fri, 23 Mar 2018 19:14:46 +0100 Subject: [PATCH] feat: Added debug meta and repos --- Cargo.toml | 1 + src/lib.rs | 1 + src/protocol/v7.rs | 137 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f1b1778a..ed60e4c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ serde_json = "1.0" serde_plain = "0.3.0" url_serde = "0.2.0" chrono = { version = "0.4.0", features = ["serde"] } +uuid = { version = "0.6.2", features = ["serde"] } [patch.crates-io] serde = { git = "https://github.com/mitsuhiko/serde", branch = "feature/flatten" } diff --git a/src/lib.rs b/src/lib.rs index 54e53b80..3b6bfcdd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ extern crate serde_json; extern crate serde_plain; extern crate url; extern crate url_serde; +extern crate uuid; #[macro_use] mod macros; diff --git a/src/protocol/v7.rs b/src/protocol/v7.rs index 9bd446fa..3d861c69 100644 --- a/src/protocol/v7.rs +++ b/src/protocol/v7.rs @@ -7,6 +7,7 @@ use chrono; use chrono::{DateTime, Utc}; use url_serde; use url::Url; +use uuid::Uuid; use serde::de::{Deserialize, Deserializer, Error as DeError}; use serde::ser::{Error as SerError, Serialize, SerializeMap, Serializer}; use serde_json::{from_value, to_value, Value}; @@ -182,6 +183,7 @@ pub struct Exception { pub stacktrace: Option, } +/// Represents the level of severity of an event or breadcrumb #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[serde(rename_all = "lowercase")] pub enum Level { @@ -281,6 +283,85 @@ pub struct Request { #[serde(flatten)] pub other: HashMap, } +/// Represents debug meta information. +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[serde(default)] +pub struct SdkInfo { + /// The internal name of the SDK + sdk_name: String, + /// the major version of the SDK as integer or 0 + version_major: u32, + /// the minor version of the SDK as integer or 0 + version_minior: u32, + /// the patch version of the SDK as integer or 0 + version_patchlevel: u32, +} + +/// Represents a debug image. +#[derive(Debug, Clone, PartialEq)] +pub enum DebugImage { + Apple(AppleDebugImage), + Proguard(ProguardDebugImage), + Unknown(HashMap), +} + +impl DebugImage { + /// Returns the name of the type on sentry. + pub fn type_name(&self) -> &str { + match *self { + DebugImage::Apple(..) => "apple", + DebugImage::Proguard(..) => "proguard", + DebugImage::Unknown(ref map) => map.get("type") + .and_then(|x| x.as_str()) + .unwrap_or("unknown"), + } + } +} + +/// Represents an apple debug image in the debug meta. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct AppleDebugImage { + pub name: String, + pub arch: Option, + pub cpu_type: u32, + pub cpu_subtype: u32, + pub image_addr: u64, + pub image_size: u64, + pub image_vmaddr: u64, + pub uuid: Uuid, +} + +/// Represents a proguard mapping file reference. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ProguardDebugImage { + pub uuid: Uuid, +} + +/// Represents debug meta information. +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[serde(default)] +pub struct DebugMeta { + /// Optional system SDK information. + #[serde(skip_serializing_if = "Option::is_none")] + sdk_info: Option, + /// A list of debug information files. + #[serde(skip_serializing_if = "Option::is_none")] + images: Option, +} + +/// Represents a repository reference. +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[serde(default)] +pub struct RepoReference { + /// The name of the repository as it is registered in Sentry. + pub name: String, + /// The optional prefix path to apply to source code when pairing it + /// up with files in the repository. + pub prefix: Option, + /// The optional current revision of the local repository. + pub revision: Option, +} + /// Represents a full event for Sentry. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(default)] @@ -312,6 +393,9 @@ pub struct Event { /// A release identifier. #[serde(skip_serializing_if = "Option::is_none")] pub release: Option, + /// Repository references + #[serde(skip_serializing_if = "HashMap::is_empty")] + pub repos: HashMap, /// An optional distribution identifer. #[serde(skip_serializing_if = "Option::is_none")] pub dist: Option, @@ -350,9 +434,13 @@ pub struct Event { /// Optional extra information to be sent with the event. #[serde(skip_serializing_if = "HashMap::is_empty")] pub extra: HashMap, + /// Debug meta information. + #[serde(skip_serializing_if = "Option::is_none")] + pub debug_meta: Option, /// Additional arbitrary keys for forwards compatibility. #[serde(flatten)] pub other: HashMap, + // TODO: repos, sdk, logger, culprit, modules } fn is_other(value: &str) -> bool { @@ -374,6 +462,7 @@ impl Default for Event { timestamp: None, server_name: None, release: None, + repos: HashMap::new(), dist: None, environment: None, user: None, @@ -386,6 +475,7 @@ impl Default for Event { threads: Vec::new(), tags: HashMap::new(), extra: HashMap::new(), + debug_meta: None, other: HashMap::new(), } } @@ -554,7 +644,7 @@ fn serialize_context(value: &HashMap, serializer: S) -> Resu where S: Serializer, { - let mut map = try!(serializer.serialize_map(Some(value.len()))); + let mut map = try!(serializer.serialize_map(None)); for (key, value) in value { let mut c = match to_value(&value.data).map_err(S::Error::custom)? { @@ -629,3 +719,48 @@ where } Helper { values: &value }.serialize(serializer) } + +impl<'de> Deserialize<'de> for DebugImage { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let mut map = match Value::deserialize(deserializer)? { + Value::Object(map) => map, + _ => return Err(D::Error::custom("expected debug image")), + }; + + Ok(match map.remove("type").as_ref().and_then(|x| x.as_str()) { + Some("apple") => { + let img: AppleDebugImage = + from_value(Value::Object(map)).map_err(D::Error::custom)?; + DebugImage::Apple(img) + } + Some("proguard") => { + let img: ProguardDebugImage = + from_value(Value::Object(map)).map_err(D::Error::custom)?; + DebugImage::Proguard(img) + } + Some(ty) => { + let mut img: HashMap = map.into_iter().collect(); + img.insert("type".into(), ty.into()); + DebugImage::Unknown(img) + } + None => DebugImage::Unknown(Default::default()), + }) + } +} + +impl Serialize for DebugImage { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut c = match to_value(self).map_err(S::Error::custom)? { + Value::Object(map) => map, + _ => unreachable!(), + }; + c.insert("type".into(), self.type_name().into()); + c.serialize(serializer) + } +}