204 lines
4.5 KiB
Go
204 lines
4.5 KiB
Go
package exerr
|
|
|
|
import (
|
|
"github.com/rs/xid"
|
|
"github.com/rs/zerolog"
|
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type ExErr struct {
|
|
UniqueID string `json:"uniqueID"`
|
|
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Category ErrorCategory `json:"category"`
|
|
Severity ErrorSeverity `json:"severity"`
|
|
Type ErrorType `json:"type"`
|
|
|
|
StatusCode *int `json:"statusCode"`
|
|
|
|
Message string `json:"message"`
|
|
WrappedErrType string `json:"wrappedErrType"`
|
|
Caller string `json:"caller"`
|
|
|
|
OriginalError *ExErr
|
|
|
|
Meta MetaMap `json:"meta"`
|
|
}
|
|
|
|
func (ee *ExErr) Error() string {
|
|
return ee.Message
|
|
}
|
|
|
|
func (ee *ExErr) Unwrap() error {
|
|
return ee.OriginalError
|
|
}
|
|
|
|
func (ee *ExErr) Log(evt *zerolog.Event) {
|
|
evt.Msg(ee.FormatLog(LogPrintFull))
|
|
}
|
|
|
|
func (ee *ExErr) FormatLog(lvl LogPrintLevel) string {
|
|
if lvl == LogPrintShort {
|
|
|
|
msg := ee.Message
|
|
if ee.OriginalError != nil && ee.OriginalError.Category == CatForeign {
|
|
msg = msg + " (" + strings.ReplaceAll(ee.OriginalError.Message, "\n", " ") + ")"
|
|
}
|
|
|
|
if ee.Type != TypeWrap {
|
|
return "[" + ee.Type.Key + "] " + msg
|
|
} else {
|
|
return msg
|
|
}
|
|
|
|
} else if lvl == LogPrintOverview {
|
|
|
|
str := "[" + ee.RecursiveType().Key + "] <" + ee.UniqueID + "> " + strings.ReplaceAll(ee.RecursiveMessage(), "\n", " ") + "\n"
|
|
|
|
indent := ""
|
|
for curr := ee; curr != nil; curr = curr.OriginalError {
|
|
indent += " "
|
|
|
|
str += indent
|
|
str += "-> "
|
|
strmsg := strings.Trim(curr.Message, " \r\n\t")
|
|
if lbidx := strings.Index(curr.Message, "\n"); lbidx >= 0 {
|
|
strmsg = strmsg[0:lbidx]
|
|
}
|
|
strmsg = langext.StrLimit(strmsg, 61, "...")
|
|
str += strmsg
|
|
str += "\n"
|
|
|
|
}
|
|
return str
|
|
|
|
} else if lvl == LogPrintFull {
|
|
|
|
str := "[" + ee.RecursiveType().Key + "] <" + ee.UniqueID + "> " + strings.ReplaceAll(ee.RecursiveMessage(), "\n", " ") + "\n"
|
|
|
|
indent := ""
|
|
for curr := ee; curr != nil; curr = curr.OriginalError {
|
|
indent += " "
|
|
|
|
etype := ee.Type.Key
|
|
if ee.Type == TypeWrap {
|
|
etype = "~"
|
|
}
|
|
|
|
str += indent
|
|
str += "-> ["
|
|
str += etype
|
|
if curr.Category == CatForeign {
|
|
str += "|Foreign"
|
|
}
|
|
str += "] "
|
|
str += strings.ReplaceAll(curr.Message, "\n", " ")
|
|
if curr.Caller != "" {
|
|
str += " (@ "
|
|
str += curr.Caller
|
|
str += ")"
|
|
}
|
|
str += "\n"
|
|
|
|
if curr.Meta.Any() {
|
|
meta := indent + " {" + curr.Meta.FormatOneLine(240) + "}"
|
|
if len(meta) < 200 {
|
|
str += meta
|
|
str += "\n"
|
|
} else {
|
|
str += curr.Meta.FormatMultiLine(indent+" ", " ", 1024)
|
|
str += "\n"
|
|
}
|
|
}
|
|
}
|
|
return str
|
|
|
|
} else {
|
|
|
|
return "[?[" + ee.UniqueID + "]?]"
|
|
|
|
}
|
|
}
|
|
|
|
func (ee *ExErr) ShortLog(evt *zerolog.Event) {
|
|
ee.Meta.Apply(evt).Msg(ee.FormatLog(LogPrintShort))
|
|
}
|
|
|
|
// RecursiveMessage returns the message to show
|
|
// = first error (top-down) that is not wrapping/foreign/empty
|
|
func (ee *ExErr) RecursiveMessage() string {
|
|
for curr := ee; curr != nil; curr = curr.OriginalError {
|
|
if curr.Message != "" && curr.Category != CatWrap && curr.Category != CatForeign {
|
|
return curr.Message
|
|
}
|
|
}
|
|
|
|
// fallback to self
|
|
return ee.Message
|
|
}
|
|
|
|
// RecursiveType returns the statuscode to use
|
|
// = first error (top-down) that is not wrapping/empty
|
|
func (ee *ExErr) RecursiveType() ErrorType {
|
|
for curr := ee; curr != nil; curr = curr.OriginalError {
|
|
if curr.Type != TypeWrap {
|
|
return curr.Type
|
|
}
|
|
|
|
}
|
|
|
|
// fallback to self
|
|
return ee.Type
|
|
}
|
|
|
|
// RecursiveStatuscode returns the HTTP Statuscode to use
|
|
// = first error (top-down) that has a statuscode set
|
|
func (ee *ExErr) RecursiveStatuscode() *int {
|
|
for curr := ee; curr != nil; curr = curr.OriginalError {
|
|
if curr.StatusCode != nil {
|
|
return langext.Ptr(*curr.StatusCode)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RecursiveCategory returns the ErrorCategory to use
|
|
// = first error (top-down) that has a statuscode set
|
|
func (ee *ExErr) RecursiveCategory() ErrorCategory {
|
|
for curr := ee; curr != nil; curr = curr.OriginalError {
|
|
if curr.Category != CatWrap {
|
|
return curr.Category
|
|
}
|
|
}
|
|
|
|
// fallback to <empty>
|
|
return ee.Category
|
|
}
|
|
|
|
// RecursiveMeta searches (top-down) for teh first error that has a meta value with teh specified key
|
|
// and returns its value (or nil)
|
|
func (ee *ExErr) RecursiveMeta(key string) *MetaValue {
|
|
for curr := ee; curr != nil; curr = curr.OriginalError {
|
|
if metaval, ok := curr.Meta[key]; ok {
|
|
return langext.Ptr(metaval)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ee *ExErr) Depth() int {
|
|
if ee.OriginalError == nil {
|
|
return 1
|
|
} else {
|
|
return ee.OriginalError.Depth() + 1
|
|
}
|
|
}
|
|
|
|
func newID() string {
|
|
return xid.New().String()
|
|
}
|