Skip to content

Commit

Permalink
✨ Introduce DioExceptionReadableStringBuilder (#2297)
Browse files Browse the repository at this point in the history
Resolves #1949
Resolves #2287

Developers may want the URL of the exception to know what endpoint has
gone wrong, or they want to have fewer tips about what the status code
means. If we open too many flags to support various logging content, it
will be a mess eventually.
Introducing the `DioExceptionReadableStringBuilder` easily builds text
content from the `DioException`.

---------

Signed-off-by: Alex Li <[email protected]>
  • Loading branch information
AlexV525 authored Jan 28, 2025
1 parent 518aa6f commit 0b0f527
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 6 deletions.
1 change: 1 addition & 0 deletions dio/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ See the [Migration Guide][] for the complete breaking changes list.**
- Fixes boundary inconsistency in `FormData.clone()`.
- Support `FileAccessMode` in `Dio.download` and `Dio.downloadUri` to change download file opening mode
- Fix `ListParam` equality by using the `DeepCollectionEquality`.
- Enables configuring the logging details of `DioException` globally and locally.

## 5.7.0

Expand Down
35 changes: 31 additions & 4 deletions dio/lib/src/dio_exception.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'options.dart';
import 'response.dart';
import 'utils.dart' show warningLog;

/// Deprecated in favor of [DioExceptionType] and will be removed in future major versions.
@Deprecated('Use DioExceptionType instead. This will be removed in 6.0.0')
Expand Down Expand Up @@ -205,6 +206,14 @@ class DioException implements Exception {
/// The error message that throws a [DioException].
final String? message;

/// Users can customize the content of [toString] when thrown.
static DioExceptionReadableStringBuilder readableStringBuilder =
defaultDioExceptionReadableStringBuilder;

/// Each exception can be override with a customized builder or fallback to
/// the default [DioException.readableStringBuilder].
DioExceptionReadableStringBuilder? stringBuilder;

/// Generate a new [DioException] by combining given values and original values.
DioException copyWith({
RequestOptions? requestOptions,
Expand All @@ -226,11 +235,12 @@ class DioException implements Exception {

@override
String toString() {
String msg = 'DioException [${type.toPrettyDescription()}]: $message';
if (error != null) {
msg += '\nError: $error';
try {
return stringBuilder?.call(this) ?? readableStringBuilder(this);
} catch (e, s) {
warningLog(e, s);
return defaultDioExceptionReadableStringBuilder(this);
}
return msg;
}

/// Because of [ValidateStatus] we need to consider all status codes when
Expand Down Expand Up @@ -278,3 +288,20 @@ class DioException implements Exception {
return buffer.toString();
}
}

/// The readable string builder's signature of
/// [DioException.readableStringBuilder].
typedef DioExceptionReadableStringBuilder = String Function(DioException e);

/// The default implementation of building a readable string of [DioException].
String defaultDioExceptionReadableStringBuilder(DioException e) {
final buffer = StringBuffer(
'DioException [${e.type.toPrettyDescription()}]: '
'${e.message}',
);
if (e.error != null) {
buffer.writeln();
buffer.write('Error: ${e.error}');
}
return buffer.toString();
}
4 changes: 2 additions & 2 deletions dio/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ Map<String, V> caseInsensitiveKeyMap<V>([Map<String, V>? value]) {
}

// TODO(Alex): Provide a configurable property on the Dio class once https://github.com/cfug/dio/discussions/1982 has made some progress.
void warningLog(String message, StackTrace stackTrace) {
void warningLog(Object message, StackTrace stackTrace) {
if (!kReleaseMode) {
dev.log(
message,
message.toString(),
level: 900,
name: '🔔 Dio',
stackTrace: stackTrace,
Expand Down
30 changes: 30 additions & 0 deletions dio/test/exception_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,34 @@ void main() {
},
testOn: '!browser',
);

test('DioExceptionReadableStringBuilder', () {
final requestOptions = RequestOptions(path: 'just/a/test', method: 'POST');
final exception = DioException(
requestOptions: requestOptions,
response: Response(requestOptions: requestOptions),
error: 'test',
message: 'test message',
stackTrace: StackTrace.current,
);
DioException.readableStringBuilder = (e) => 'Hey, Dio throws an exception: '
'${e.requestOptions.path}, '
'${e.requestOptions.method}, '
'${e.type}, '
'${e.error}, '
'${e.stackTrace}, '
'${e.message}';
expect(
exception.toString(),
'Hey, Dio throws an exception: '
'just/a/test, '
'POST, '
'DioExceptionType.unknown, '
'test, '
'${exception.stackTrace}, '
'test message',
);
exception.stringBuilder = (e) => 'Locally override: ${e.message}';
expect(exception.toString(), 'Locally override: test message');
});
}

0 comments on commit 0b0f527

Please sign in to comment.