Skip to content

Commit 9acd049

Browse files
uemanbuenaflor
andauthored
Exception aggregate mechanism (#1866)
* Exception aggregate * changelog * Update CHANGELOG.md * fix json keys in test * Update dart/lib/src/protocol/mechanism.dart * Update CHANGELOG.md --------- Co-authored-by: Giancarlo Buenaflor <[email protected]>
1 parent 645aefa commit 9acd049

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
- Set ip_address to {{auto}} by default, even if sendDefaultPII is disabled ([#1665](https://github.com/getsentry/sentry-dart/pull/1665))
1919
- Instead use the "Prevent Storing of IP Addresses" option in the "Security & Privacy" project settings on sentry.io
2020

21+
### Features
22+
23+
- Add support for exception aggregates ([#1866](https://github.com/getsentry/sentry-dart/pull/1866))
24+
2125
## 7.20.0
2226

2327
### Build

dart/lib/src/protocol/mechanism.dart

+52
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,38 @@ class Mechanism {
4444
/// This may be because they are created at a central place (like a crash handler), and are all called the same: Error, Segfault etc. When the flag is set, Sentry will then try to use other information (top in-app frame function) rather than exception type and value in the UI for the primary event display. This flag should be set for all "segfaults" for instance as every single error group would look very similar otherwise.
4545
final bool? synthetic;
4646

47+
/// An optional boolean value, set `true` when the exception is the exception
48+
/// group type specific to the platform or language.
49+
/// The default is false when omitted.
50+
/// For example, exceptions of type [PlatformException](https://api.flutter.dev/flutter/services/PlatformException-class.html)
51+
/// have set it to `true`, others are set to `false`.
52+
final bool? isExceptionGroup;
53+
54+
/// An optional string value describing the source of the exception.
55+
///
56+
/// The SDK should populate this with the name of the property or attribute of
57+
/// the parent exception that this exception was acquired from.
58+
/// In the case of an array, it should include the zero-based array index as
59+
/// well.
60+
final String? source;
61+
62+
/// An optional numeric value providing an ID for the exception relative to
63+
/// this specific event.
64+
///
65+
/// The SDK should assign simple incrementing integers to each exception in
66+
/// the tree, starting with 0 for the root of the tree.
67+
/// In other words, when flattened into the list provided in the exception
68+
/// values on the event, the last exception in the list should have ID 0,
69+
/// the previous one should have ID 1, the next previous should have ID 2, etc.
70+
final int? exceptionId;
71+
72+
/// An optional numeric value pointing at the [exceptionId] that is the parent
73+
/// of this exception.
74+
///
75+
/// The SDK should assign this to all exceptions except the root exception
76+
/// (the last to be listed in the exception values).
77+
final int? parentId;
78+
4779
Mechanism({
4880
required this.type,
4981
this.description,
@@ -52,6 +84,10 @@ class Mechanism {
5284
this.synthetic,
5385
Map<String, dynamic>? meta,
5486
Map<String, dynamic>? data,
87+
this.isExceptionGroup,
88+
this.source,
89+
this.exceptionId,
90+
this.parentId,
5591
}) : _meta = meta != null ? Map.from(meta) : null,
5692
_data = data != null ? Map.from(data) : null;
5793

@@ -63,6 +99,10 @@ class Mechanism {
6399
Map<String, dynamic>? meta,
64100
Map<String, dynamic>? data,
65101
bool? synthetic,
102+
bool? isExceptionGroup,
103+
String? source,
104+
int? exceptionId,
105+
int? parentId,
66106
}) =>
67107
Mechanism(
68108
type: type ?? this.type,
@@ -72,6 +112,10 @@ class Mechanism {
72112
meta: meta ?? this.meta,
73113
data: data ?? this.data,
74114
synthetic: synthetic ?? this.synthetic,
115+
isExceptionGroup: isExceptionGroup ?? this.isExceptionGroup,
116+
source: source ?? this.source,
117+
exceptionId: exceptionId ?? this.exceptionId,
118+
parentId: parentId ?? this.parentId,
75119
);
76120

77121
/// Deserializes a [Mechanism] from JSON [Map].
@@ -94,6 +138,10 @@ class Mechanism {
94138
meta: meta,
95139
data: data,
96140
synthetic: json['synthetic'],
141+
isExceptionGroup: json['is_exception_group'],
142+
source: json['source'],
143+
exceptionId: json['exception_id'],
144+
parentId: json['parent_id'],
97145
);
98146
}
99147

@@ -107,6 +155,10 @@ class Mechanism {
107155
if (_meta?.isNotEmpty ?? false) 'meta': _meta,
108156
if (_data?.isNotEmpty ?? false) 'data': _data,
109157
if (synthetic != null) 'synthetic': synthetic,
158+
if (isExceptionGroup != null) 'is_exception_group': isExceptionGroup,
159+
if (source != null) 'source': source,
160+
if (exceptionId != null) 'exception_id': exceptionId,
161+
if (parentId != null) 'parent_id': parentId,
110162
};
111163
}
112164
}

dart/test/protocol/mechanism_test.dart

+17
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ void main() {
1111
synthetic: true,
1212
meta: {'key': 'value'},
1313
data: {'keyb': 'valueb'},
14+
isExceptionGroup: false,
15+
exceptionId: 0,
16+
parentId: 0,
17+
source: 'source',
1418
);
1519

1620
final mechanismJson = <String, dynamic>{
@@ -21,6 +25,10 @@ void main() {
2125
'meta': {'key': 'value'},
2226
'data': {'keyb': 'valueb'},
2327
'synthetic': true,
28+
'is_exception_group': false,
29+
'source': 'source',
30+
'exception_id': 0,
31+
'parent_id': 0,
2432
};
2533

2634
group('json', () {
@@ -51,6 +59,7 @@ void main() {
5159

5260
expect(data.toJson(), copy.toJson());
5361
});
62+
5463
test('copyWith takes new values', () {
5564
final data = mechanism;
5665

@@ -62,6 +71,10 @@ void main() {
6271
synthetic: false,
6372
meta: {'key1': 'value1'},
6473
data: {'keyb1': 'valueb1'},
74+
exceptionId: 1,
75+
parentId: 1,
76+
isExceptionGroup: false,
77+
source: 'foo',
6578
);
6679

6780
expect('type1', copy.type);
@@ -71,6 +84,10 @@ void main() {
7184
expect(false, copy.synthetic);
7285
expect({'key1': 'value1'}, copy.meta);
7386
expect({'keyb1': 'valueb1'}, copy.data);
87+
expect(1, copy.exceptionId);
88+
expect(1, copy.parentId);
89+
expect(false, copy.isExceptionGroup);
90+
expect('foo', copy.source);
7491
});
7592
});
7693
}

0 commit comments

Comments
 (0)