Skip to content

Commit 94daf24

Browse files
authored
Feature: Add http response to event (#934)
1 parent 982893c commit 94daf24

11 files changed

+469
-95
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
* Dio Integration adds response data ([#934](https://github.com/getsentry/sentry-dart/pull/934))
8+
39
## 6.7.0
410

511
### Fixes

dart/lib/src/protocol.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export 'protocol/mechanism.dart';
1111
export 'protocol/sentry_message.dart';
1212
export 'protocol/sentry_operating_system.dart';
1313
export 'protocol/sentry_request.dart';
14+
export 'protocol/sentry_response.dart';
1415
export 'protocol/sdk_info.dart';
1516
export 'protocol/sdk_version.dart';
1617
export 'protocol/sentry_event.dart';
@@ -22,7 +23,7 @@ export 'protocol/sentry_runtime.dart';
2223
export 'protocol/sentry_stack_frame.dart';
2324
export 'protocol/sentry_stack_trace.dart';
2425
export 'protocol/sentry_user.dart';
25-
export 'protocol/max_request_body_size.dart';
26+
export 'protocol/max_body_size.dart';
2627
export 'protocol/sentry_culture.dart';
2728
export 'protocol/sentry_thread.dart';
2829
export 'sentry_event_like.dart';

dart/lib/src/protocol/contexts.dart

+24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'dart:collection';
22

3+
import 'package:meta/meta.dart';
4+
35
import '../protocol.dart';
46

57
/// The context interfaces provide additional context data.
@@ -18,6 +20,7 @@ class Contexts extends MapView<String, dynamic> {
1820
SentryGpu? gpu,
1921
SentryCulture? culture,
2022
SentryTraceContext? trace,
23+
SentryResponse? response,
2124
}) : super({
2225
SentryDevice.type: device,
2326
SentryOperatingSystem.type: operatingSystem,
@@ -27,6 +30,7 @@ class Contexts extends MapView<String, dynamic> {
2730
SentryGpu.type: gpu,
2831
SentryCulture.type: culture,
2932
SentryTraceContext.type: trace,
33+
SentryResponse.type: response,
3034
});
3135

3236
/// Deserializes [Contexts] from JSON [Map].
@@ -57,6 +61,9 @@ class Contexts extends MapView<String, dynamic> {
5761
runtimes: data[SentryRuntime.type] != null
5862
? [SentryRuntime.fromJson(Map.from(data[SentryRuntime.type]))]
5963
: null,
64+
response: data[SentryResponse.type] != null
65+
? SentryResponse.fromJson(Map.from(data[SentryResponse.type]))
66+
: null,
6067
);
6168

6269
data.keys
@@ -126,6 +133,12 @@ class Contexts extends MapView<String, dynamic> {
126133

127134
set trace(SentryTraceContext? trace) => this[SentryTraceContext.type] = trace;
128135

136+
/// Response context for a HTTP response.
137+
@experimental
138+
SentryResponse? get response => this[SentryResponse.type];
139+
140+
set response(SentryResponse? value) => this[SentryResponse.type] = value;
141+
129142
/// Produces a [Map] that can be serialized to JSON.
130143
Map<String, dynamic> toJson() {
131144
final json = <String, dynamic>{};
@@ -174,6 +187,13 @@ class Contexts extends MapView<String, dynamic> {
174187
}
175188
break;
176189

190+
case SentryResponse.type:
191+
final responseMap = response?.toJson();
192+
if (responseMap?.isNotEmpty ?? false) {
193+
json[SentryResponse.type] = responseMap;
194+
}
195+
break;
196+
177197
case SentryTraceContext.type:
178198
final traceMap = trace?.toJson();
179199
if (traceMap?.isNotEmpty ?? false) {
@@ -230,6 +250,7 @@ class Contexts extends MapView<String, dynamic> {
230250
culture: culture?.clone(),
231251
gpu: gpu?.clone(),
232252
trace: trace?.clone(),
253+
response: response?.clone(),
233254
runtimes: runtimes.map((runtime) => runtime.clone()).toList(),
234255
)..addEntries(
235256
entries.where((element) => !_defaultFields.contains(element.key)),
@@ -247,6 +268,7 @@ class Contexts extends MapView<String, dynamic> {
247268
SentryCulture? culture,
248269
SentryGpu? gpu,
249270
SentryTraceContext? trace,
271+
SentryResponse? response,
250272
}) =>
251273
Contexts(
252274
device: device ?? this.device,
@@ -257,6 +279,7 @@ class Contexts extends MapView<String, dynamic> {
257279
gpu: gpu ?? this.gpu,
258280
culture: culture ?? this.culture,
259281
trace: trace ?? this.trace,
282+
response: response ?? this.response,
260283
)..addEntries(
261284
entries.where((element) => !_defaultFields.contains(element.key)),
262285
);
@@ -271,5 +294,6 @@ class Contexts extends MapView<String, dynamic> {
271294
SentryBrowser.type,
272295
SentryCulture.type,
273296
SentryTraceContext.type,
297+
SentryResponse.type,
274298
];
275299
}
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// See https://docs.sentry.io/platforms/dotnet/guides/aspnetcore/configuration/options/#max-request-body-size
2+
import 'package:meta/meta.dart';
3+
4+
const _mediumSize = 10000;
5+
const _smallSize = 4000;
6+
7+
/// Describes the size of http request bodies which should be added to an event
8+
enum MaxRequestBodySize {
9+
/// Request bodies are never sent
10+
never,
11+
12+
/// Only small request bodies will be captured where the cutoff for small
13+
/// depends on the SDK (typically 4KB)
14+
small,
15+
16+
/// Medium and small requests will be captured (typically 10KB)
17+
medium,
18+
19+
/// The SDK will always capture the request body for as long as Sentry can
20+
/// make sense of it
21+
always,
22+
}
23+
24+
extension MaxRequestBodySizeX on MaxRequestBodySize {
25+
bool shouldAddBody(int contentLength) {
26+
if (this == MaxRequestBodySize.never) {
27+
return false;
28+
}
29+
if (this == MaxRequestBodySize.always) {
30+
return true;
31+
}
32+
if (this == MaxRequestBodySize.medium && contentLength <= _mediumSize) {
33+
return true;
34+
}
35+
36+
if (this == MaxRequestBodySize.small && contentLength <= _smallSize) {
37+
return true;
38+
}
39+
return false;
40+
}
41+
}
42+
43+
/// Describes the size of http response bodies which should be added to an event
44+
/// This enum might be removed at any time.
45+
@experimental
46+
enum MaxResponseBodySize {
47+
/// Response bodies are never sent
48+
never,
49+
50+
/// Only small response bodies will be captured where the cutoff for small
51+
/// depends on the SDK (typically 4KB)
52+
small,
53+
54+
/// Medium and small response will be captured (typically 10KB)
55+
medium,
56+
57+
/// The SDK will always capture the request body for as long as Sentry can
58+
/// make sense of it
59+
always,
60+
}
61+
62+
extension MaxResponseBodySizeX on MaxResponseBodySize {
63+
bool shouldAddBody(int contentLength) {
64+
if (this == MaxResponseBodySize.never) {
65+
return false;
66+
}
67+
if (this == MaxResponseBodySize.always) {
68+
return true;
69+
}
70+
if (this == MaxResponseBodySize.medium && contentLength <= _mediumSize) {
71+
return true;
72+
}
73+
74+
if (this == MaxResponseBodySize.small && contentLength <= _smallSize) {
75+
return true;
76+
}
77+
return false;
78+
}
79+
}

dart/lib/src/protocol/max_request_body_size.dart

-36
This file was deleted.
+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import 'package:meta/meta.dart';
2+
import 'contexts.dart';
3+
4+
/// The response interface contains information on a HTTP request related to the event.
5+
/// This is an experimental feature. It might be removed at any time.
6+
@experimental
7+
@immutable
8+
class SentryResponse {
9+
/// The tpye of this class in the [Contexts] field
10+
static const String type = 'response';
11+
12+
/// The URL of the response if available.
13+
/// This might be the redirected URL
14+
final String? url;
15+
16+
/// Indicates whether or not the response is the result of a redirect
17+
/// (that is, its URL list has more than one entry).
18+
final bool? redirected;
19+
20+
/// The body of the response
21+
final Object? body;
22+
23+
/// The HTTP status code of the response.
24+
/// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
25+
final int? statusCode;
26+
27+
/// The status message for the corresponding [statusCode]
28+
final String? status;
29+
30+
/// An immutable dictionary of submitted headers.
31+
/// If a header appears multiple times it,
32+
/// needs to be merged according to the HTTP standard for header merging.
33+
/// Header names are treated case-insensitively by Sentry.
34+
Map<String, String> get headers => Map.unmodifiable(_headers ?? const {});
35+
36+
final Map<String, String>? _headers;
37+
38+
Map<String, String> get other => Map.unmodifiable(_other ?? const {});
39+
40+
final Map<String, String>? _other;
41+
42+
SentryResponse({
43+
this.url,
44+
this.body,
45+
this.redirected,
46+
this.statusCode,
47+
this.status,
48+
Map<String, String>? headers,
49+
Map<String, String>? other,
50+
}) : _headers = headers != null ? Map.from(headers) : null,
51+
_other = other != null ? Map.from(other) : null;
52+
53+
/// Deserializes a [SentryResponse] from JSON [Map].
54+
factory SentryResponse.fromJson(Map<String, dynamic> json) {
55+
return SentryResponse(
56+
url: json['url'],
57+
headers: json['headers'],
58+
other: json['other'],
59+
body: json['body'],
60+
statusCode: json['status_code'],
61+
status: json['status'],
62+
redirected: json['redirected'],
63+
);
64+
}
65+
66+
/// Produces a [Map] that can be serialized to JSON.
67+
Map<String, dynamic> toJson() {
68+
return <String, dynamic>{
69+
if (url != null) 'url': url,
70+
if (headers.isNotEmpty) 'headers': headers,
71+
if (other.isNotEmpty) 'other': other,
72+
if (redirected != null) 'redirected': redirected,
73+
if (body != null) 'body': body,
74+
if (status != null) 'status': status,
75+
if (statusCode != null) 'status_code': statusCode,
76+
};
77+
}
78+
79+
SentryResponse copyWith({
80+
String? url,
81+
bool? redirected,
82+
int? statusCode,
83+
String? status,
84+
Object? body,
85+
Map<String, String>? headers,
86+
Map<String, String>? other,
87+
}) =>
88+
SentryResponse(
89+
url: url ?? this.url,
90+
headers: headers ?? _headers,
91+
redirected: redirected ?? this.redirected,
92+
other: other ?? _other,
93+
body: body ?? this.body,
94+
status: status ?? this.status,
95+
statusCode: statusCode ?? this.statusCode,
96+
);
97+
98+
SentryResponse clone() => SentryResponse(
99+
body: body,
100+
headers: headers,
101+
other: other,
102+
redirected: redirected,
103+
status: status,
104+
statusCode: statusCode,
105+
url: url,
106+
);
107+
}

0 commit comments

Comments
 (0)