removed herror

This commit is contained in:
Erik Winter 2021-03-29 08:31:05 +02:00
parent b313767026
commit 4326fb11d6
5 changed files with 0 additions and 621 deletions

View File

@ -1,29 +0,0 @@
package herror_test
import (
"fmt"
"git.sr.ht/~ewintr/go-kit/herror"
)
var ErrTaskFailed = herror.New("task has failed")
func step() error {
return fmt.Errorf("cannot move")
}
func performTask() error {
if err := step(); err != nil {
return ErrTaskFailed.Wrap(err)
}
return nil
}
func Example() {
if err := performTask(); err != nil {
fmt.Print(err)
return
}
// Output: task has failed
//-> cannot move
}

View File

@ -1,161 +0,0 @@
package herror
import (
"bytes"
"encoding/json"
"fmt"
"github.com/davecgh/go-spew/spew"
"golang.org/x/xerrors"
)
// Err represents an error
type Err struct {
error string
wrapped *Err
details string
stack *Stacktrace
}
type errJSON struct {
E string `json:"error"`
W *Err `json:"wrapped"`
D string `json:"details"`
S *Stacktrace `json:"stack"`
}
// New returns a new instance for Err type with assigned error
func New(err interface{}) *Err {
newerror := new(Err)
switch e := err.(type) {
case string:
newerror.error = e
case error:
if castErr, ok := e.(*Err); ok {
return castErr
}
newerror.error = e.Error()
}
return newerror
}
// Wrap set an error that is wrapped by Err
func Wrap(err, errwrapped error) error {
newerr := New(err)
return newerr.Wrap(errwrapped)
}
// Unwrap returns a wrapped error if present
func Unwrap(err error) error {
return xerrors.Unwrap(err)
}
// Is reports whether any error in err's chain matches target.
func Is(err, target error) bool {
return xerrors.Is(err, target)
}
// Wrap set an error that is wrapped by Err
func (e *Err) Wrap(err error) *Err {
wrapped := New(err)
if deeper := xerrors.Unwrap(err); deeper != nil {
Wrap(wrapped, deeper)
}
newerr := &Err{
error: e.error,
wrapped: e.wrapped,
details: e.details,
stack: e.stack,
}
newerr.wrapped = wrapped
return newerr
}
// Unwrap returns wrapped error
func (e *Err) Unwrap() error {
if e.wrapped == nil {
return nil
}
return e.wrapped
}
// Is reports whether an error matches.
func (e *Err) Is(err error) bool {
if e.wrapped != nil {
return e.error == err.Error() || e.wrapped.Is(err)
}
return e.error == err.Error()
}
// CaptureStack sets stack traces when the method is called
func (e *Err) CaptureStack() *Err {
e.stack = NewStacktrace()
return e
}
// Stack returns full stack traces
func (e *Err) Stack() *Stacktrace {
return e.stack
}
// AddDetails is a alias for AppendDetail [DEPRECATED]
func (e *Err) AddDetails(v ...interface{}) *Err {
return e.AppendDetails(v...)
}
// AppendDetails appends formated variable information at the end of a text
// field in the error mostly for debugging purposes.
func (e *Err) AppendDetails(v ...interface{}) *Err {
buff := new(bytes.Buffer)
fmt.Fprintln(buff, e.details)
spew.Fdump(buff, v...)
e.details = buff.String()
return e
}
// Details returns error's details
func (e *Err) Details() string {
return e.details
}
// Errors return a composed message of the assigned error e wrapped error
func (e *Err) Error() string {
if e.wrapped == nil {
return e.error
}
return fmt.Sprintf("%s\n-> %s", e.error, e.wrapped.Error())
}
// UnmarshalJSON
func (e *Err) UnmarshalJSON(b []byte) error {
var errJSON errJSON
if err := json.Unmarshal(b, &errJSON); err != nil {
return err
}
*e = Err{
error: errJSON.E,
wrapped: errJSON.W,
details: errJSON.D,
stack: errJSON.S,
}
return nil
}
// MarshalJSON
func (e *Err) MarshalJSON() ([]byte, error) {
return json.Marshal(errJSON{
E: e.error,
W: e.wrapped,
D: e.details,
S: e.stack,
})
}

View File

