From 8846c23cdba27d2e9c040f026524d8cd96bd3087 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 22 Mar 2018 10:55:41 +0100 Subject: [PATCH] feat: Added more compliant breadcrumb interface as per protocol spec v7 --- Cargo.toml | 1 + src/lib.rs | 1 + src/protocol/v7.rs | 71 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2829a651..f1b1778a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ serde_derive = "1.0" serde_json = "1.0" serde_plain = "0.3.0" url_serde = "0.2.0" +chrono = { version = "0.4.0", 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 296e3776..54e53b80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ //! Sentry server. It's used by the sentry relay infrastructure as well as the //! rust Sentry client/. #![warn(missing_docs)] +extern crate chrono; extern crate failure; #[macro_use] extern crate failure_derive; diff --git a/src/protocol/v7.rs b/src/protocol/v7.rs index f3b3ce10..a44940e3 100644 --- a/src/protocol/v7.rs +++ b/src/protocol/v7.rs @@ -2,6 +2,8 @@ use std::collections::HashMap; use std::net::IpAddr; +use chrono; +use chrono::{DateTime, Utc}; use url_serde; use url::Url; use serde::de::{Deserialize, Deserializer, Error as DeError}; @@ -47,14 +49,72 @@ pub struct SingleException { pub stacktrace: Option, } +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(rename_all = "lowercase")] +pub enum Level { + Debug, + Info, + Warning, + Error, + Critical, +} + +impl Default for Level { + fn default() -> Level { + Level::Info + } +} + +impl Level { + /// A quick way to check if the level is `debug`. + pub fn is_debug(&self) -> bool { + *self == Level::Debug + } + + /// A quick way to check if the level is `info`. + pub fn is_info(&self) -> bool { + *self == Level::Info + } + + /// A quick way to check if the level is `warning`. + pub fn is_warning(&self) -> bool { + *self == Level::Warning + } + + /// A quick way to check if the level is `error`. + pub fn is_error(&self) -> bool { + *self == Level::Error + } + + /// A quick way to check if the level is `critical`. + pub fn is_critical(&self) -> bool { + *self == Level::Critical + } +} + /// Represents a single breadcrumb -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(default)] pub struct Breadcrumb { - pub timestamp: f64, + #[serde(with = "chrono::serde::ts_seconds")] pub timestamp: DateTime, #[serde(rename = "type")] pub ty: String, - pub message: String, - pub category: String, - #[serde(flatten)] pub data: HashMap, + #[serde(skip_serializing_if = "Option::is_none")] pub category: Option, + #[serde(skip_serializing_if = "Level::is_info")] pub level: Level, + #[serde(skip_serializing_if = "Option::is_none")] pub message: Option, + #[serde(skip_serializing_if = "HashMap::is_empty")] pub data: HashMap, +} + +impl Default for Breadcrumb { + fn default() -> Breadcrumb { + Breadcrumb { + timestamp: Utc::now(), + ty: "default".into(), + category: None, + level: Default::default(), + message: None, + data: HashMap::new(), + } + } } /// Represents user info. @@ -89,6 +149,7 @@ pub struct Request { pub struct Event { #[serde(skip_serializing_if = "Option::is_none")] pub level: Option, #[serde(skip_serializing_if = "Option::is_none")] pub fingerprint: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub message: Option, #[serde(skip_serializing_if = "Option::is_none")] pub logentry: Option, #[serde(skip_serializing_if = "Option::is_none")] pub platform: Option, #[serde(skip_serializing_if = "Option::is_none")] pub timestamp: Option,