Skip to content

Commit

Permalink
Merge pull request #8 from Bibob7/wrap-error-message
Browse files Browse the repository at this point in the history
Wrap error messages by default and remove Kind
  • Loading branch information
Bibob7 authored Nov 5, 2022
2 parents 17f13c0 + c95fa17 commit 8dc3d8e
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 192 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@ As arguments, you can pass in any order the following types:

Apart from that, when a new error is created, the call position is remembered so that this information can
be used later in the call stack.
If you pass an error to this function, this error will be wrapped by the new error.

Here is an example:
## Examples:

### Wrapping errors

You can simply wrap errors by passing the previous error to sterrors.E() as parameter.

In the stacktrace every wrapped error is an entry in the trace with its error message.
However, if you call Error() on the last error in the trace, it will return all error message in the form

{message}: {previous message1}: {previous message1}: ...

```go
package main
Expand All @@ -38,7 +48,12 @@ func main() {
second := sterrors.E("action not possible", sterrors.SeverityError, err)

jsonStackTrace, _ := json.Marshal(sterrors.CallStack(second))
fmt.Printf("%s", jsonStackTrace)
// Print out the error stack trace
fmt.Printf("%s \n", jsonStackTrace)
// Calling Error() return the wrapped error message
fmt.Printf("Simply print the wrapped error message: %s \n", second.Error())
// The provided error type also implements the Unwrap() error method so that you can use it with errors.Is()
fmt.Printf("Is initial error: %v \n", errors.Is(second, InitialError))
}

func anotherMethod() error {
Expand Down Expand Up @@ -68,6 +83,9 @@ Output:
}
}
]

Simply print the wrapped error message: action not possible: some error message
Is initial error: true
```

Inspired by a talk from GopherCon 2019: https://www.youtube.com/watch?v=4WIhhzTTd0Y
50 changes: 23 additions & 27 deletions error.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
package sterrors

import "fmt"

type Error interface {
error
Cause() error
Message() string
Unwrap() error
Severity() Severity
Kind() Kind
Caller() *Caller
Enrich(args ...interface{})
setCaller(caller *Caller)
}

type BaseError struct {
message string
kind Kind
caller *Caller
severity Severity
cause error
}

func (e *BaseError) Message() string {
return e.message
}

func (e *BaseError) Error() string {
if e.message != "" {
return e.message
if e.cause != nil {
return fmt.Sprintf("%s: %s", e.Message(), e.cause.Error())
}
return string(e.Kind())
return e.Message()
}

func (e *BaseError) Cause() error {
func (e *BaseError) Unwrap() error {
return e.cause
}

func (e *BaseError) Severity() Severity {
return e.severity
}

func (e *BaseError) Kind() Kind {
if e.kind == "" {
return KindUnexpected
}
return e.kind
}

func (e *BaseError) Caller() *Caller {
return e.caller
}
Expand All @@ -49,22 +47,22 @@ Enrich can be overridden or extended by a custom error type
For example:
type CustomErrorType struct {
BaseError
CustomAttribute
}
type CustomErrorType struct {
BaseError
CustomAttribute
}
type CustomAttribute int
func (e *CustomErrorType) Enrich(args ...interface{}) {
for _, arg := range args {
switch arg := arg.(type) {
case CustomAttribute:
e.CustomAttribute = arg
func (e *CustomErrorType) Enrich(args ...interface{}) {
for _, arg := range args {
switch arg := arg.(type) {
case CustomAttribute:
e.CustomAttribute = arg
}
}
e.BaseError.Enrich(args...)
}
e.BaseError.Enrich(args...)
}
*/
func (e *BaseError) Enrich(args ...interface{}) {
for _, arg := range args {
Expand All @@ -73,8 +71,6 @@ func (e *BaseError) Enrich(args ...interface{}) {
e.cause = arg
case Severity:
e.severity = arg
case Kind:
e.kind = arg
case string:
e.message = arg
default:
Expand Down
18 changes: 16 additions & 2 deletions error_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sterrors

import (
"errors"
"fmt"
"testing"
)
Expand Down Expand Up @@ -28,20 +29,33 @@ func TestBaseError_Error(t *testing.T) {
testCases := map[string]struct {
Message string
ExpectedErrorMessage string
Cause error
}{
"Custom error message": {
Message: "custom error message",
ExpectedErrorMessage: "custom error message",
},
"No custom error message": {
ExpectedErrorMessage: "unexpected",
ExpectedErrorMessage: "",
},
"With wrapped error": {
Message: "some message",
ExpectedErrorMessage: "some message: previous error",
Cause: errors.New("previous error"),
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
err := E(tc.Message)
if tc.Cause != nil {
err = E(tc.Message, tc.Cause)
}
if tc.ExpectedErrorMessage != err.Error() {
t.Errorf("expected error message is not actual error message")
t.Errorf("expected message \"%s\" is not actual message \"%s\"", tc.ExpectedErrorMessage, err.Error())
}
stError, _ := err.(Error)
if tc.Message != "" && tc.Message != stError.Message() {
t.Errorf("expected message \"%s\" is not actual message \"%s\"", tc.Message, stError.Message())
}
})
}
Expand Down
38 changes: 36 additions & 2 deletions examples/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,54 @@ package main

import (
"encoding/json"
"errors"
"fmt"
"github.com/Bibob7/sterrors"
)

var InitialError = errors.New("initial error")

func main() {
err := secondMethod()

// second error that results from the first one
second := sterrors.E("action not possible", sterrors.SeverityError, err)

jsonStackTrace, _ := json.Marshal(sterrors.CallStack(second))
fmt.Printf("%s", jsonStackTrace)
// Print out the error stack trace
fmt.Printf("%s \n", jsonStackTrace)
// Calling Error() return the wrapped error message
fmt.Printf("Simply print the wrapped error message: %s \n", second.Error())
// The provided error type also implements the Unwrap() error method so that you can use it with errors.Is()
fmt.Printf("Is initial error: %v \n", errors.Is(second, InitialError))
}

func secondMethod() error {
return sterrors.E("some error message", sterrors.SeverityWarning)
return sterrors.E("some error message", InitialError, sterrors.SeverityWarning)
}

/*
Output:
[
{
"msg": "action not possible",
"caller": {
"funcName": "main.main",
"file": "/Users/root/Repositories/sterrors/examples/main.go",
"line": 13
}
},
{
"msg": "some error message",
"caller": {
"funcName": "main.anotherMethod",
"file": "/Users/root/Repositories/sterrors/examples/main.go",
"line": 20
}
}
]
Simply print the wrapped error message: action not possible: some error message
Is initial error: true
*/
44 changes: 0 additions & 44 deletions kind.go

This file was deleted.

Loading

0 comments on commit 8dc3d8e

Please sign in to comment.