reguerr - Code generator for systematic error handling
reguerr helps with systematic error handling.
In order to facilitate the handling of system failure, you can set the error code to identify the error in reguerr and the log level and response code associated with it.
go install gitlab.com/future-architect/reguerr/cmd/reguerr@latest
>reguerr -h
Usage:
reguerr [command]
Available Commands:
generate generate reguerr code
help Help about any command
validate validate input file
Flags:
-h, --help help for reguerr
generate command is main function in reguerr.
>reguerr generate -h
generate reguerr code
Usage:
reguerr generate [flags]
Flags:
--defaultErrorLevel string change default log level(Trace,Debug,Info,Warn,Error,Fatal)
--defaultStatusCode int change default status code (default -1)
-f, --file string input go file
-h, --help help for generate
# target file
cat <<EOF > example.go
package example
import (
"gitlab.com/future-architect/reguerr"
)
var (
// No message arguments
PermissionDeniedErr = reguerr.New("1001", "permission denied").Build()
// One message arguments
UpdateConflictErr = reguerr.New("1002", "other user updated: key=%s").Build()
// Message arguments with label
InvalidInputParameterErr = reguerr.New("1003", "invalid input parameter: %v").
Label(0,"payload", map[string]interface{}{}).
Build()
)
EOF
# START reguerr
./reguerr generate -f example.go
Output is bellow format.
// Code generated by reguerr; DO NOT EDIT.
package example
import (
"gitlab.com/future-architect/reguerr"
)
func NewPermissionDeniedErr(err error) *reguerr.Error {
return PermissionDeniedErr.WithError(err)
}
func IsPermissionDeniedErr(err error) bool {
var cerr *reguerr.Error
if as := errors.As(err, &cerr); as {
if cerr.Code() == PermissionDeniedErr.Code() {
return true
}
}
return false
}
func NewUpdateConflictErr(err error, arg1 interface{}) *reguerr.Error {
return UpdateConflictErr.WithError(err).WithArgs(arg1)
}
func IsUpdateConflictErr(err error) bool {
var cerr *reguerr.Error
if as := errors.As(err, &cerr); as {
if cerr.Code() == UpdateConflictErr.Code() {
return true
}
}
return false
}
func NewInvalidInputParameterErr(err error, payload map[string]interface{}) *reguerr.Error {
return InvalidInputParameterErr.WithError(err).WithArgs(payload)
}
func IsInvalidInputParameterErr(err error) bool {
var cerr *reguerr.Error
if as := errors.As(err, &cerr); as {
if cerr.Code() == InvalidInputParameterErr.Code() {
return true
}
}
return false
}
Then reguerr also generated markdown table.
CODE | NAME | LOGLEVEL | STATUSCODE | FORMAT |
---|---|---|---|---|
1001 | PermissionDeniedErr | Error | 500 | permission denied |
1002 | UpdateConflictErr | Error | 500 | other user updated: key=%s |
1003 | InvalidInputParameterErr | Error | 500 | invalid input parameter: %v |
If you want to see more examples, you can get example.
The output location of the error log and the switching process of the response status code are aggregated.
package example
import (
"fmt"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"gitlab.com/future-architect/reguerr"
"net/http"
)
func UserHandleFunc(w http.ResponseWriter, r *http.Request) {
if err := somethingUserOperation("id1"); err != nil {
errorLog(err)
w.WriteHeader(httpStatus(err))
return
}
w.WriteHeader(http.StatusOK)
}
func errorLog(err error) {
rerr, ok := reguerr.ErrorOf(err)
if ok {
level, err := zerolog.ParseLevel(rerr.Level().String())
if err != nil {
log.Error().Str("code", rerr.Code()).Msgf(rerr.Error())
} else {
log.WithLevel(level).Str("code", rerr.Code()).Msgf(rerr.Error())
}
return
}
log.Printf("unexpected error: %v\n", err)
}
func httpStatus(err error) int {
code, ok := reguerr.StatusOf(err)
if ok {
return code
} else {
return http.StatusInternalServerError
}
}
func somethingUserOperation(key string) error {
// some operation for user
return NewNotFoundOperationIDErr(fmt.Errorf("key=%v", key))
}
Apache License Version 2.0