Skip to content

Commit 3b50810

Browse files
committed
Merge branch 'main' into feat/proxy-setup
2 parents 2e9926e + c19bfb6 commit 3b50810

Some content is hidden

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

46 files changed

+620
-71
lines changed

CHANGELOG.md

+48-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,53 @@
11
# Changelog
22

3-
## Unreleased
3+
## Unreleased
4+
5+
### Improvements
6+
7+
- Add error type identifier to improve obfuscated Flutter issue titles ([#2170](https://github.com/getsentry/sentry-dart/pull/2170))
8+
- Example: transforms issue titles from `GA` to `FlutterError` or `minified:nE` to `FlutterError`
9+
- This is enabled automatically and will change grouping if you already have issues with obfuscated titles
10+
- If you want to disable this feature, set `enableExceptionTypeIdentification` to `false` in your Sentry options
11+
- You can add your custom exception identifier if there are exceptions that we do not identify out of the box
12+
```dart
13+
// How to add your own custom exception identifier
14+
class MyCustomExceptionIdentifier implements ExceptionIdentifier {
15+
@override
16+
String? identifyType(Exception exception) {
17+
if (exception is MyCustomException) {
18+
return 'MyCustomException';
19+
}
20+
if (exception is MyOtherCustomException) {
21+
return 'MyOtherCustomException';
22+
}
23+
return null;
24+
}
25+
}
26+
27+
SentryFlutter.init((options) =>
28+
options..prependExceptionTypeIdentifier(MyCustomExceptionIdentifier()));
29+
```
30+
31+
### Deprecated
32+
33+
- Deprecate `enableTracing` ([#2199](https://github.com/getsentry/sentry-dart/pull/2199))
34+
- The `enableTracing` option has been deprecated and will be removed in the next major version. We recommend removing it
35+
in favor of the `tracesSampleRate` and `tracesSampler` options. If you want to enable performance monitoring, please set
36+
the `tracesSampleRate` to a sample rate of your choice, or provide a sampling function as `tracesSampler` option
37+
instead. If you want to disable performance monitoring, remove the `tracesSampler` and `tracesSampleRate` options.
38+
39+
### Dependencies
40+
41+
- Bump Android SDK from v7.12.0 to v7.12.1 ([#2198](https://github.com/getsentry/sentry-dart/pull/2198))
42+
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7121)
43+
- [diff](https://github.com/getsentry/sentry-java/compare/7.12.0...7.12.1)
44+
45+
## 8.5.0
446

547
### Features
648

49+
- Add dart platform to sentry frames ([#2193](https://github.com/getsentry/sentry-dart/pull/2193))
50+
- This allows viewing the correct dart formatted raw stacktrace in the Sentry UI
751
- Support `ignoredExceptionsForType` ([#2150](https://github.com/getsentry/sentry-dart/pull/2150))
852
- Filter out exception types by calling `SentryOptions.addExceptionFilterForType(Type exceptionType)`
953
- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192))
@@ -25,9 +69,9 @@
2569
- [diff](https://github.com/getsentry/sentry-java/compare/7.11.0...7.12.0)
2670
- updates AGP to v7.4.2
2771
- updates Kotlin to v1.8.0
28-
- Bump Cocoa SDK from v8.30.1 to v8.31.1 ([#2174](https://github.com/getsentry/sentry-dart/pull/2174))
29-
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8311)
30-
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.30.1...8.31.1)
72+
- Bump Cocoa SDK from v8.30.1 to v8.32.0 ([#2174](https://github.com/getsentry/sentry-dart/pull/2174), [#2195](https://github.com/getsentry/sentry-dart/pull/2195))
73+
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8320)
74+
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.30.1...8.32.0)
3175

3276
## 8.4.0
3377

dart/lib/sentry.dart

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export 'src/sentry_baggage.dart';
4040
export 'src/exception_cause_extractor.dart';
4141
export 'src/exception_cause.dart';
4242
export 'src/exception_stacktrace_extractor.dart';
43+
export 'src/exception_type_identifier.dart';
4344
// URL
4445
// ignore: invalid_export_of_internal_element
4546
export 'src/utils/http_sanitizer.dart';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import 'package:http/http.dart' show ClientException;
2+
import 'dart:async' show TimeoutException, AsyncError, DeferredLoadException;
3+
import '../sentry.dart';
4+
5+
import 'dart_exception_type_identifier_io.dart'
6+
if (dart.library.html) 'dart_exception_type_identifier_web.dart';
7+
8+
class DartExceptionTypeIdentifier implements ExceptionTypeIdentifier {
9+
@override
10+
String? identifyType(dynamic throwable) {
11+
// dart:core
12+
if (throwable is ArgumentError) return 'ArgumentError';
13+
if (throwable is AssertionError) return 'AssertionError';
14+
if (throwable is ConcurrentModificationError) {
15+
return 'ConcurrentModificationError';
16+
}
17+
if (throwable is FormatException) return 'FormatException';
18+
if (throwable is IndexError) return 'IndexError';
19+
if (throwable is NoSuchMethodError) return 'NoSuchMethodError';
20+
if (throwable is OutOfMemoryError) return 'OutOfMemoryError';
21+
if (throwable is RangeError) return 'RangeError';
22+
if (throwable is StackOverflowError) return 'StackOverflowError';
23+
if (throwable is StateError) return 'StateError';
24+
if (throwable is TypeError) return 'TypeError';
25+
if (throwable is UnimplementedError) return 'UnimplementedError';
26+
if (throwable is UnsupportedError) return 'UnsupportedError';
27+
// not adding Exception or Error because it's too generic
28+
29+
// dart:async
30+
if (throwable is TimeoutException) return 'TimeoutException';
31+
if (throwable is AsyncError) return 'FutureTimeout';
32+
if (throwable is DeferredLoadException) return 'DeferredLoadException';
33+
// not adding ParallelWaitError because it's not supported in dart 2.17.0
34+
35+
// dart http package
36+
if (throwable is ClientException) return 'ClientException';
37+
38+
// platform specific exceptions
39+
return identifyPlatformSpecificException(throwable);
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'dart:io';
2+
3+
import 'package:meta/meta.dart';
4+
5+
@internal
6+
String? identifyPlatformSpecificException(dynamic throwable) {
7+
if (throwable is FileSystemException) return 'FileSystemException';
8+
if (throwable is HttpException) return 'HttpException';
9+
if (throwable is SocketException) return 'SocketException';
10+
if (throwable is HandshakeException) return 'HandshakeException';
11+
if (throwable is CertificateException) return 'CertificateException';
12+
if (throwable is TlsException) return 'TlsException';
13+
return null;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import 'package:meta/meta.dart';
2+
3+
@internal
4+
String? identifyPlatformSpecificException(dynamic throwable) {
5+
return null;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'package:meta/meta.dart';
2+
3+
/// An abstract class for identifying the type of Dart errors and exceptions.
4+
///
5+
/// It's used in scenarios where error types need to be determined in obfuscated builds
6+
/// as [runtimeType] is not reliable in such cases.
7+
///
8+
/// Implement this class to create custom error type identifiers for errors or exceptions.
9+
/// that we do not support out of the box.
10+
///
11+
/// Example:
12+
/// ```dart
13+
/// class MyExceptionTypeIdentifier implements ExceptionTypeIdentifier {
14+
/// @override
15+
/// String? identifyType(dynamic throwable) {
16+
/// if (throwable is MyCustomError) return 'MyCustomError';
17+
/// return null;
18+
/// }
19+
/// }
20+
/// ```
21+
abstract class ExceptionTypeIdentifier {
22+
String? identifyType(dynamic throwable);
23+
}
24+
25+
extension CacheableExceptionIdentifier on ExceptionTypeIdentifier {
26+
ExceptionTypeIdentifier withCache() => CachingExceptionTypeIdentifier(this);
27+
}
28+
29+
@visibleForTesting
30+
class CachingExceptionTypeIdentifier implements ExceptionTypeIdentifier {
31+
@visibleForTesting
32+
ExceptionTypeIdentifier get identifier => _identifier;
33+
final ExceptionTypeIdentifier _identifier;
34+
35+
final Map<Type, String?> _knownExceptionTypes = {};
36+
37+
CachingExceptionTypeIdentifier(this._identifier);
38+
39+
@override
40+
String? identifyType(dynamic throwable) {
41+
final runtimeType = throwable.runtimeType;
42+
if (_knownExceptionTypes.containsKey(runtimeType)) {
43+
return _knownExceptionTypes[runtimeType];
44+
}
45+
46+
final identifiedType = _identifier.identifyType(throwable);
47+
48+
if (identifiedType != null) {
49+
_knownExceptionTypes[runtimeType] = identifiedType;
50+
}
51+
52+
return identifiedType;
53+
}
54+
}

dart/lib/src/sentry.dart

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22

33
import 'package:meta/meta.dart';
44

5+
import 'dart_exception_type_identifier.dart';
56
import 'metrics/metrics_api.dart';
67
import 'run_zoned_guarded_integration.dart';
78
import 'event_processor/enricher/enricher_event_processor.dart';
@@ -85,6 +86,8 @@ class Sentry {
8586
options.addEventProcessor(EnricherEventProcessor(options));
8687
options.addEventProcessor(ExceptionEventProcessor(options));
8788
options.addEventProcessor(DeduplicationEventProcessor(options));
89+
90+
options.prependExceptionTypeIdentifier(DartExceptionTypeIdentifier());
8891
}
8992

9093
/// This method reads available environment variables and uses them

dart/lib/src/sentry_client.dart

+13-12
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11
import 'dart:async';
22
import 'dart:math';
3+
34
import 'package:meta/meta.dart';
4-
import 'utils/stacktrace_utils.dart';
5-
import 'metrics/metric.dart';
6-
import 'metrics/metrics_aggregator.dart';
7-
import 'sentry_baggage.dart';
8-
import 'sentry_attachment/sentry_attachment.dart';
95

6+
import 'client_reports/client_report_recorder.dart';
7+
import 'client_reports/discard_reason.dart';
108
import 'event_processor.dart';
119
import 'hint.dart';
12-
import 'sentry_trace_context_header.dart';
13-
import 'sentry_user_feedback.dart';
14-
import 'transport/rate_limiter.dart';
10+
import 'metrics/metric.dart';
11+
import 'metrics/metrics_aggregator.dart';
1512
import 'protocol.dart';
1613
import 'scope.dart';
14+
import 'sentry_attachment/sentry_attachment.dart';
15+
import 'sentry_baggage.dart';
16+
import 'sentry_envelope.dart';
1717
import 'sentry_exception_factory.dart';
1818
import 'sentry_options.dart';
1919
import 'sentry_stack_trace_factory.dart';
20+
import 'sentry_trace_context_header.dart';
21+
import 'sentry_user_feedback.dart';
22+
import 'transport/data_category.dart';
2023
import 'transport/http_transport.dart';
2124
import 'transport/noop_transport.dart';
25+
import 'transport/rate_limiter.dart';
2226
import 'transport/spotlight_http_transport.dart';
2327
import 'transport/task_queue.dart';
2428
import 'utils/isolate_utils.dart';
29+
import 'utils/stacktrace_utils.dart';
2530
import 'version.dart';
26-
import 'sentry_envelope.dart';
27-
import 'client_reports/client_report_recorder.dart';
28-
import 'client_reports/discard_reason.dart';
29-
import 'transport/data_category.dart';
3031

3132
/// Default value for [SentryUser.ipAddress]. It gets set when an event does not have
3233
/// a user and IP address. Only applies if [SentryOptions.sendDefaultPii] is set

dart/lib/src/sentry_exception_factory.dart

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import 'utils/stacktrace_utils.dart';
2-
3-
import 'recursive_exception_cause_extractor.dart';
41
import 'protocol.dart';
2+
import 'recursive_exception_cause_extractor.dart';
53
import 'sentry_options.dart';
64
import 'sentry_stack_trace_factory.dart';
75
import 'throwable_mechanism.dart';
6+
import 'utils/stacktrace_utils.dart';
87

98
/// class to convert Dart Error and exception to SentryException
109
class SentryExceptionFactory {
@@ -62,10 +61,22 @@ class SentryExceptionFactory {
6261
final stackTraceString = stackTrace.toString();
6362
final value = throwableString.replaceAll(stackTraceString, '').trim();
6463

64+
String errorTypeName = throwable.runtimeType.toString();
65+
66+
if (_options.enableExceptionTypeIdentification) {
67+
for (final errorTypeIdentifier in _options.exceptionTypeIdentifiers) {
68+
final identifiedErrorType = errorTypeIdentifier.identifyType(throwable);
69+
if (identifiedErrorType != null) {
70+
errorTypeName = identifiedErrorType;
71+
break;
72+
}
73+
}
74+
}
75+
6576
// if --obfuscate feature is enabled, 'type' won't be human readable.
6677
// https://flutter.dev/docs/deployment/obfuscate#caveat
6778
return SentryException(
68-
type: (throwable.runtimeType).toString(),
79+
type: errorTypeName,
6980
value: value.isNotEmpty ? value : null,
7081
mechanism: mechanism,
7182
stackTrace: sentryStackTrace,

dart/lib/src/sentry_options.dart

+33-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import 'dart:async';
22
import 'dart:developer';
33

4-
import 'package:meta/meta.dart';
54
import 'package:http/http.dart';
5+
import 'package:meta/meta.dart';
66

77
import '../sentry.dart';
88
import 'client_reports/client_report_recorder.dart';
99
import 'client_reports/noop_client_report_recorder.dart';
10-
import 'sentry_exception_factory.dart';
11-
import 'sentry_stack_trace_factory.dart';
1210
import 'diagnostic_logger.dart';
1311
import 'environment/environment_variables.dart';
1412
import 'noop_client.dart';
13+
import 'sentry_exception_factory.dart';
14+
import 'sentry_stack_trace_factory.dart';
1515
import 'transport/noop_transport.dart';
1616
import 'version.dart';
1717

@@ -398,6 +398,8 @@ class SentryOptions {
398398
/// Enables generation of transactions and propagation of trace data. If set
399399
/// to null, tracing might be enabled if [tracesSampleRate] or [tracesSampler]
400400
/// are set.
401+
@Deprecated(
402+
'Use either tracesSampleRate or tracesSampler instead. This will be removed in v9')
401403
bool? enableTracing;
402404

403405
/// Enables sending developer metrics to Sentry.
@@ -452,6 +454,33 @@ class SentryOptions {
452454
/// Settings this to `false` will set the `level` to [SentryLevel.error].
453455
bool markAutomaticallyCollectedErrorsAsFatal = true;
454456

457+
/// Enables identification of exception types in obfuscated builds.
458+
/// When true, the SDK will attempt to identify common exception types
459+
/// to improve readability of obfuscated issue titles.
460+
///
461+
/// If you already have events with obfuscated issue titles this will change grouping.
462+
///
463+
/// Default: `true`
464+
bool enableExceptionTypeIdentification = true;
465+
466+
final List<ExceptionTypeIdentifier> _exceptionTypeIdentifiers = [];
467+
468+
List<ExceptionTypeIdentifier> get exceptionTypeIdentifiers =>
469+
List.unmodifiable(_exceptionTypeIdentifiers);
470+
471+
void addExceptionTypeIdentifierByIndex(
472+
int index, ExceptionTypeIdentifier exceptionTypeIdentifier) {
473+
_exceptionTypeIdentifiers.insert(
474+
index, exceptionTypeIdentifier.withCache());
475+
}
476+
477+
/// Adds an exception type identifier to the beginning of the list.
478+
/// This ensures it is processed first and takes precedence over existing identifiers.
479+
void prependExceptionTypeIdentifier(
480+
ExceptionTypeIdentifier exceptionTypeIdentifier) {
481+
addExceptionTypeIdentifierByIndex(0, exceptionTypeIdentifier);
482+
}
483+
455484
/// The Spotlight configuration.
456485
/// Disabled by default.
457486
/// ```dart
@@ -523,6 +552,7 @@ class SentryOptions {
523552
/// Returns if tracing should be enabled. If tracing is disabled, starting transactions returns
524553
/// [NoOpSentrySpan].
525554
bool isTracingEnabled() {
555+
// ignore: deprecated_member_use_from_same_package
526556
final enable = enableTracing;
527557
if (enable != null) {
528558
return enable;

dart/lib/src/sentry_stack_trace_factory.dart

+2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class SentryStackTraceFactory {
103103
// least we get an indication something's wrong and are able to fix it.
104104
}
105105

106+
final platform = _options.platformChecker.isWeb ? 'javascript' : 'dart';
106107
final fileName =
107108
frame.uri.pathSegments.isNotEmpty ? frame.uri.pathSegments.last : null;
108109
final abs = '$eventOrigin${_absolutePathForCrashReport(frame)}';
@@ -114,6 +115,7 @@ class SentryStackTraceFactory {
114115
inApp: _isInApp(frame),
115116
fileName: fileName,
116117
package: frame.package,
118+
platform: platform,
117119
);
118120

119121
final line = frame.line;

dart/lib/src/sentry_traces_sampler.dart

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class SentryTracesSampler {
5959

6060
double? optionsRate = _options.tracesSampleRate;
6161
double? defaultRate =
62+
// ignore: deprecated_member_use_from_same_package
6263
_options.enableTracing == true ? _defaultSampleRate : null;
6364
double? optionsOrDefaultRate = optionsRate ?? defaultRate;
6465

dart/lib/src/version.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
library version;
1010

1111
/// The SDK version reported to Sentry.io in the submitted events.
12-
const String sdkVersion = '8.4.0';
12+
const String sdkVersion = '8.5.0';
1313

1414
String sdkName(bool isWeb) => isWeb ? _browserSdkName : _ioSdkName;
1515

0 commit comments

Comments
 (0)