Compare commits

..

No commits in common. "main" and "v0.3.1" have entirely different histories.
main ... v0.3.1

2 changed files with 31 additions and 132 deletions

View file

@ -2,45 +2,25 @@
package main package main
import ( import (
// External // External
werr "git.gibonuddevalla.se/go/wrappederror" werr "git.gibonuddevalla.se/go/wrappederror"
// Standard // Standard
"encoding/json" "errors"
"errors" "fmt"
"fmt"
"os"
) )
func errorHandler(err werr.Error) { func errorHandler(err werr.Error) {
// For example print or log error to file // For example print or log error to file
fmt.Printf("\x1b[31;1m%s\x1b[0m\n", err) fmt.Printf("ERROR - %s\n", err)
fmt.Printf("\x1b[33;1m%s\x1b[0m\n", err.NoTrace())
j, _ := json.MarshalIndent(err, "", " ")
fmt.Printf("%s\n\n", j)
} }
func main() { func foo() {
// Make file paths relative to this file. werr.SetLogCallback(errorHandler)
werr.Init()
// Handler to call when using Log(). err := errors.New("foobar 1")
werr.SetLogCallback(errorHandler) err1 := werr.Wrap(err)
// Wrap an existing error. err2 := werr.New("foobar 2")
err := errors.New("foobar 1")
err1 := werr.Wrap(err)
// Create a new error with extra information.
err2 := werr.New("foobar 2").WithCode("FOO-100").WithData(137)
// The os error contains more information.
_, errOS := os.ReadFile("/tmp/does_not_exist")
werr.Wrap(errOS).Log()
// Log the previously wrapped errors.
werr.Wrap(err1).Log()
werr.Wrap(err2).Log()
} }
``` ```

119
pkg.go
View file

@ -1,75 +1,17 @@
/*
wrappederror provides traceable errors:
package main
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
"encoding/json"
"errors"
"fmt"
"os"
)
func errorHandler(err werr.Error) {
// For example print or log error to file
fmt.Printf("\x1b[31;1m%s\x1b[0m\n", err)
fmt.Printf("\x1b[33;1m%s\x1b[0m\n", err.NoTrace())
j, _ := json.MarshalIndent(err, "", " ")
fmt.Printf("%s\n\n", j)
}
func main() {
// Make file paths relative to this file.
werr.Init()
// Handler to call when using Log().
werr.SetLogCallback(errorHandler)
// Wrap an existing error.
err := errors.New("foobar 1")
err1 := werr.Wrap(err)
// Create a new error with extra information.
err2 := werr.New("foobar 2").WithCode("FOO-100").WithData(137)
// The os error contains more information.
_, errOS := os.ReadFile("/tmp/does_not_exist")
werr.Wrap(errOS).Log()
// Log the previously wrapped errors.
werr.Wrap(err1).Log()
werr.Wrap(err2).Log()
}
*/
package WrappedError package WrappedError
import ( import (
// Standard // Standard
"fmt" "fmt"
"path" "path"
"regexp"
"runtime" "runtime"
) )
type Error struct { type Error struct {
Wrapped error Wrapped error
ErrStr string // wrapped error isn't necessarily json encodable
Code string
File string File string
Line int Line int
Data any Data interface{}
}
type CodableError interface {
error
WithCode(string) CodableError
WithData(any) CodableError
Log() CodableError
} }
type LogCallback func(Error) type LogCallback func(Error)
@ -100,74 +42,51 @@ func callback(wrapped Error) {
// Error implements the error inteface and adds filename and line to the error. // Error implements the error inteface and adds filename and line to the error.
func (wrapped Error) Error() string { func (wrapped Error) Error() string {
var code string
if wrapped.Code != "" {
code = wrapped.Code + ":"
}
return fmt.Sprintf( return fmt.Sprintf(
"[%s%s:%d] %s", "[%s:%d] %s",
code,
wrapped.File, wrapped.File,
wrapped.Line, wrapped.Line,
wrapped.Wrapped.Error(), wrapped.Wrapped.Error(),
) )
} }
func create(err error, data interface{}) *Error { func create(err error, data interface{}) error {
if err == nil { if err == nil {
return nil return nil
} }
_, file, line, _ := runtime.Caller(2) _, file, line, _ := runtime.Caller(2)
file = file[baseDirLength+1:] file = file[baseDirLength+1:]
wrapped := Error{ wrapped := Error{
Wrapped: err, Wrapped: err,
ErrStr: err.Error(),
File: file, File: file,
Line: line, Line: line,
Data: data, Data: data,
} }
return &wrapped callback(wrapped)
}
// Wrap wraps an existing error with file and line.
func Wrap(err error) *Error {
return create(err, nil)
}
// New creates a new wrapped error with file and line.
func New(msg string, params ...any) *Error {
err := fmt.Errorf(msg, params...)
wrapped := create(err, nil)
return wrapped return wrapped
} }
// WithCode associates a string code with the error. // Wrap wraps an existing error with file and line.
func (e *Error) WithCode(code string) CodableError { func Wrap(err error) error {
e.Code = code return create(err, "")
return e
} }
// WithData associates any data with the error to make troubleshooting easier. func WrapData(err error, data interface{}) error {
func (e *Error) WithData(data any) CodableError { return create(err, data)
e.Data = data
return e
} }
// Log calls the log callback. // New creates a new wrapped error with file and line.
func (e *Error) Log() CodableError { func New(msg string, params ...any) error {
callback(*e) err := fmt.Errorf(msg, params...)
return e wrapped := create(err, "")
return wrapped
} }
// NoTrace returns the Error() string without the trace. func NewData(msg string, data interface{}, params ...any) error {
func (e *Error) NoTrace() string { err := fmt.Errorf(msg, params...)
rxp := regexp.MustCompile(`^(\[[^\]]+\.go:\d+\]\s*)*`) wrapped := create(err, data)
return string( return wrapped
rxp.ReplaceAll(
[]byte(e.Error()),
[]byte(""),
),
)
} }