@ -1,150 +0,0 @@
package herror_test
import (
"encoding/json"
"fmt"
"testing"
"git.sr.ht/~ewintr/go-kit/herror"
"git.sr.ht/~ewintr/go-kit/test"
)
func TestHError(t *testing.T) {
t.Run("new error", func(t *testing.T) {
errDefault := "this is an error"
for _, tc := range []struct {
m string
input interface{}
expected string
}{
{
m: "empty",
},
{
m: "string",
input: errDefault,
expected: errDefault,
},
{
m: "error",
input: fmt.Errorf(errDefault),
expected: errDefault,
},
{
m: "herror.Err",
input: herror.New(errDefault),
expected: errDefault,
},
{
m: "invalid type",
input: 123456789,
expected: "",
},
} {
t.Run(tc.m, func(t *testing.T) {
test.Equals(t, tc.expected, herror.New(tc.input).Error())
})
}
})
t.Run("wrap", func(t *testing.T) {
errmain := herror.New("MAIN ERROR")
errfmt := fmt.Errorf("ERROR FORMATTED")
errA := herror.New("ERR A")
errB := herror.New("ERR B")
errC := herror.New("ERR C")
errD := herror.New("ERR D")
errNested := errmain.Wrap(
errA.Wrap(
errB.Wrap(
errC.Wrap(errD),
),
),
)
for _, tc := range []struct {
m string
err error
expected []error
}{
{
m: "error",
err: errfmt,
expected: []error{
errfmt,
},
},
{
m: "deeper nested wrap",
err: errNested,
expected: []error{
errA, errB, errC, errD,
},
},
} {
t.Run(tc.m, func(t *testing.T) {
newerr := errmain.Wrap(tc.err)
for _, e := range tc.expected {
test.Equals(t, true, newerr.Is(e))
}
})
}
})
t.Run("json marshalling", func(t *testing.T) {
hError := herror.New("this is an error").
Wrap(fmt.Errorf("this is another error")).
CaptureStack()
marshalled, err := json.Marshal(hError)
test.OK(t, err)
var unmarshalled *herror.Err
test.OK(t, json.Unmarshal(marshalled, &unmarshalled))
test.Equals(t, hError, unmarshalled)
})
}
func ExampleErr_Wrap() {
errA := herror.New("something went wrong")
errB := fmt.Errorf("because of this error")
newerr := herror.Wrap(errA, errB)
fmt.Print(herror.Unwrap(newerr), "\n", newerr)
// Output: because of this error
// something went wrong
// -> because of this error
}
func ExampleErr_Is() {
errA := herror.New("something went wrong")
errB := func() error {
return errA
}()
fmt.Print(herror.Is(errA, errB))
// Output: true
}
func ExampleErr_CaptureStack() {
err := herror.New("something went wrong")
err.CaptureStack()
fmt.Print(err, "\n", err.Stack().Frames[2].Function)
// Output: something went wrong
// ExampleErr_CaptureStack
}
func ExampleErr_AddDetails() {
err := herror.New("something went wrong")
err.AddDetails(struct {
number int
}{123})
fmt.Print(err, err.Details())
// Output: something went wrong
// (struct { number int }) {
// number: (int) 123
// }
}

View File

@ -1,151 +0,0 @@
package herror
import (
"fmt"
"go/build"
"path/filepath"
"runtime"
"strings"
)
// Stacktrace holds information about the frames of the stack.
type Stacktrace struct {
Frames []Frame `json:"frames,omitempty"`
}
// Frame represents parsed information from runtime.Frame
type Frame struct {
Function string `json:"function,omitempty"`
Type string `json:"type,omitempty"`
Package string `json:"package,omitempty"`
Filename string `json:"filename,omitempty"`
AbsPath string `json:"abs_path,omitempty"`
Line int `json:"line,omitempty"`
InApp bool `json:"in_app,omitempty"`
}
// FrameFilter represents function to filter frames
type FrameFilter func(Frame) bool
const unknown string = "unknown"
// NewStacktrace creates a stacktrace using `runtime.Callers`.
func NewStacktrace(filters ...FrameFilter) *Stacktrace {
pcs := make([]uintptr, 100)
n := runtime.Callers(1, pcs)
if n == 0 {
return nil
}
frames := extractFrames(pcs[:n])
// default filter
frames = filterFrames(frames, func(f Frame) bool {
return f.Package == "runtime" || f.Package == "testing" ||
strings.HasSuffix(f.Package, "/herror")
})
for _, filter := range filters {
frames = filterFrames(frames, filter)
}
stacktrace := Stacktrace{
Frames: frames,
}
return &stacktrace
}
// NewFrame assembles a stacktrace frame out of `runtime.Frame`.
func NewFrame(f runtime.Frame) Frame {
abspath := unknown
filename := unknown
if f.File != "" {
abspath = f.File
_, filename = filepath.Split(f.File)
}
function := unknown
pkgname := unknown
typer := ""
if f.Function != "" {
pkgname, typer, function = deconstructFunctionName(f.Function)
}
inApp := func() bool {
out := strings.HasPrefix(abspath, build.Default.GOROOT) ||
strings.Contains(pkgname, "vendor")
return !out
}()
return Frame{
AbsPath: abspath,
Filename: filename,
Line: f.Line,
Package: pkgname,
Type: typer,
Function: function,
InApp: inApp,
}
}
func filterFrames(frames []Frame, filter FrameFilter) []Frame {
filtered := make([]Frame, 0, len(frames))
for _, frame := range frames {
if filter(frame) {
continue
}
filtered = append(filtered, frame)
}
return filtered
}
func extractFrames(pcs []uintptr) []Frame {
frames := make([]Frame, 0, len(pcs))
callersFrames := runtime.CallersFrames(pcs)
for {
callerFrame, more := callersFrames.Next()
frames = append([]Frame{
NewFrame(callerFrame),
}, frames...)
if !more {
break
}
}
return frames
}
func deconstructFunctionName(name string) (pkg string, typer string, function string) {
if i := strings.LastIndex(name, "/"); i != -1 {
pkg = name[:i]
function = name[i+1:]
if d := strings.Index(function, "."); d != -1 {
pkg = fmt.Sprint(pkg, "/", function[:d])
function = function[d+1:]
}
if o, c := strings.LastIndex(name, ".("), strings.LastIndex(name, ")."); o != -1 && c != -1 {
pkg = name[:o]
function = name[c+2:]
typer = name[o+2 : c]
if i := strings.Index(typer, "*"); i != -1 {
typer = typer[1:]
}
}
return
}
if i := strings.LastIndex(name, "."); i != -1 {
pkg = name[:i]
function = name[i+1:]
}
return
}

