diff --git a/README.md b/README.md index 4f28c38..99a8908 100644 --- a/README.md +++ b/README.md @@ -83,4 +83,77 @@ func doStuffWrapped() error { fmt.Println(adverr.Trace()) ``` -### \ No newline at end of file +### Example of a printed error +Code: +```go +package main + +import ( + "adverr" + "errors" +) + +var ( + ErrDoStuffFailed = adverr.NewErrTmpl("ErrDoStuffFailed", "Could'nt do stuff because of %s") +) + +func main() { + err := doStuffInAnotherGoroutine() + if err != nil { + adverr.Fatalln(err, 1) + } +} + +func doStuff() error { + err := doGoNativeStuff() + if err != nil { + return ErrDoStuffFailed.Wrap(err, "reasons") + } + + return nil +} + +func doStuffInAnotherGoroutine() error { + ch := make(chan error, 1) + + go func() { + ch <- doStuff() + close(ch) + }() + + err := <-ch + if err != nil { + return adverr.Wrap("Goroutine failed because of errors", err) + } + + return nil +} + +func doGoNativeStuff() error { + return errors.New("some go error") +} + +``` +Output: +``` +adverr.Error: Goroutine failed because of errors + at main.doStuffInAnotherGoroutine (/home/user/go/src/test/main.go:38) + at main.main (/home/user/go/src/test/main.go:13) + at runtime.main (/usr/local/go/src/runtime/proc.go:204) +Caused by ErrDoStuffFailed: Could'nt do stuff because of reasons + at main.doStuff (/home/user/go/src/test/main.go:22) + at main.doStuffInAnotherGoroutine.func1 (/home/user/go/src/test/main.go:32) +Caused by errors.errorString: some go error + (Unknown source) +``` + +### Globals +You can set the maximum limit of the call stack trace via +```go +adverr.CallStackLength = 50 // default value: 100 +``` + +If you are in a productive environment, consider disabling call traces completely for performance reasons: +```go +adverr.DisableTrace = true // default value: false +``` \ No newline at end of file diff --git a/calltrace.go b/calltrace.go index 4a99722..3368131 100644 --- a/calltrace.go +++ b/calltrace.go @@ -1,6 +1,7 @@ package adverr import ( + "fmt" "runtime" "strconv" "strings" @@ -9,19 +10,21 @@ import ( // CallTrace represents a call stack trace similar to Java's stack trace type CallTrace struct { frames *runtime.Frames + more bool } // Trace returns a new CallTrace starting from this call // Use skip to skip the first entries in the trace func Trace(skip int) *CallTrace { - if !TraceCallStack { + if DisableTrace { return nil } - pc := make([]uintptr, CallStackLength) + pc := make([]uintptr, CallStackLength+1) n := runtime.Callers(skip+1, pc) pc = pc[:n] - return &CallTrace{runtime.CallersFrames(pc)} + fmt.Println(n, CallStackLength) + return &CallTrace{runtime.CallersFrames(pc), n == CallStackLength+1} } func (ct *CallTrace) String() string { @@ -42,5 +45,9 @@ func (ct *CallTrace) String() string { b.WriteString("\n") } + if ct.more { + b.WriteString("\t ...\n") + } + return b.String() } diff --git a/error.go b/error.go index e4f49e3..749d6df 100644 --- a/error.go +++ b/error.go @@ -89,7 +89,7 @@ func printErr(err error, b *strings.Builder) { b.WriteString(errtype(err)) b.WriteString(": ") b.WriteString(err.Error()) - b.WriteString("\n") + b.WriteString("\n\t(Unknown source)\n") } cause := errors.Unwrap(err) diff --git a/error_tmpl.go b/error_tmpl.go index 11e088c..16e6e29 100644 --- a/error_tmpl.go +++ b/error_tmpl.go @@ -33,3 +33,13 @@ func (t *ErrTmpl) New(args ...interface{}) *Error { callTrace: Trace(2), } } + +// Wrap returns a new Error with a given cause in which args are being formatted into the format string of its template +func (t *ErrTmpl) Wrap(cause error, args ...interface{}) *Error { + return &Error{ + msg: fmt.Sprintf(t.format, args...), + cause: cause, + tmpl: t, + callTrace: Trace(2), + } +} diff --git a/globals.go b/globals.go index 4c6de23..dff85da 100644 --- a/globals.go +++ b/globals.go @@ -1,9 +1,9 @@ package adverr -// TraceCallStack decides if any call stack traces will be gathered when creating Errors -// If your application is doing performance-heavy tasks with lots of Error creations, you may consider setting this to false -// If set to false, all CallTraces in Error will be nil -var TraceCallStack bool = true +// DisableTrace decides if any call stack traces will be gathered when creating Errors +// If your application is doing performance-heavy tasks with lots of Error creations, you may consider setting this to true +// If set to true, all CallTraces in Error will be nil +var DisableTrace bool = true // CallStackLength decides how many calls from the call stack should be gathered at most var CallStackLength int = 100