Skip to content

Commit e5a3315

Browse files
authored
Merge branch 'main' into feat/support-allow-urls-deny-urls
2 parents 102f0e5 + 3356741 commit e5a3315

File tree

98 files changed

+2695
-743
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+2695
-743
lines changed

CHANGELOG.md

+101-23
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,83 @@
55
### Features
66

77
- Support allowUrls and denyUrls for Flutter Web ([#2227](https://github.com/getsentry/sentry-dart/pull/2227))
8+
89
```dart
910
await SentryFlutter.init(
1011
(options) {
11-
options.dsn = 'https://[email protected]/0';
12+
...
1213
options.allowUrls = ["^https://sentry.com.*\$", "my-custom-domain"];
13-
options.denyUrls = ["^.*ends-with-this\$", "denied-url"];
14+
options.denyUrls = ["^.*ends-with-this\$", "denied-url"];
15+
},
16+
appRunner: () => runApp(MyApp()),
17+
);
18+
```
19+
20+
- Session replay Alpha for Android and iOS ([#2208](https://github.com/getsentry/sentry-dart/pull/2208)).
21+
22+
To try out replay, you can set following options (access is limited to early access orgs on Sentry. If you're interested, [sign up for the waitlist](https://sentry.io/lp/mobile-replay-beta/)):
23+
24+
```dart
25+
await SentryFlutter.init(
26+
(options) {
1427
...
28+
options.experimental.replay.sessionSampleRate = 1.0;
29+
options.experimental.replay.errorSampleRate = 1.0;
1530
},
1631
appRunner: () => runApp(MyApp()),
1732
);
1833
```
34+
35+
### Dependencies
36+
37+
- Bump Cocoa SDK from v8.35.1 to v8.36.0 ([#2252](https://github.com/getsentry/sentry-dart/pull/2252))
38+
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8360)
39+
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.35.1...8.36.0)
40+
41+
## 8.8.0
42+
43+
### Features
44+
45+
- Add `SentryFlutter.nativeCrash()` using MethodChannels for Android and iOS ([#2239](https://github.com/getsentry/sentry-dart/pull/2239))
46+
- This can be used to test if native crash reporting works
47+
1948
- Add `ignoreRoutes` parameter to `SentryNavigatorObserver`. ([#2218](https://github.com/getsentry/sentry-dart/pull/2218))
20-
- This will ignore the Routes and prevent the Route from being pushed to the Sentry server.
21-
- Ignored routes will also create no TTID and TTFD spans.
22-
```dart
23-
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
24-
```
49+
- This will ignore the Routes and prevent the Route from being pushed to the Sentry server.
50+
- Ignored routes will also create no TTID and TTFD spans.
51+
52+
```dart
53+
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
54+
```
2555

2656
### Improvements
2757

2858
- Debouncing of SentryWidgetsBindingObserver.didChangeMetrics with delay of 100ms. ([#2232](https://github.com/getsentry/sentry-dart/pull/2232))
2959

3060
### Dependencies
3161

62+
- Bump Cocoa SDK from v8.33.0 to v8.35.1 ([#2247](https://github.com/getsentry/sentry-dart/pull/2247))
63+
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8351)
64+
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.33.0...8.35.1)
65+
- Bump Android SDK from v7.13.0 to v7.14.0 ([#2228](https://github.com/getsentry/sentry-dart/pull/2228))
66+
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7140)
67+
- [diff](https://github.com/getsentry/sentry-java/compare/7.13.0...7.14.0)
68+
69+
## 8.8.0-alpha.1
70+
71+
### Features
72+
73+
- iOS Session Replay Alpha ([#2209](https://github.com/getsentry/sentry-dart/pull/2209))
74+
- Android replay touch tracking support ([#2228](https://github.com/getsentry/sentry-dart/pull/2228))
75+
- Add `ignoreRoutes` parameter to `SentryNavigatorObserver`. ([#2218](https://github.com/getsentry/sentry-dart/pull/2218))
76+
- This will ignore the Routes and prevent the Route from being pushed to the Sentry server.
77+
- Ignored routes will also create no TTID and TTFD spans.
78+
79+
```dart
80+
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
81+
```
82+
83+
### Dependencies
84+
3285
- Bump Android SDK from v7.13.0 to v7.14.0 ([#2228](https://github.com/getsentry/sentry-dart/pull/2228))
3386
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7140)
3487
- [diff](https://github.com/getsentry/sentry-java/compare/7.13.0...7.14.0)
@@ -39,6 +92,7 @@ SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
3992

4093
- Add support for span level measurements. ([#2214](https://github.com/getsentry/sentry-dart/pull/2214))
4194
- Add `ignoreTransactions` and `ignoreErrors` to options ([#2207](https://github.com/getsentry/sentry-dart/pull/2207))
95+
4296
```dart
4397
await SentryFlutter.init(
4498
(options) {
@@ -50,8 +104,10 @@ SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
50104
appRunner: () => runApp(MyApp()),
51105
);
52106
```
107+
53108
- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192))
54109
- Configure a `SentryProxy` object and set it on `SentryFlutter.init`
110+
55111
```dart
56112
import 'package:flutter/widgets.dart';
57113
import 'package:sentry_flutter/sentry_flutter.dart';
@@ -91,24 +147,25 @@ SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
91147
- This is enabled automatically and will change grouping if you already have issues with obfuscated titles
92148
- If you want to disable this feature, set `enableExceptionTypeIdentification` to `false` in your Sentry options
93149
- You can add your custom exception identifier if there are exceptions that we do not identify out of the box
94-
```dart
95-
// How to add your own custom exception identifier
96-
class MyCustomExceptionIdentifier implements ExceptionIdentifier {
97-
@override
98-
String? identifyType(Exception exception) {
99-
if (exception is MyCustomException) {
100-
return 'MyCustomException';
101-
}
102-
if (exception is MyOtherCustomException) {
103-
return 'MyOtherCustomException';
150+
151+
```dart
152+
// How to add your own custom exception identifier
153+
class MyCustomExceptionIdentifier implements ExceptionIdentifier {
154+
@override
155+
String? identifyType(Exception exception) {
156+
if (exception is MyCustomException) {
157+
return 'MyCustomException';
158+
}
159+
if (exception is MyOtherCustomException) {
160+
return 'MyOtherCustomException';
161+
}
162+
return null;
104163
}
105-
return null;
106164
}
107-
}
108165
109-
SentryFlutter.init((options) =>
110-
options..prependExceptionTypeIdentifier(MyCustomExceptionIdentifier()));
111-
```
166+
SentryFlutter.init((options) =>
167+
options..prependExceptionTypeIdentifier(MyCustomExceptionIdentifier()));
168+
```
112169

113170
### Deprecated
114171

@@ -124,6 +181,27 @@ SentryFlutter.init((options) =>
124181
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7130)
125182
- [diff](https://github.com/getsentry/sentry-java/compare/7.12.0...7.13.0)
126183

184+
## 8.6.0-alpha.2
185+
186+
### Features
187+
188+
- Android Session Replay Alpha ([#2032](https://github.com/getsentry/sentry-dart/pull/2032))
189+
190+
To try out replay, you can set following options:
191+
192+
```dart
193+
await SentryFlutter.init(
194+
(options) {
195+
...
196+
options.experimental.replay.sessionSampleRate = 1.0;
197+
options.experimental.replay.errorSampleRate = 1.0;
198+
},
199+
appRunner: () => runApp(MyApp()),
200+
);
201+
```
202+
203+
Access is limited to early access orgs on Sentry. If you're interested, [sign up for the waitlist](https://sentry.io/lp/mobile-replay-beta/)
204+
127205
## 8.5.0
128206

129207
### Features
@@ -136,7 +214,7 @@ SentryFlutter.init((options) =>
136214
### Fixes
137215

138216
- Disable sff & frame delay detection on web, linux and windows ([#2182](https://github.com/getsentry/sentry-dart/pull/2182))
139-
- Display refresh rate is locked at 60 for these platforms which can lead to inaccurate metrics
217+
- Display refresh rate is locked at 60 for these platforms which can lead to inaccurate metrics
140218

141219
### Improvements
142220

dart/lib/src/protocol/breadcrumb.dart

+30
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ class Breadcrumb {
5252
String? httpQuery,
5353
String? httpFragment,
5454
}) {
55+
// The timestamp is used as the request-end time, so we need to set it right
56+
// now and not rely on the default constructor.
57+
timestamp ??= getUtcDateTime();
58+
5559
return Breadcrumb(
5660
type: 'http',
5761
category: 'http',
@@ -67,6 +71,11 @@ class Breadcrumb {
6771
if (responseBodySize != null) 'response_body_size': responseBodySize,
6872
if (httpQuery != null) 'http.query': httpQuery,
6973
if (httpFragment != null) 'http.fragment': httpFragment,
74+
if (requestDuration != null)
75+
'start_timestamp':
76+
timestamp.millisecondsSinceEpoch - requestDuration.inMilliseconds,
77+
if (requestDuration != null)
78+
'end_timestamp': timestamp.millisecondsSinceEpoch,
7079
},
7180
);
7281
}
@@ -97,11 +106,32 @@ class Breadcrumb {
97106
String? viewClass,
98107
}) {
99108
final newData = data ?? {};
109+
var path = '';
110+
100111
if (viewId != null) {
101112
newData['view.id'] = viewId;
113+
path = viewId;
114+
}
115+
116+
if (newData.containsKey('label')) {
117+
if (path.isEmpty) {
118+
path = newData['label'];
119+
} else {
120+
path = "$path, label: ${newData['label']}";
121+
}
102122
}
123+
103124
if (viewClass != null) {
104125
newData['view.class'] = viewClass;
126+
if (path.isEmpty) {
127+
path = viewClass;
128+
} else {
129+
path = "$viewClass($path)";
130+
}
131+
}
132+
133+
if (path.isNotEmpty && !newData.containsKey('path')) {
134+
newData['path'] = path;
105135
}
106136

107137
return Breadcrumb(

dart/lib/src/protocol/sentry_trace_context.dart

+13-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ class SentryTraceContext {
1818
/// Id of a parent span
1919
final SpanId? parentSpanId;
2020

21+
/// Replay associated with this trace.
22+
final SentryId? replayId;
23+
2124
/// Whether the span is sampled or not
2225
final bool? sampled;
2326

@@ -50,6 +53,9 @@ class SentryTraceContext {
5053
? null
5154
: SpanId.fromId(json['parent_span_id'] as String),
5255
traceId: SentryId.fromId(json['trace_id'] as String),
56+
replayId: json['replay_id'] == null
57+
? null
58+
: SentryId.fromId(json['replay_id'] as String),
5359
description: json['description'] as String?,
5460
status: json['status'] == null
5561
? null
@@ -68,6 +74,7 @@ class SentryTraceContext {
6874
'trace_id': traceId.toString(),
6975
'op': operation,
7076
if (parentSpanId != null) 'parent_span_id': parentSpanId!.toString(),
77+
if (replayId != null) 'replay_id': replayId!.toString(),
7178
if (description != null) 'description': description,
7279
if (status != null) 'status': status!.toString(),
7380
if (origin != null) 'origin': origin,
@@ -84,6 +91,7 @@ class SentryTraceContext {
8491
sampled: sampled,
8592
origin: origin,
8693
unknown: unknown,
94+
replayId: replayId,
8795
);
8896

8997
SentryTraceContext({
@@ -96,16 +104,17 @@ class SentryTraceContext {
96104
this.status,
97105
this.origin,
98106
this.unknown,
107+
this.replayId,
99108
}) : traceId = traceId ?? SentryId.newId(),
100109
spanId = spanId ?? SpanId.newId();
101110

102111
@internal
103112
factory SentryTraceContext.fromPropagationContext(
104113
PropagationContext propagationContext) {
105114
return SentryTraceContext(
106-
traceId: propagationContext.traceId,
107-
spanId: propagationContext.spanId,
108-
operation: 'default',
109-
);
115+
traceId: propagationContext.traceId,
116+
spanId: propagationContext.spanId,
117+
operation: 'default',
118+
replayId: propagationContext.baggage?.getReplayId());
110119
}
111120
}

dart/lib/src/scope.dart

+10-1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ class Scope {
9797
/// they must be JSON-serializable.
9898
Map<String, dynamic> get extra => Map.unmodifiable(_extra);
9999

100+
/// Active replay recording.
101+
@internal
102+
SentryId? get replayId => _replayId;
103+
@internal
104+
set replayId(SentryId? value) => _replayId = value;
105+
SentryId? _replayId;
106+
100107
final Contexts _contexts = Contexts();
101108

102109
/// Unmodifiable map of the scope contexts key/value
@@ -237,6 +244,7 @@ class Scope {
237244
_tags.clear();
238245
_extra.clear();
239246
_eventProcessors.clear();
247+
_replayId = null;
240248

241249
_clearBreadcrumbsSync();
242250
_setUserSync(null);
@@ -429,7 +437,8 @@ class Scope {
429437
..fingerprint = List.from(fingerprint)
430438
.._transaction = _transaction
431439
..span = span
432-
.._enableScopeSync = false;
440+
.._enableScopeSync = false
441+
.._replayId = _replayId;
433442

434443
clone._setUserSync(user);
435444

dart/lib/src/sentry_baggage.dart

+10
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ class SentryBaggage {
111111
// ignore: deprecated_member_use_from_same_package
112112
setUserSegment(scope.user!.segment!);
113113
}
114+
if (scope.replayId != null && scope.replayId != SentryId.empty()) {
115+
setReplayId(scope.replayId.toString());
116+
}
114117
}
115118

116119
static Map<String, String> _extractKeyValuesFromBaggageString(
@@ -205,5 +208,12 @@ class SentryBaggage {
205208
return double.tryParse(sampleRate);
206209
}
207210

211+
void setReplayId(String value) => set('sentry-replay_id', value);
212+
213+
SentryId? getReplayId() {
214+
final replayId = get('sentry-replay_id');
215+
return replayId == null ? null : SentryId.fromId(replayId);
216+
}
217+
208218
Map<String, String> get keyValues => Map.unmodifiable(_keyValues);
209219
}

dart/lib/src/sentry_client.dart

+5-5
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,15 @@ class SentryClient {
168168

169169
var traceContext = scope?.span?.traceContext();
170170
if (traceContext == null) {
171-
if (scope?.propagationContext.baggage == null) {
172-
scope?.propagationContext.baggage =
173-
SentryBaggage({}, logger: _options.logger);
174-
scope?.propagationContext.baggage?.setValuesFromScope(scope, _options);
175-
}
176171
if (scope != null) {
172+
scope.propagationContext.baggage ??=
173+
SentryBaggage({}, logger: _options.logger)
174+
..setValuesFromScope(scope, _options);
177175
traceContext = SentryTraceContextHeader.fromBaggage(
178176
scope.propagationContext.baggage!);
179177
}
178+
} else {
179+
traceContext.replayId = scope?.replayId;
180180
}
181181

182182
final envelope = SentryEnvelope.fromEvent(

0 commit comments

Comments
 (0)