View File

@ -1,130 +0,0 @@
package herror_test
import (
"runtime"
"testing"
"git.sr.ht/~ewintr/go-kit/herror"
"git.sr.ht/~ewintr/go-kit/test"
)
func trace() *herror.Stacktrace {
return herror.NewStacktrace()
}
func traceStepIn(f []herror.FrameFilter) *herror.Stacktrace {
return traceWithFilter(f)
}
func traceWithFilter(f []herror.FrameFilter) *herror.Stacktrace {
return herror.NewStacktrace(f...)
}
func TestStacktrace(t *testing.T) {
t.Run("new", func(t *testing.T) {
stack := trace()
expectedFrames := []herror.Frame{
herror.Frame{
Function: "TestStacktrace.func1",
},
herror.Frame{
Function: "trace",
},
}
test.Equals(t, len(expectedFrames), len(stack.Frames))
for i, frame := range expectedFrames {
test.Equals(t, frame.Function, stack.Frames[i].Function)
test.Equals(t, "git.sr.ht/~ewintr/go-kit/herror_test", stack.Frames[i].Package)
test.Equals(t, "stacktrace_test.go", stack.Frames[i].Filename)
}
})
t.Run("filter frames", func(t *testing.T) {
for _, tc := range []struct {
m string
filters []herror.FrameFilter
expected []herror.Frame
}{
{
m: "no filter",
expected: []herror.Frame{
herror.Frame{
Function: "TestStacktrace.func2",
},
herror.Frame{
Function: "traceStepIn",
},
herror.Frame{
Function: "traceWithFilter",
},
},
},
{
m: "single filter",
expected: []herror.Frame{
herror.Frame{
Function: "traceStepIn",
},
herror.Frame{
Function: "traceWithFilter",
},
},
filters: []herror.FrameFilter{
func(f herror.Frame) bool {
return f.Function == "TestStacktrace.func2"
},
},
},
{
m: "multiple filters",
expected: []herror.Frame{
herror.Frame{
Function: "traceWithFilter",
},
},
filters: []herror.FrameFilter{
func(f herror.Frame) bool {
return f.Function == "TestStacktrace.func2"
},
func(f herror.Frame) bool {
return f.Function == "traceStepIn"
},
},
},
} {
stack := traceStepIn(tc.filters)
t.Run(tc.m, func(t *testing.T) {
test.Equals(t, len(tc.expected), len(stack.Frames))
for i, frame := range tc.expected {
test.Equals(t, frame.Function, stack.Frames[i].Function)
test.Equals(t, "git.sr.ht/~ewintr/go-kit/herror_test", stack.Frames[i].Package)
test.Equals(t, "stacktrace_test.go", stack.Frames[i].Filename)
}
})
}
})
}
func TestFrame(t *testing.T) {
t.Run("new", func(t *testing.T) {
f := func() herror.Frame {
pc := make([]uintptr, 1)
n := runtime.Callers(0, pc)
test.Assert(t, n == 1, "expected available pcs")
frames := runtime.CallersFrames(pc)
runtimeframe, _ := frames.Next()
return herror.NewFrame(runtimeframe)
}
frame := f()
test.Equals(t, "Callers", frame.Function)
test.Equals(t, "runtime", frame.Package)
test.Equals(t, "extern.go", frame.Filename)
})
}