https://github.com/corebreaker/goerrors
Easy error informations and stack traces for Go with rich informations and a Try/Catch/Finally mechanism.
https://github.com/corebreaker/goerrors
error-handling error-reporting errors go golang try-catch
Last synced: 8 months ago
JSON representation
Easy error informations and stack traces for Go with rich informations and a Try/Catch/Finally mechanism.
- Host: GitHub
- URL: https://github.com/corebreaker/goerrors
- Owner: corebreaker
- License: gpl-3.0
- Created: 2016-11-05T19:17:46.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2019-06-02T14:09:53.000Z (about 7 years ago)
- Last Synced: 2024-12-22T11:29:13.366Z (over 1 year ago)
- Topics: error-handling, error-reporting, errors, go, golang, try-catch
- Language: Go
- Homepage:
- Size: 86.9 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GoErrors - Easy error informations and stack traces for Go with rich informations and a Try/Catch/Finally mechanism.
[](https://goreportcard.com/report/github.com/corebreaker/goerrors)
[](https://travis-ci.com/corebreaker/goerrors)
[](https://coveralls.io/github/corebreaker/goerrors)
[](https://godoc.org/github.com/corebreaker/goerrors)
[](https://github.com/corebreaker/goerrors/blob/master/LICENSE)
[](https://github.com/corebreaker/goerrors/releases)
[](https://libraries.io/github/corebreaker/goerrors)
It's a package that's allow you to make Go errors more comprehensive, more featured and easier to use.
This project is the realisation of the idea introduced by the GIST [try-catch-finally.go](https://gist.github.com/corebreaker/6a93c8210425e96dc1bcbb157f0270b0).
## Features
- Verbose with stack trace
- Ready for Try/Catch/Finally paradigm
- Extensible with your own error
- Error hierarchy
- Entirely customizable
## Installation
go get github.com/corebreaker/goerrors
## How is it work ?
A normal error is just an interface. But here we added an extended interface IError which can transport other infomations.
Therefore to add informations, the standard error (`error` interface) is «decorated» with informations and so
we obtain a new error value. These informations are:
- stack trace informations (files + lines)
- additionnal customized string
- optionnal error code
When the `Error` method is called, all these informations will be formated in a string.
This type of error gives you rich informations on an error without using `panic` function (even if with a panic, you
could show your additionnal infomations).
## How to use it ?
### Decorate error to add a stack trace
```go
// for example, let's open a file
func OpenMyFile() (*os.File, error) {
file, err := os.Open("MyFile.txt")
if err != nil {
// Here, we decorate the error
return nil, goerrors.DecorateError(err)
}
return file, nil
}
```
Then, we can `panic` this decorated error or simply print it, like this:
```go
func main() {
// First we must enable the debug mode to activate the stacktrace
goerrors.SetDebug(true)
// Use a function that use the `goerrors` package
file, err := OpenMyFile()
// Check the error
if err != nil {
// Show the error
fmt.Println(err)
// Terminate
return
}
// …
}
```
You will see some thing like this:
```
github.com/corebreaker/goerrors.tStandardError: open MyFile.txt: no such file or directory
github.com/corebreaker/goerrors.(*GoError).Init (/home/frederic/go/src/github.com/corebreaker/goerrors/errors.go:219)
github.com/corebreaker/goerrors.DecorateError (/home/frederic/go/src/github.com/corebreaker/goerrors/standard.go:51)
main.OpenMyFile (/home/frederic/.local/share/data/liteide/liteide/goplay.go:13)
main.main (/home/frederic/.local/share/data/liteide/liteide/goplay.go:24)
------------------------------------------------------------------------------
```
### A Try/Catch/Finally mechanism
Plus, this library uses the `panic()` function, the `recover()` function and the `defer` instruction,
as a Throw and a Try/Catch/Finally mechanisms and can be used like this:
```go
goerrors.Try(func(err goerrors.IError) error {
// Try block
}, func(err goerrors.IError) error {
// Catch block
}, func(err goerrors.IError) error {
// Finally block
})
```
The error passed in `Try` block is the error which called the `Try` method:
```go
theError := goerrors.MakeError("the error in `Try` block")
theError.Try(func(err goerrors.IError) error {
// Here err === theError
return nil
})
```
In the case in using the `Try` function in the GoError package, the error passed as argument is an error created by the
call the `Try` function. Then, that error can be customized with the GoError API.
#### An example with a throw, called "raise" here
Actually, returning an error in the `Try` block is a `Throw`, and a Go `panic` call is too like a throw but there is
a `panic`-like function for keeping Try/Catch formalism, the `Raise` function, used like that:
```go
goerrors.Try(func(err goerrors.IError) error {
if aCondition {
// `Raise` call
goerrors.Raise("an error")
}
// Do something
return nil
}, func(err goerrors.IError) error {
// Catch block
}, func(err goerrors.IError) error {
// Finally block
})
```
At last, all errors generated by GoError have a `Raise` method. So, you can throw an error like that:
```go
goerrors.Try(func(err goerrors.IError) error {
if aCondition {
// `Raise` method call
goerrors.MakeError("an error").Raise()
}
// Do something
return nil
}, func(err goerrors.IError) error {
// Catch block
}, func(err goerrors.IError) error {
// Finally block
})
```
## A simple example
```go
package main
import (
"fmt"
gerr "github.com/corebreaker/goerrors"
)
// A function which return checked quotient
func my_func(i, j int) (int, error) {
if j == 0 {
return 0, gerr.MakeError("Division by zero")
}
return i / j, nil
}
// Main function
func main() {
// Activate stack trace
gerr.SetDebug(true)
i, j := 1, 0
// Call checked function
q, err := my_func(i, j)
if err != nil {
fmt.Println(err)
return
}
// Here, in this example, this code won't never be executed
fmt.Print(i, "/", j, "=", q)
}
```
This will show:
```
StandardError: Division by zero
main.my_func (/projects/go/prototype/main.go:11)
main.main (/projects/go/prototype/main.go:23)
------------------------------------------------------------------------------
```
## Another example with existing error
```go
package main
import (
"fmt"
"os"
gerr "github.com/corebreaker/goerrors"
)
// A function which open a file
func openFile(name string) (*os.File, error) {
f, err := os.Open(name)
// Decorate the opening error
if err != nil {
return nil, gerr.DecorateError(err)
}
return f, nil
}
// A function which read one byte in the opened file
func readFile(f *os.File) (byte, error) {
var b [1]byte
n, err := f.Read(b[:])
// Decorate the read error
if err != nil {
return 0, gerr.DecorateError(err)
}
// Return custom error
if n == 0 {
return 0, gerr.MakeError("No data to read")
}
return b[0], nil
}
// Main function
func main() {
// Activate stack trace
gerr.SetDebug(true)
// Call the checked open function
f, err := openFile("a_file.txt")
if err != nil {
fmt.Println(err)
return
}
// Here, in this example, this code won't never be executed if the file can't be opened
defer f.Close()
_, err = readFile(f)
}
```
This will show:
```
StandardError: open a_file.txt: no such file or directory
main.open_file (/projects/go/src/github.com/corebreaker/goerrors.go:15)
main.main (/projects/go/src/github.com/corebreaker/goerrors.go:46)
------------------------------------------------------------------------------
```
### A Try/Catch example with error inheritance
```go
package main
import (
"fmt"
gerr "github.com/corebreaker/goerrors"
)
type ErrorBase struct{ gerr.GoError }
type ErrorA struct{ ErrorBase }
type ErrorB struct{ ErrorBase }
type ChildError struct{ ErrorA }
func newErrorBase() gerr.IError {
err := &ErrorBase{}
return err.Init(err, "message from Error base", nil, nil, 0)
}
func newErrorB() gerr.IError {
err := &ErrorB{}
return err.Init(err, "message from Error B", nil, nil, 0)
}
func newChildError() gerr.IError {
err := &ChildError{}
return err.Init(err, "message from Child Error", nil, nil, 0)
}
// A function which raise and try to catch the error which is not in the same hierarchy
func myFunc() () {
_ = newErrorB().Try(func(err gerr.IError) error {
newChildError().Raise()
return nil
}, func(err gerr.IError) error {
// This catch block will not called because ErrorB is not in the same error hierarchy of ChildError
return nil
}, nil)
}
// Main function
func main() {
_ = newErrorBase().Try(func(err gerr.IError) error {
myFunc()
return nil
}, func(err gerr.IError) error {
fmt.Println("Catched error:", err)
return nil
}, nil)
}
```
This will show:
```
Catched error: main.ChildError: message from Child Error
```