2021-03-11 00:49:14 +00:00
|
|
|
package oops
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/go-stack/stack"
|
2021-03-11 03:19:39 +00:00
|
|
|
"github.com/rs/zerolog"
|
2021-03-11 00:49:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Error struct {
|
|
|
|
Message string
|
|
|
|
Wrapped error
|
2021-03-11 03:19:39 +00:00
|
|
|
Stack CallStack
|
2021-03-11 00:49:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Error) Error() string {
|
|
|
|
return fmt.Sprintf("%s: %v", e.Message, e.Wrapped)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Error) Unwrap() error {
|
|
|
|
return e.Wrapped
|
|
|
|
}
|
|
|
|
|
2021-03-11 03:19:39 +00:00
|
|
|
type CallStack []StackFrame
|
|
|
|
|
|
|
|
func (s CallStack) MarshalZerologArray(a *zerolog.Array) {
|
|
|
|
for _, frame := range s {
|
|
|
|
a.Object(frame)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 00:49:14 +00:00
|
|
|
type StackFrame struct {
|
|
|
|
File string `json:"file"`
|
|
|
|
Line int `json:"line"`
|
|
|
|
Function string `json:"function"`
|
|
|
|
}
|
|
|
|
|
2021-03-11 03:19:39 +00:00
|
|
|
func (f StackFrame) MarshalZerologObject(e *zerolog.Event) {
|
|
|
|
e.
|
|
|
|
Str("file", f.File).
|
|
|
|
Int("line", f.Line).
|
|
|
|
Str("function", f.Function)
|
|
|
|
}
|
|
|
|
|
2021-03-11 00:49:14 +00:00
|
|
|
var ZerologStackMarshaler = func(err error) interface{} {
|
|
|
|
if asOops, ok := err.(*Error); ok {
|
|
|
|
return asOops.Stack
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(wrapped error, format string, args ...interface{}) error {
|
|
|
|
trace := stack.Trace().TrimRuntime()
|
2021-03-11 03:19:39 +00:00
|
|
|
frames := make(CallStack, len(trace))
|
2021-03-11 00:49:14 +00:00
|
|
|
for i, call := range trace {
|
|
|
|
callFrame := call.Frame()
|
|
|
|
frames[i] = StackFrame{
|
|
|
|
File: callFrame.File,
|
|
|
|
Line: callFrame.Line,
|
|
|
|
Function: callFrame.Function,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Error{
|
|
|
|
Message: fmt.Sprintf(format, args...),
|
|
|
|
Wrapped: wrapped,
|
|
|
|
Stack: frames,
|
|
|
|
}
|
|
|
|
}
|