Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions relay-general/derive/src/jsonschema.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::Visibility;
use syn::{Attribute, Visibility};

use crate::parse_field_attributes;

fn is_doc_attr(attr: &Attribute) -> bool {
attr.parse_meta()
.ok()
.and_then(|meta| Some(meta.path().get_ident()? == "doc"))
.unwrap_or(false)
}

pub fn derive_jsonschema(mut s: synstructure::Structure<'_>) -> TokenStream {
let _ = s.add_bounds(synstructure::AddBounds::Generics);

Expand All @@ -30,12 +37,7 @@ pub fn derive_jsonschema(mut s: synstructure::Structure<'_>) -> TokenStream {

let mut ast = bi.ast().clone();
ast.vis = Visibility::Inherited;
ast.attrs.retain(|attr| {
attr.parse_meta()
.ok()
.and_then(|meta| Some(meta.path().get_ident()? == "doc"))
.unwrap_or(false)
});
ast.attrs.retain(is_doc_attr);
fields = quote!(#fields #ast,);
}

Expand All @@ -54,6 +56,12 @@ pub fn derive_jsonschema(mut s: synstructure::Structure<'_>) -> TokenStream {
}

let ident = &s.ast().ident;
let mut attrs = quote!();
for attr in &s.ast().attrs {
if is_doc_attr(attr) {
attrs = quote!(#attrs #attr);
}
}

s.gen_impl(quote! {
// Massive hack to tell schemars that fields are nullable. Causes it to emit {"default":
Expand All @@ -72,6 +80,7 @@ pub fn derive_jsonschema(mut s: synstructure::Structure<'_>) -> TokenStream {
#[derive(schemars::JsonSchema)]
#[cfg_attr(feature = "jsonschema", schemars(untagged))]
#[cfg_attr(feature = "jsonschema", schemars(deny_unknown_fields))]
#attrs
enum Helper {
#arms
}
Expand Down
89 changes: 83 additions & 6 deletions relay-general/src/protocol/breadcrumb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,107 @@ use chrono::{TimeZone, Utc};
use crate::protocol::{Level, Timestamp};
use crate::types::{Annotated, Object, Value};

/// A breadcrumb.
/// The Breadcrumbs Interface specifies a series of application events, or "breadcrumbs", that
/// occurred before an event.
///
/// An event may contain one or more breadcrumbs in an attribute named `breadcrumbs`. The entries
/// are ordered from oldest to newest. Consequently, the last entry in the list should be the last
/// entry before the event occurred.
///
/// While breadcrumb attributes are not strictly validated in Sentry, a breadcrumb is most useful
/// when it includes at least a `timestamp` and `type`, `category` or `message`. The rendering of
/// breadcrumbs in Sentry depends on what is provided.
///
/// The following example illustrates the breadcrumbs part of the event payload and omits other
/// attributes for simplicity.
///
/// ```json
/// {
/// "breadcrumbs": {
/// "values": [
/// {
/// "timestamp": "2016-04-20T20:55:53.845Z",
/// "message": "Something happened",
/// "category": "log",
/// "data": {
/// "foo": "bar",
/// "blub": "blah"
/// }
/// },
/// {
/// "timestamp": "2016-04-20T20:55:53.847Z",
/// "type": "navigation",
/// "data": {
/// "from": "/login",
/// "to": "/dashboard"
/// }
/// }
/// ]
/// }
/// }
/// ```
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, ToValue, ProcessValue)]
#[cfg_attr(feature = "jsonschema", derive(JsonSchema))]
#[metastructure(process_func = "process_breadcrumb", value_type = "Breadcrumb")]
pub struct Breadcrumb {
/// The timestamp of the breadcrumb.
/// The timestamp of the breadcrumb. Recommended.
///
/// A timestamp representing when the breadcrumb occurred. The format is either a string as
/// defined in [RFC 3339](https://tools.ietf.org/html/rfc3339) or a numeric (integer or float)
/// value representing the number of seconds that have elapsed since the [Unix
/// epoch](https://en.wikipedia.org/wiki/Unix_time).
///
/// Breadcrumbs are most useful when they include a timestamp, as it creates a timeline leading
/// up to an event.
pub timestamp: Annotated<Timestamp>,

/// The type of the breadcrumb.
/// The type of the breadcrumb. _Optional_, defaults to `default`.
///
/// - `default`: Describes a generic breadcrumb. This is typically a log message or
/// user-generated breadcrumb. The `data` field is entirely undefined and as such, completely
/// rendered as a key/value table.
///
/// - `navigation`: Describes a navigation breadcrumb. A navigation event can be a URL change
/// in a web application, or a UI transition in a mobile or desktop application, etc.
///
/// Such a breadcrumb's `data` object has the required fields `from` and `to`, which
/// represent an application route/url each.
///
/// - `http`: Describes an HTTP request breadcrumb. This represents an HTTP request transmitted
/// from your application. This could be an AJAX request from a web application, or a
/// server-to-server HTTP request to an API service provider, etc.
///
/// Such a breadcrumb's `data` property has the fields `url`, `method`, `status_code`
/// (integer) and `reason` (string).
#[metastructure(field = "type", max_chars = "enumlike")]
pub ty: Annotated<String>,

/// The optional category of the breadcrumb.
/// A dotted string indicating what the crumb is or from where it comes. _Optional._
///
/// Typically it is a module name or a descriptive string. For instance, _ui.click_ could be
/// used to indicate that a click happened in the UI or _flask_ could be used to indicate that
/// the event originated in the Flask framework.
#[metastructure(max_chars = "enumlike")]
pub category: Annotated<String>,

/// Severity level of the breadcrumb.
/// Severity level of the breadcrumb. _Optional._
///
/// Allowed values are, from highest to lowest: `fatal`, `error`, `warning`, `info`, and
/// `debug`. Levels are used in the UI to emphasize and deemphasize the crumb. Defaults to
/// `info`.
pub level: Annotated<Level>,

/// Human readable message for the breadcrumb.
///
/// If a message is provided, it is rendered as text with all whitespace preserved. Very long
/// text might be truncated in the UI.
#[metastructure(pii = "true", max_chars = "message")]
pub message: Annotated<String>,

/// Custom user-defined data of this breadcrumb.
/// Arbitrary data associated with this breadcrumb.
///
/// Contains a dictionary whose contents depend on the breadcrumb `type`. Additional parameters
/// that are unsupported by the type are rendered as a key/value table.
#[metastructure(pii = "true", bag_size = "medium")]
#[metastructure(skip_serialization = "empty")]
pub data: Annotated<Object<Value>>,
Expand Down
34 changes: 28 additions & 6 deletions relay-general/src/protocol/clientsdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,51 @@ pub struct ClientSdkPackage {
pub version: Annotated<String>,
}

/// Information about the Sentry SDK.
/// The SDK Interface describes the Sentry SDK and its configuration used to capture and transmit an event.
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, ToValue, ProcessValue)]
#[cfg_attr(feature = "jsonschema", derive(JsonSchema))]
#[metastructure(process_func = "process_client_sdk_info", value_type = "ClientSdkInfo")]
pub struct ClientSdkInfo {
/// Unique SDK name.
/// Unique SDK name. _Required._
///
/// The name of the SDK. The format is `entity.ecosystem[.flavor]` where entity identifies the
/// developer of the SDK, ecosystem refers to the programming language or platform where the
/// SDK is to be used and the optional flavor is used to identify standalone SDKs that are part
/// of a major ecosystem.
///
/// Official Sentry SDKs use the entity `sentry`, as in `sentry.python` or
/// `sentry.javascript.react-native`. Please use a different entity for your own SDKs.
#[metastructure(required = "true", max_chars = "symbol")]
pub name: Annotated<String>,

/// SDK version.
/// The version of the SDK. _Required._
///
/// It should have the [Semantic Versioning](https://semver.org/) format `MAJOR.MINOR.PATCH`,
/// without any prefix (no `v` or anything else in front of the major version number).
///
/// Examples: `0.1.0`, `1.0.0`, `4.3.12`
#[metastructure(required = "true", max_chars = "symbol")]
pub version: Annotated<String>,

/// List of integrations that are enabled in the SDK.
/// List of integrations that are enabled in the SDK. _Optional._
///
/// The list should have all enabled integrations, including default integrations. Default
/// integrations are included because different SDK releases may contain different default
/// integrations.
#[metastructure(skip_serialization = "empty_deep")]
pub integrations: Annotated<Array<String>>,

/// List of installed and loaded SDK packages.
/// List of installed and loaded SDK packages. _Optional._
///
/// A list of packages that were installed as part of this SDK or the activated integrations.
/// Each package consists of a name in the format `source:identifier` and `version`. If the
/// source is a Git repository, the `source` should be `git`, the identifier should be a
/// checkout link and the version should be a Git reference (branch, tag or SHA).
#[metastructure(skip_serialization = "empty_deep")]
pub packages: Annotated<Array<ClientSdkPackage>>,

/// IP Address of sender??? Seems unused.
#[metastructure(pii = "true", skip_serialization = "empty")]
#[metastructure(pii = "true", skip_serialization = "empty", omit_from_schema)]
pub client_ip: Annotated<IpAddr>,

/// Additional arbitrary fields for forwards compatibility.
Expand Down
Loading