Skip to content

Commit

Permalink
feat: Change output display format
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmah309 committed Nov 25, 2024
1 parent 6d7855f commit 97d8f87
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 92 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ Result<String> makePizza() {
```
#### Output
```text
Error: Could not order for Bob.
Could not order for Bob.
Caused by:
Caused By:
0: Order was number 1.
1: Pizza was missing a topping..
Expand Down Expand Up @@ -117,7 +117,7 @@ Now with `anyhow`, we are able to better understand and handle errors in an idio

```text
Error.hasStackTrace;
Error.displayFormat;
Error.displayOrder;
Error.stackTraceDisplayFormat;
Error.stackTraceDisplayModifier;
```
Expand All @@ -127,17 +127,17 @@ Which is usually done at startup.
* `hasStackTrace`: With `Error.hasStackTrace = false`, we can exclude capturing a stack trace:

```text
Error: Could not order for Bob.
Could not order for Bob.
Caused by:
Caused By:
0: Order was number 1.
1: Pizza was missing a topping.
```

* `displayFormat`: We can view the root cause first with `Error.displayFormat = ErrorDisplayFormat.rootCauseFirst`
* `displayFormat`: We can view the root cause first with `Error.displayOrder = ErrorDisplayOrder.rootFirst`

```text
Root Cause: Pizza was missing a topping.
Pizza was missing a topping.
Additional Context:
0: Order was number 1.
Expand Down
2 changes: 1 addition & 1 deletion example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Result<String> makeHamburger() {
//Output:
// Error: Could not order for user: Bob.
//
// Caused by:
// Caused By:
// 0: Order number 1 failed.
// 1: Hmm something went wrong making the hamburger.
//
Expand Down
2 changes: 1 addition & 1 deletion example/working_with_anyhow_errors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void main() {
}
}
// Output:
// Error: This is a single error
// This is a single error
//
// chain 0: This is also more context for the error
// chain 1: This is context for the error
Expand Down
83 changes: 44 additions & 39 deletions lib/src/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,20 @@ class Error implements Exception {
static bool hasStackTrace = true;

/// Setting for how errors are converted to strings
static ErrorDisplayFormat displayFormat = ErrorDisplayFormat.rootCauseLast;
static ErrorDisplayOrder displayOrder = ErrorDisplayOrder.rootLast;

/// How to display [StackTrace]s. Requires [hasStackTrace] = true
static StackTraceDisplayFormat stackTraceDisplayFormat =
StackTraceDisplayFormat.one;
static StackTraceDisplayFormat stackTraceDisplayFormat = StackTraceDisplayFormat.one;

/// Modifies the stacktrace during display. Useful for adjusting number of frames to include during
/// display/logging. Stacktraces that are captured internally through [bail], [anyhow],
/// [AnyhowResultExtension.context], etc.
/// or directly by calling [Error.new], are always captured as soon as possible - one stack frame
/// display/logging. Stacktraces that are captured internally through [bail], [anyhow],
/// [AnyhowResultExtension.context], etc.
/// or directly by calling [Error.new], are always captured as soon as possible - one stack frame
/// below the calling code. Therefore, if pruning during display is desired,
/// one can comfortably prune 1 off the root and then leave as many other frames as you desire.
/// Note passing the optional stackTrace param for functions like [bail] obviously will not hold
/// this guarantee.
///
///
/// See also the [stack_trace](https://pub.dev/packages/stack_trace) package.
/// Requires [hasStackTrace] = true
static StackTrace Function(StackTrace) stackTraceDisplayModifier = (s) => s;
Expand All @@ -39,8 +38,7 @@ class Error implements Exception {
}

/// Constructor used internally when it is known a [StackTrace] is needed, so it is eagerly created.
Error._withStackTrace(this._inner, this._stackTrace, {Error? parent})
: _parent = parent;
Error._withStackTrace(this._inner, this._stackTrace, {Error? parent}) : _parent = parent;

/// Returns true if [E] is the type held by this error object.
bool isType<E extends Object>() {
Expand Down Expand Up @@ -90,26 +88,24 @@ class Error implements Exception {
@override
String toString() {
final StringBuffer stringBuf = StringBuffer();
switch (displayFormat) {
case ErrorDisplayFormat.rootCauseLast:
switch (displayOrder) {
case ErrorDisplayOrder.rootLast:
final list = chain();
_writeErrorAndContext(stringBuf, "Error", "Caused by", list.iterator);
_writeErrorAndContext(stringBuf, "Caused By", list.iterator);
_writeStackTraces(stringBuf, list.iterator);
break;
case ErrorDisplayFormat.rootCauseFirst:
case ErrorDisplayOrder.rootFirst:
final list = chain().toList(growable: false).reversed;
_writeErrorAndContext(
stringBuf, "Root Cause", "Additional Context", list.iterator);
_writeErrorAndContext(stringBuf, "Additional Context", list.iterator);
_writeStackTraces(stringBuf, list.iterator);
break;
}
return stringBuf.toString();
}

void _writeErrorAndContext(StringBuffer stringBuf, String firstTitle,
String restTitle, Iterator<Error> iter) {
void _writeErrorAndContext(StringBuffer stringBuf, String restTitle, Iterator<Error> iter) {
iter.moveNext();
stringBuf.write("$firstTitle: ${iter.current._inner}\n");
stringBuf.write("${iter.current._inner}\n");
if (iter.moveNext()) {
stringBuf.write("\n$restTitle:\n");
stringBuf.write("\t0: ${iter.current._inner}\n");
Expand All @@ -127,30 +123,34 @@ class Error implements Exception {
case StackTraceDisplayFormat.none:
break;
case StackTraceDisplayFormat.one:
stringBuf.write("\n");
if (iter.moveNext()) {
stringBuf.write(
"StackTrace:\n${stackTraceDisplayModifier(iter.current._stackTrace!)}\n");
stringBuf.write("\nStackTrace:\n");
stringBuf.write(stackTraceDisplayModifier(iter.current._stackTrace!));
stringBuf.write("\n");
}
break;
case StackTraceDisplayFormat.full:
stringBuf.write("\n");
if (iter.moveNext()) {
stringBuf.write(
"Main StackTrace:\n${stackTraceDisplayModifier(iter.current._stackTrace!)}\n");
stringBuf.write("\nStackTrace:\n");
stringBuf.write(stackTraceDisplayModifier(iter.current._stackTrace!));
stringBuf.write("\n");
}
if (iter.moveNext()) {
stringBuf.write("\nAdditional StackTraces:\n");
stringBuf.write(
"\t0: ${stackTraceDisplayModifier(iter.current._stackTrace!)}\n");
stringBuf.write("\n");
switch (displayOrder) {
case ErrorDisplayOrder.rootLast:
stringBuf.write("\nCaused By StackTraces:\n");
case ErrorDisplayOrder.rootFirst:
stringBuf.write("\nAdditional Context StackTraces:\n");
}
stringBuf.write("\t0: ${stackTraceDisplayModifier(iter.current._stackTrace!)}\n");
int index = 1;
while (iter.moveNext()) {
stringBuf.write(
"\t${index}: ${stackTraceDisplayModifier(iter.current._stackTrace!)}\n");
stringBuf
.write("\t${index}: ${stackTraceDisplayModifier(iter.current._stackTrace!)}\n");
index++;
}
break;
}
// case StackTraceDisplayFormat.firstAndLast:
}
}
}
Expand All @@ -164,34 +164,39 @@ class Error implements Exception {
}

/// Controls the base [toString] format
enum ErrorDisplayFormat {
enum ErrorDisplayOrder {
/// Traditional anyhow display. The most recent context to the root cause. E.g.:
/// Error: Bob ordered.
///
/// Caused by:
/// Bob ordered.
///
/// Caused By:
/// 0: Order was pizza.
/// 1: Pizza was missing a topping.
rootCauseLast,
rootLast,

/// Root cause to additional context added above. E.g.:
/// Root Cause: Pizza was missing a topping.
///
/// Pizza was missing a topping.
///
/// Additional Context:
/// 0: Order was pizza.
/// 1: Bob ordered.
rootCauseFirst
rootFirst
}

/// How StackTrace should be displayed to the user.
enum StackTraceDisplayFormat {
/// Every linked [Error]'s stackTrace will be included. Warning can get verbose.
/// Every linked [Error]'s stackTrace will be included. Note - this can get verbose.
full,

/// Only first [StackTrace] will be included.
one,

/// No stackTraces should be printed.
/// No [StackTrace]s should be included.
none,

/// Only the first and last [StackTrace]s should be included.
// firstAndLast,
}

extension FutureAnyhowError on Future<Error> {
Expand Down
Loading

0 comments on commit 97d8f87

Please sign in to comment.