https://github.com/hedzr/errors
Nestable/wrappable golang errors library.
https://github.com/hedzr/errors
errno error errors go golang stack unwraps
Last synced: about 1 year ago
JSON representation
Nestable/wrappable golang errors library.
- Host: GitHub
- URL: https://github.com/hedzr/errors
- Owner: hedzr
- License: mit
- Created: 2019-12-05T04:07:12.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2024-10-30T17:24:29.000Z (over 1 year ago)
- Last Synced: 2025-03-25T22:35:17.900Z (about 1 year ago)
- Topics: errno, error, errors, go, golang, stack, unwraps
- Language: Go
- Homepage: https://hedzr.github.io/golang/errors/golang-errors-2/
- Size: 326 KB
- Stars: 7
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# errors.v3
[](https://github.com/hedzr/errors/actions/workflows/go.yml)
[](https://gopkg.in/hedzr/errors.v3)
[](https://pkg.go.dev/gopkg.in/hedzr/errors.v3)
[](https://goreportcard.com/report/github.com/hedzr/errors)
[](https://coveralls.io/github/hedzr/errors)
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fhedzr%2Ferrors?ref=badge_shield)
Wrapped errors and more for golang developing (not just for go1.11, go1.13, and go1.20+).
`hedzr/errors` provides the compatibilities to your old project up to go 1.20.
`hedzr/errors` provides some extra enhancements for better context environment saving on error occurred.
## Features
- Simple migrating way from std errors: all of standard functions have been copied to
- Better `New()`:
- format message inline: `err := errors.New("hello %s", "world")`
- format with `WithXXX`: `err := errors.New(errors.WithErrors(errs...))`
- cascade format: `err := errors.New().WithErrors(errs...)`
- Stacktrace awareness
- Container for canning errors: [Error Container (Inner/Nested)](#error-container-innernested)
- error template: [Format message instantly but the text template can be given at beginning](#error-template)
- Codes: treat a number as an error object
- Unwrap inner canned errors one by one
- No mental burden
### Others
## History
- v3.3.5
- fixed Iss() - dead loop or break unexpected
- v3.3.3
- ensure working on go 1.23+
- v3.3.2
- fixed/improved Attach() - attaching itself is denied now
- v3.3.1
- fixed Iss() couldn't test the others except the first error.
- v3.3.0
- added `Iss(err, errs...)` to test if any of errors are included in 'err'.
- improved As/Is/Unwrap to fit for new joint error since go1.20
- added causes2.Clear, ...
- improved Error() string
- reviewed and re-published this repo from v3.3
- v3.1.9
- fixed error.Is deep test to check two errors' message text contents if matched
- fixed errors.v3.Join when msg is not empty in an err obj
- fixed causes.WithErrors(): err obj has been ignored even if its message is not empty
- OLDER in [CHANGELOG](https://github.com/hedzr/errors/blob/master/CHANGELOG)
## Compatibilities
These features are supported for compatibilities.
### stdlib `errors' compatibilities
- `func As(err error, target interface{}) bool`
- `func Is(err, target error) bool`
- `func New(text string) error`
- `func Unwrap(err error) error`
- `func Join(errs ...error) error`
### `pkg/errors` compatibilities
- `func Wrap(err error, message string) error`
- `func Cause(err error) error`: unwraps recursively, just like Unwrap()
- [x] `func Cause1(err error) error`: unwraps just one level
- `func WithCause(cause error, message string, args ...interface{}) error`, = `Wrap`
- supports Stacktrace
- in an error by `Wrap()`, stacktrace wrapped;
- for your error, attached by `WithStack(cause error)`;
### Some Enhancements
- `Iss(err error, errs ...error) bool`
- `AsSlice(errs []error, target interface{}) bool`
- `IsAnyOf(err error, targets ...error) bool`
- `IsSlice(errs []error, target error) bool`
- `TypeIs(err, target error) bool`
- `TypeIsSlice(errs []error, target error) bool`
- `Join(errs ...error) error`
- `DumpStacksAsString(allRoutines bool) string`
- `CanAttach(err interface{}) (ok bool)`
- `CanCause(err interface{}) (ok bool)`
- `CanCauses(err interface{}) (ok bool)`
- `CanUnwrap(err interface{}) (ok bool)`
- `CanIs(err interface{}) (ok bool)`
- `CanAs(err interface{}) (ok bool)`
- `Causes(err error) (errs []error)`
## Best Practices
### Basics
```go
package test
import (
"gopkg.in/hedzr/errors.v3"
"io"
"reflect"
"testing"
)
func TestForExample(t *testing.T) {
fn := func() (err error) {
ec := errors.New("some tips %v", "here")
defer ec.Defer(&err)
// attaches much more errors
for _, e := range []error{io.EOF, io.ErrClosedPipe} {
ec.Attach(e)
}
}
err := fn()
t.Logf("failed: %+v", err)
// use another number different to default to skip the error frames
err = errors.
Skip(3). // from on Skip()
WithMessage("some tips %v", "here").Build()
t.Logf("failed: %+v", err)
err = errors.
Message("1"). // from Message() on
WithSkip(0).
WithMessage("bug msg").
Build()
t.Logf("failed: %+v", err)
err = errors.
NewBuilder(). // from NewBuilder() on
WithCode(errors.Internal). // add errors.Code
WithErrors(io.EOF). // attach inner errors
WithErrors(io.ErrShortWrite, io.ErrClosedPipe).
Build()
t.Logf("failed: %+v", err)
// As code
var c1 errors.Code
if errors.As(err, &c1) {
println(c1) // = Internal
}
// As inner errors
var a1 []error
if errors.As(err, &a1) {
println(len(a1)) // = 3, means [io.EOF, io.ErrShortWrite, io.ErrClosedPipe]
}
// Or use Causes() to extract them:
if reflect.DeepEqual(a1, errors.Causes(err)) {
t.Fatal("unexpected problem")
}
// As error, the first inner error will be extracted
var ee1 error
if errors.As(err, &ee1) {
println(ee1) // = io.EOF
}
series := []error{io.EOF, io.ErrShortWrite, io.ErrClosedPipe, errors.Internal}
var index int
for ; ee1 != nil; index++ {
ee1 = errors.Unwrap(err) // extract the inner errors one by one
if ee1 != nil && ee1 != series[index] {
t.Fatalf("%d. cannot extract '%v' error with As(), ee1 = %v", index, series[index], ee1)
}
}
}
```
### Error Container (Inner/Nested)
```go
func TestContainer(t *testing.T) {
// as a inner errors container
child := func() (err error) {
ec := errors.New("multiple tasks have errors")
defer ec.Defer(&err) // package the attached errors as a new one and return it as `err`
for _, r := range []error{io.EOF, io.ErrShortWrite, io.ErrClosedPipe, errors.Internal} {
ec.Attach(r)
}
doWithItem := func(item Item) (err error) {
// ...
return
}
for _, item := range SomeItems {
// nil will be ignored safely, do'nt worry about invalid attaches.
ec.Attach(doWithItem(item))
}
return
}
err := child() // get the canned errors as a packaged one
t.Logf("failed: %+v", err)
}
```
### Error Template
We could *declare* a message template at first and format it with live args
to build an error instantly.
```go
func TestErrorsTmpl(t *testing.T) {
errTmpl := errors.New("expecting %v but got %v")
var err error
err = errTmpl.FormatWith("789", "123")
t.Logf("The error is: %v", err)
err = errTmpl.FormatWith(true, false)
t.Logf("The error is: %v", err)
}
```
`FormatWith` will make new clone from errTmpl so you can use multiple cloned errors thread-safely.
The derived error instance is the descendant of the error template.
This relation can be tested by `errors.IsDescent(errTempl, err)`
```go
func TestIsDescended(t *testing.T) {
err3 := New("any error tmpl with %v")
err4 := err3.FormatWith("huahua")
if !IsDescended(err3, err4) {
t.Fatalf("bad test on IsDescended(err3, err4)")
}
}
```
### Better format for a nested error
Since v3.1.1, the better message format will be formatted at Printf("%+v").
```go
func TestAs_betterFormat(t *testing.T) {
var err = New("Have errors").WithErrors(io.EOF, io.ErrShortWrite, io.ErrNoProgress)
t.Logf("%v\n", err)
var nestNestErr = New("Errors FOUND:").WithErrors(err, io.EOF)
var nnnErr = New("Nested Errors:").WithErrors(nestNestErr, strconv.ErrRange)
t.Logf("%v\n", nnnErr)
t.Logf("%+v\n", nnnErr)
}
```
The output is:
```bash
=== RUN TestAs_betterFormat
causes_test.go:23: Have errors [EOF | short write | multiple Read calls return no data or error]
causes_test.go:27: Nested Errors: [Errors FOUND: [Have errors [EOF | short write | multiple Read calls return no data or error] | EOF] | value out of range]
causes_test.go:28: Nested Errors:
- Errors FOUND:
- Have errors
- EOF
- short write
- multiple Read calls return no data or error
- EOF
- value out of range
gopkg.in/hedzr/errors%2ev3.TestAs_betterFormat
/Volumes/VolHack/work/godev/cmdr-series/libs/errors/causes_test.go:26
testing.tRunner
/usr/local/go/src/testing/testing.go:1576
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1598
--- PASS: TestAs_betterFormat (0.00s)
PASS
```
## LICENSE
MIT
### Scan
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fhedzr%2Ferrors?ref=badge_large)