Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(replays): add replay_id onto event from dynamic sampling context #1983

Merged
merged 23 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Metrics:
**Features**:

- Allow monitor checkins to paass `monitor_config` for monitor upserts. ([#1962](https://github.com/getsentry/relay/pull/1962))
- Add replay_id onto event from dynamic sampling context. ([#1983](https://github.com/getsentry/relay/pull/1983))

**Internal**:

Expand Down
5 changes: 5 additions & 0 deletions relay-general/src/protocol/contexts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod os;
pub use os::*;
mod profile;
pub use profile::*;
mod replay;
pub use replay::*;
mod reprocessing;
pub use reprocessing::*;
mod response;
Expand Down Expand Up @@ -53,6 +55,8 @@ pub enum Context {
Trace(Box<TraceContext>),
/// Information related to Profiling.
Profile(Box<ProfileContext>),
/// Information related to Replay.
Replay(Box<ReplayContext>),
/// Information related to Monitors feature.
Monitor(Box<MonitorContext>),
/// Auxilliary information for reprocessing.
Expand Down Expand Up @@ -85,6 +89,7 @@ impl Context {
Context::Trace(_) => Some(TraceContext::default_key()),
Context::Profile(_) => Some(ProfileContext::default_key()),
Context::Monitor(_) => Some(MonitorContext::default_key()),
Context::Replay(_) => Some(ReplayContext::default_key()),
Context::Response(_) => Some(ResponseContext::default_key()),
Context::Otel(_) => Some(OtelContext::default_key()),
Context::CloudResource(_) => Some(CloudResourceContext::default_key()),
Expand Down
51 changes: 51 additions & 0 deletions relay-general/src/protocol/contexts/replay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::protocol::EventId;
use crate::types::Annotated;

/// Replay context
jjbayer marked this conversation as resolved.
Show resolved Hide resolved
JoshFerge marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
#[cfg_attr(feature = "jsonschema", derive(JsonSchema))]
pub struct ReplayContext {
/// The replay ID.
#[metastructure(required = "true")]
pub replay_id: Annotated<EventId>,
}
JoshFerge marked this conversation as resolved.
Show resolved Hide resolved

impl ReplayContext {
/// The key under which a replay context is generally stored (in `Contexts`)
JoshFerge marked this conversation as resolved.
Show resolved Hide resolved
pub fn default_key() -> &'static str {
"replay"
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::protocol::Context;

#[test]
pub(crate) fn test_trace_context_roundtrip() {
let json = r#"{
"replay_id": "4c79f60c11214eb38604f4ae0781bfb2",
"type": "replay"
}"#;
let context = Annotated::new(Context::Replay(Box::new(ReplayContext {
replay_id: Annotated::new(EventId("4c79f60c11214eb38604f4ae0781bfb2".parse().unwrap())),
})));

assert_eq!(context, Annotated::from_json(json).unwrap());
assert_eq!(json, context.to_json_pretty().unwrap());
}

#[test]
pub(crate) fn test_replay_context_normalization() {
let json = r#"{
"replay_id": "4C79F60C11214EB38604F4AE0781BFB2",
"type": "replay"
}"#;
let context = Annotated::new(Context::Replay(Box::new(ReplayContext {
replay_id: Annotated::new(EventId("4c79f60c11214eb38604f4ae0781bfb2".parse().unwrap())),
})));

assert_eq!(context, Annotated::from_json(json).unwrap());
}
}
28 changes: 28 additions & 0 deletions relay-general/tests/snapshots/test_fixtures__event_schema.snap
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,9 @@ expression: "relay_general::protocol::event_json_schema()"
{
"$ref": "#/definitions/ProfileContext"
},
{
"$ref": "#/definitions/ReplayContext"
},
{
"$ref": "#/definitions/MonitorContext"
},
Expand Down Expand Up @@ -2665,6 +2668,31 @@ expression: "relay_general::protocol::event_json_schema()"
"RegVal": {
"type": "string"
},
"ReplayContext": {
"description": " Replay context",
"anyOf": [
{
"type": "object",
"required": [
"replay_id"
],
"properties": {
"replay_id": {
"description": " The replay ID.",
"anyOf": [
{
"$ref": "#/definitions/EventId"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
}
]
},
"Request": {
"description": " Http request information.\n\n The Request interface contains information on a HTTP request related to the event. In client\n SDKs, this can be an outgoing request, or the request that rendered the current web page. On\n server SDKs, this could be the incoming web request that is being handled.\n\n The data variable should only contain the request body (not the query string). It can either be\n a dictionary (for standard HTTP requests) or a raw request body.\n\n ### Ordered Maps\n\n In the Request interface, several attributes can either be declared as string, object, or list\n of tuples. Sentry attempts to parse structured information from the string representation in\n such cases.\n\n Sometimes, keys can be declared multiple times, or the order of elements matters. In such\n cases, use the tuple representation over a plain object.\n\n Example of request headers as object:\n\n ```json\n {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json, application/xml\"\n }\n ```\n\n Example of the same headers as list of tuples:\n\n ```json\n [\n [\"content-type\", \"application/json\"],\n [\"accept\", \"application/json\"],\n [\"accept\", \"application/xml\"]\n ]\n ```\n\n Example of a fully populated request object:\n\n ```json\n {\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"http://absolute.uri/foo\",\n \"query_string\": \"query=foobar&page=2\",\n \"data\": {\n \"foo\": \"bar\"\n },\n \"cookies\": \"PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;\",\n \"headers\": {\n \"content-type\": \"text/html\"\n },\n \"env\": {\n \"REMOTE_ADDR\": \"192.168.0.1\"\n }\n }\n }\n ```",
"anyOf": [
Expand Down
21 changes: 21 additions & 0 deletions relay-sampling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,8 @@ pub struct DynamicSamplingContext {
/// user object).
#[serde(flatten, default)]
pub user: TraceUserContext,
/// if the event occured during a session replay, the associated replay_id is added to the DSC
JoshFerge marked this conversation as resolved.
Show resolved Hide resolved
pub replay_id: Option<Uuid>,
/// Additional arbitrary fields for forwards compatibility.
#[serde(flatten, default)]
pub other: BTreeMap<String, Value>,
Expand Down Expand Up @@ -1197,6 +1199,7 @@ impl DynamicSamplingContext {
release: event.release.as_str().map(str::to_owned),
environment: event.environment.value().cloned(),
transaction: event.transaction.value().cloned(),
replay_id: None,
sample_rate: None,
user: TraceUserContext {
user_segment: user
Expand Down Expand Up @@ -1311,6 +1314,7 @@ mod tests {
transaction: None,
sample_rate: None,
user: TraceUserContext::default(),
replay_id: None,
other: BTreeMap::new(),
}
}
Expand Down Expand Up @@ -1413,6 +1417,7 @@ mod tests {
user_segment: user_segment.to_string(),
user_id: user_id.to_string(),
},
replay_id: Default::default(),
other: Default::default(),
}
}
Expand Down Expand Up @@ -1587,6 +1592,7 @@ mod tests {
environment: Some("prod".into()),
transaction: Some("transaction1".into()),
sample_rate: None,
replay_id: Some(Uuid::new_v4()),
other: BTreeMap::new(),
};

Expand Down Expand Up @@ -1622,6 +1628,7 @@ mod tests {
environment: None,
transaction: None,
sample_rate: None,
replay_id: None,
other: BTreeMap::new(),
};
assert_eq!(Value::Null, dsc.get_value("trace.release"));
Expand All @@ -1638,6 +1645,7 @@ mod tests {
environment: None,
transaction: None,
sample_rate: None,
replay_id: None,
other: BTreeMap::new(),
};
assert_eq!(Value::Null, dsc.get_value("trace.user.id"));
Expand Down Expand Up @@ -1742,6 +1750,7 @@ mod tests {
user_segment: "vip".into(),
user_id: "user-id".into(),
},
replay_id: Some(Uuid::new_v4()),
environment: Some("debug".into()),
transaction: Some("transaction1".into()),
sample_rate: None,
Expand Down Expand Up @@ -1917,6 +1926,7 @@ mod tests {
user_segment: "vip".to_owned(),
user_id: "user-id".to_owned(),
},
replay_id: Some(Uuid::new_v4()),
environment: Some("debug".to_string()),
transaction: Some("transaction1".into()),
sample_rate: None,
Expand Down Expand Up @@ -1979,6 +1989,7 @@ mod tests {
user_segment: "vip".to_owned(),
user_id: "user-id".to_owned(),
},
replay_id: Some(Uuid::new_v4()),
environment: Some("debug".to_string()),
transaction: Some("transaction1".into()),
sample_rate: None,
Expand Down Expand Up @@ -2018,6 +2029,7 @@ mod tests {
user_segment: "vip".to_owned(),
user_id: "user-id".to_owned(),
},
replay_id: Some(Uuid::new_v4()),
environment: Some("debug".to_string()),
transaction: Some("transaction1".into()),
sample_rate: None,
Expand Down Expand Up @@ -2080,6 +2092,7 @@ mod tests {
user_segment: "vip".to_owned(),
user_id: "user-id".to_owned(),
},
replay_id: Some(Uuid::new_v4()),
environment: Some("debug".to_string()),
transaction: Some("transaction1".into()),
sample_rate: None,
Expand Down Expand Up @@ -2467,6 +2480,7 @@ mod tests {
user_segment: "vip".to_owned(),
user_id: "user-id".to_owned(),
},
replay_id: Some(Uuid::new_v4()),
environment: Some("debug".to_string()),
transaction: Some("transaction1".into()),
sample_rate: None,
Expand All @@ -2487,6 +2501,7 @@ mod tests {
public_key: ProjectKey::parse("abd0f232775f45feab79864e580d160b").unwrap(),
release: Some("1.1.1".to_string()),
user: TraceUserContext::default(),
replay_id: Some(Uuid::new_v4()),
environment: Some("debug".to_string()),
transaction: Some("transaction1".into()),
sample_rate: None,
Expand All @@ -2510,6 +2525,7 @@ mod tests {
user_segment: "vip".to_owned(),
user_id: "user-id".to_owned(),
},
replay_id: None,
environment: None,
transaction: Some("transaction1".into()),
sample_rate: None,
Expand All @@ -2533,6 +2549,7 @@ mod tests {
user_segment: "vip".to_owned(),
user_id: "user-id".to_owned(),
},
replay_id: None,
environment: Some("debug".to_string()),
transaction: None,
sample_rate: None,
Expand All @@ -2549,6 +2566,7 @@ mod tests {
public_key: ProjectKey::parse("abd0f232775f45feab79864e580d160b").unwrap(),
release: None,
user: TraceUserContext::default(),
replay_id: None,
environment: None,
transaction: None,
sample_rate: None,
Expand Down Expand Up @@ -2944,6 +2962,7 @@ mod tests {
"environment": None,
"transaction": None,
"user_id": "hello",
"replay_id": None,
}
"###);
}
Expand All @@ -2968,6 +2987,7 @@ mod tests {
"transaction": None,
"sample_rate": "0.5",
"user_id": "hello",
"replay_id": None,
}
"###);
}
Expand All @@ -2992,6 +3012,7 @@ mod tests {
"transaction": None,
"sample_rate": "0.00001",
"user_id": "hello",
"replay_id": None,
}
"###);
}
Expand Down
Loading