Skip to content

Commit

Permalink
implement some sort of simple exception chaining.
Browse files Browse the repository at this point in the history
  • Loading branch information
hpoul committed Feb 18, 2024
1 parent bbb1e35 commit 421d4e1
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.3.0-dev.1

* Support for exception chaining.

## 1.2.0+1

* Graylog: Send timestamp with decimal places.
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ packages:
path: ".."
relative: true
source: path
version: "1.2.0+1"
version: "1.3.0-dev.1"
meta:
dependency: transitive
description:
Expand Down
35 changes: 35 additions & 0 deletions lib/src/exception_chain.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// based on https://github.com/dart-lang/language/issues/2119#issuecomment-1042365842

final Expando<ErrorStack> _causedBy = Expando();
T _wasCausedBy<T extends Exception>(
T target, Object cause, StackTrace causeStackTrace) {
_causedBy[target] = (error: cause, stack: causeStackTrace);
return target;
}

typedef ErrorStack = ({Object error, StackTrace stack});

/// Allow exception chaining.
/// example:
/// ```
/// try {
/// ...
/// } on Exception (e, stackTrace) {
/// throw
/// }
extension CausedByException<E extends Exception> on E {
E causedBy(Object chainedException, StackTrace stackTrace) =>
_wasCausedBy(this, chainedException, stackTrace);
ErrorStack? getCausedByException() => _causedBy[this];

String toStringWithCause() {
final cause = this.getCausedByException();
if (cause == null) {
return toString();
}
final error = cause.error;
final causeToString =
error is Exception ? error.toStringWithCause() : error.toString();
return '${toString()} cause: {$causeToString}';
}
}
32 changes: 21 additions & 11 deletions lib/src/logrecord_formatter.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:logging/logging.dart';
import 'package:logging_appenders/src/exception_chain.dart';
import 'internal/ansi.dart' as ansi;

/// Base class for formatters which are responsible for converting
Expand Down Expand Up @@ -39,18 +40,27 @@ class DefaultLogRecordFormatter extends LogRecordFormatter {
sb.write('${rec.time} ${rec.level.name} '
'${rec.loggerName} - ${rec.message}');

if (rec.error != null) {
sb.writeln();
sb.write('### ${rec.error?.runtimeType}: ');
sb.write(rec.error);
}
// ignore: avoid_as
final stackTrace = rec.stackTrace ??
(rec.error is Error ? (rec.error as Error).stackTrace : null);
if (stackTrace != null) {
sb.writeln();
sb.write(stackTrace);
void formatErrorAndStackTrace(final Object? error, StackTrace? stackTrace) {
if (error != null) {
sb.writeln();
sb.write('### ${error.runtimeType}: ');
sb.write(error);
}
// ignore: avoid_as
final stack = stackTrace ?? (error is Error ? (error).stackTrace : null);
if (stack != null) {
sb.writeln();
sb.write(stack);
}
final causedBy = error is Exception ? error.getCausedByException() : null;
if (causedBy != null) {
sb.write('### Caused by: ');
formatErrorAndStackTrace(causedBy.error, causedBy.stack);
}
}

formatErrorAndStackTrace(rec.error, rec.stackTrace);

return sb;
}
}
Expand Down
9 changes: 8 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: logging_appenders
description: Logging appenders for the dart logging package for print, file and remote (logz, loki, graylog (gelf)).
version: 1.2.0+1
version: 1.3.0-dev.1
homepage: https://github.com/hpoul/dart_logging_appenders/
screenshots:
- description: Colored console output
Expand All @@ -18,8 +18,15 @@ dependencies:

dev_dependencies:
test: ^1.25.2
matcher: ^0.12.16+1
lints: ^3.0.0
mockito: ^5.4.4
fake_async: ^1.3.1
path: ^1.8.3
build_runner: ^2.4.8

topics:
- logging
- logger
- error
- console
26 changes: 26 additions & 0 deletions test/exception_chain.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:logging_appenders/logging_appenders.dart';
import 'package:logging_appenders/src/exception_chain.dart';
import 'package:test/expect.dart';
import 'package:test/scaffolding.dart';

import 'package:logging/logging.dart';

final _logger = Logger('exception_chain');

void main() {
PrintAppender.setupLogging();
test('Simple chained exception', () {
try {
try {
int.parse('a');
} catch (e, stackTrace) {
throw Exception('unable to parse').causedBy(e, stackTrace);
}
fail('unreachable');
} on Exception catch (e, stackTrace) {
expect(e.getCausedByException(), isNotNull);
expect(e.getCausedByException()?.error, isFormatException);
_logger.finer('catched exception.', e, stackTrace);
}
});
}

0 comments on commit 421d4e1

Please sign in to comment.