Skip to content

Commit 0336a02

Browse files
authored
feat(types): add Response context (#874)
1 parent 9df3816 commit 0336a02

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
## Features
6+
7+
- feat(core): add Response context ([#874](https://github.com/getsentry/sentry-rust/pull/874)) by @lcian
8+
- The `Response` context can now be attached to events, to include information about HTTP responses such as headers, cookies and status code.
9+
- Example:
10+
```rust
11+
let mut event = Event::new();
12+
let response = ResponseContext {
13+
cookies: Some(r#""csrftoken": "1234567""#.to_owned()),
14+
headers: Some(headers_map),
15+
status_code: Some(500),
16+
body_size: Some(15),
17+
data: Some("Invalid request"),
18+
};
19+
event
20+
.contexts
21+
.insert("response".to_owned(), response.into());
22+
```
23+
324
## 0.42.0
425

526
### Features

sentry-types/src/protocol/v7.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,8 @@ pub enum Context {
11001100
Gpu(Box<GpuContext>),
11011101
/// OpenTelemetry data.
11021102
Otel(Box<OtelContext>),
1103+
/// HTTP response data.
1104+
Response(Box<ResponseContext>),
11031105
/// Generic other context data.
11041106
#[serde(rename = "unknown")]
11051107
Other(Map<String, Value>),
@@ -1117,6 +1119,7 @@ impl Context {
11171119
Context::Trace(..) => "trace",
11181120
Context::Gpu(..) => "gpu",
11191121
Context::Otel(..) => "otel",
1122+
Context::Response(..) => "response",
11201123
Context::Other(..) => "unknown",
11211124
}
11221125
}
@@ -1351,6 +1354,29 @@ pub struct OtelContext {
13511354
pub other: Map<String, Value>,
13521355
}
13531356

1357+
/// Holds information about an HTTP response.
1358+
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
1359+
pub struct ResponseContext {
1360+
/// The unparsed cookie values.
1361+
#[serde(default, skip_serializing_if = "Option::is_none")]
1362+
pub cookies: Option<String>,
1363+
/// A map of submitted headers.
1364+
///
1365+
/// If a header appears multiple times, it needs to be merged according to the HTTP standard
1366+
/// for header merging. Header names are treated case-insensitively by Sentry.
1367+
#[serde(default, skip_serializing_if = "Map::is_empty")]
1368+
pub headers: Map<String, String>,
1369+
/// The HTTP response status code.
1370+
#[serde(default, skip_serializing_if = "Option::is_none")]
1371+
pub status_code: Option<u64>,
1372+
/// The response body size in bytes.
1373+
#[serde(default, skip_serializing_if = "Option::is_none")]
1374+
pub body_size: Option<u64>,
1375+
/// Response data in any format that makes sense.
1376+
#[serde(default, skip_serializing_if = "Option::is_none")]
1377+
pub data: Option<Value>,
1378+
}
1379+
13541380
/// Holds the identifier for a Span
13551381
#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash)]
13561382
#[serde(try_from = "String", into = "String")]
@@ -1501,9 +1527,10 @@ into_context!(Browser, BrowserContext);
15011527
into_context!(Trace, TraceContext);
15021528
into_context!(Gpu, GpuContext);
15031529
into_context!(Otel, OtelContext);
1530+
into_context!(Response, ResponseContext);
15041531

15051532
const INFERABLE_CONTEXTS: &[&str] = &[
1506-
"device", "os", "runtime", "app", "browser", "trace", "gpu", "otel",
1533+
"device", "os", "runtime", "app", "browser", "trace", "gpu", "otel", "response",
15071534
];
15081535

15091536
struct ContextsVisitor;

sentry-types/tests/test_protocol_v7.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,43 @@ mod test_contexts {
13131313
);
13141314
}
13151315

1316+
#[test]
1317+
fn test_response_context() {
1318+
let event = v7::Event {
1319+
event_id: event_id(),
1320+
timestamp: event_time(),
1321+
contexts: {
1322+
let mut m = v7::Map::new();
1323+
m.insert(
1324+
"response".into(),
1325+
v7::ResponseContext {
1326+
status_code: Some(400),
1327+
cookies: Some("sessionId=abc123; Path=/; HttpOnly,authToken=xyz789; Secure; SameSite=Strict".into()),
1328+
headers: {
1329+
let mut hm = v7::Map::new();
1330+
hm.insert("Content-Type".into(), "text/plain".into());
1331+
hm
1332+
},
1333+
body_size: Some(1000),
1334+
data: Some("lol".into()),
1335+
}
1336+
.into(),
1337+
);
1338+
m
1339+
},
1340+
..Default::default()
1341+
};
1342+
1343+
assert_roundtrip(&event);
1344+
assert_eq!(
1345+
serde_json::to_string(&event).unwrap(),
1346+
"{\"event_id\":\"d43e86c96e424a93a4fbda156dd17341\",\"timestamp\":1514103120,\
1347+
\"contexts\":{\"response\":{\"type\":\"response\",\
1348+
\"cookies\":\"sessionId=abc123; Path=/; HttpOnly,authToken=xyz789; Secure; SameSite=Strict\",\
1349+
\"headers\":{\"Content-Type\":\"text/plain\"},\"status_code\":400,\"body_size\":1000,\"data\":\"lol\"}}}"
1350+
);
1351+
}
1352+
13161353
#[test]
13171354
fn test_renamed_contexts() {
13181355
let event = v7::Event {

0 commit comments

Comments
 (0)