You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
6.6 KiB

// ------------------------------------------------------------------------
// Project active2
// Active Thing (activething.com) git.activething.com/go
//
// File name error_text_formatter.go
// Created by DEV
// Modified 27/03/2024
//
// Copyright 2024 activething.com
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------
package errs
import (
"fmt"
"reflect"
"strconv"
"sync"
"time"
)
type (
FmtText struct {
FmtTextAtt
fixName int
fieldSep string
indent string
dateLayout string
fmtField string
errorHead func(s *FmtTextState, e error)
prevHead func(s *FmtTextState, e error)
traceHead func(s *FmtTextState, e error)
traceFmt func(s *FmtTextState, t StackTrace)
providers sync.Map
}
FmtTextFnc func(f *FmtText)
)
func NewFmtText(options ...FmtTextFnc) *FmtText {
fm := applyFmtTextOptions(&FmtText{
FmtTextAtt: FmtTextAttIndent | FmtTextAttDetails | FmtTextAttTrace | FmtTextAttColors | FmtTextAttEmpty,
dateLayout: time.RFC822Z,
indent : " ",
fixName : 12,
fieldSep : " : ",
traceFmt : formatStackTrace ,
}, options...)
if fm.fixName > 0 {
fm.fmtField = "%-" + strconv.Itoa(fm.fixName) + "s"
} else {
fm.fmtField = "%s"
}
return fm
}
func (f *FmtText) Format (err error) (res []byte) {
if err == nil {
return nil
}
st := newFmtTextState(f)
dn := false
defer func(d *bool, s *FmtTextState) {
if !(*d) {
if e := recover(); e != nil {
panic(e)
f.format(s,NewErrPanic(e).ToTrace(1),true)
res = s.Buffer.Bytes()
}
}
s.Reset()
}(&dn,st)
f.format(st,err,true)
if f.AddStackTrace() {
if tc := UnwrapStackTrace(err); tc != nil {
st.WriteString("\nStack Trace\n")
f.traceFmt(st, tc.StackTrace())
}
}
dn=true
return st.Buffer.Bytes()
}
func (f *FmtText) format (s *FmtTextState, err error, head bool) {
rt := reflect.TypeOf(err)
if rt.Kind() == reflect.Pointer {
err = reflect.ValueOf(err).Elem().Interface().(error)
if err == nil {
return
}
rt = rt.Elem()
}
if head {
s.WriteFieldString("error", err.Error(), FormatColorRed)
s.WriteFieldString("error-type", rt.String())
}
f.getFmtTextProvider(rt).Format(s,err)
ue := Unwrap(err)
for ue != nil {
f.format(s,ue,false)
ue = Unwrap(ue)
}
/*
if c := UnwrapCause(err); c != nil {
s.writeString("-Previous-----------------------------------------\n",[]FormatColor{FormatColorCyan})
s.IncLevel()
f.format(s,c.Cause(),true)
s.DecLevel()
}
*/
}
func (f *FmtText) getFmtTextProvider(rt reflect.Type) FmtTextProvider {
pt := rt.Kind() == reflect.Pointer
if pt {
rt = rt.Elem()
}
if fp,ok := f.providers.Load(rt); ok {
return fp.(FmtTextProvider)
}
var wg sync.WaitGroup
var np FmtTextProvider
wg.Add(1)
fp,ld := f.providers.LoadOrStore(rt, FmtTextProviderFnc(func (s *FmtTextState, err error){
wg.Wait()
np.Format(s,err)
}))
if ld {
return fp.(FmtTextProvider)
}
np = f.buildFmtTextProvider(rt)
wg.Done()
f.providers.Store(rt,np)
return np
}
func (f *FmtText) buildFmtTextProvider (rtype reflect.Type) FmtTextProvider {
if rtype.Kind() == reflect.Pointer {
rtype = rtype.Elem()
}
switch rtype {
case G.errCodeRT : return FmtTextProviderFnc(formatErrCode )
case G.errCauseRT: return FmtTextProviderFnc(formatErrCause)
case G.errTraceRT: return FmtTextProviderFnc(formatErrTrace)
case G.errPanicRT: return FmtTextProviderFnc(formatErrPanic)
case G.errInfoRT : return FmtTextProviderFnc(formatErrInfo )
case G.errGroupRT: return FmtTextProviderFnc(formatErrGroup)
case G.errMultiRT: return FmtTextProviderFnc(formatErrMulti)
default : return FmtTextProviderFnc(formatErrAny)
}
}
func formatErrCode (s *FmtTextState, e error) {
//s.WriteFieldString("error-code",e.(ErrCode).Code())
}
func formatErrPanic (s *FmtTextState, e error ){
//s.WriteFieldString("error-panic",e.(ErrPanic).Error())
}
func formatErrTrace (s *FmtTextState, e error) {
s.WriteTrace (e.(ErrTrace).StackTrace())
//s.WriteFieldString("error-Trace",e.(ErrTrace).Error())
}
func formatErrCause (s *FmtTextState, e error) {
s.WriteCause(e.(ErrCause).Cause())
}
func formatErrGroup (s *FmtTextState, e error) {
i := 0
e.(ErrGroup).Map(func(err error) bool {
i++
s.Buffer.WriteString("** Error Group (")
s.Buffer.WriteString(strconv.Itoa(i))
s.Buffer.WriteString(") ********************\n")
s.fmt.format(s,err,true)
return true
})
}
func formatErrMulti (s *FmtTextState, e error) {
i := 0
e.(ErrMulti).Map(func(err error) bool {
i++
s.Buffer.WriteString("** Multiple errors (")
s.Buffer.WriteString(strconv.Itoa(i))
s.Buffer.WriteString(") ********************\n")
s.fmt.format(s,err,true)
return true
})
}
func formatErrInfo (s *FmtTextState, e error) {
ei := e.(ErrInfo)
s.WriteFieldString("message" ,ei.Message())
s.WriteFieldString("info" ,ei.Info ())
if s.Level() == 0 {
s.WriteFieldTime("date-time",ei.Date(), FormatColorRed, FormatColorMagenta)
ei.MapMetas(func(n string, v any) bool {
s.WriteFieldString(n,fmt.Sprintf("%v",v))
return true
})
}
}
func formatErrAny (s *FmtTextState, err error) {
//s.WriteFieldString("error",err.Error())
}
func formatStackTrace(s *FmtTextState, t StackTrace) {
/*
for _,f := range t.Frames() {
s.WriteString(f.Package+"."+f.FuncName, FormatColorYellow)
s.WriteString(fmt.Sprintf(" %.90s:%d",f.File,f.LineNumber), FormatColorBlue)
if sc,er := f.SourceLine(); er == nil {
if len(sc) > 80 {
//ls := typex.SplitString(sc,70)
for _,l := range ls {
s.Buffer.WriteString(FormatColorMagenta.BeginColorString())
s.Buffer.WriteString(" ")
s.Buffer.WriteString(l)
s.Buffer.WriteByte('\n')
s.Buffer.WriteString(FormatColorMagenta.EndColorString())
}
continue
}
s.Buffer.WriteString(" ")
s.Buffer.WriteString(FormatColorMagenta.Sprintf(sc))
s.Buffer.WriteByte('\n')
}
}
*/
}
func errorHead (s *FmtTextState, e error) {
s.WriteFieldString("error", e.Error(), FormatColorRed)
s.WriteFieldString("error-type", reflect.TypeOf(e).String())
}

Powered by TurnKey Linux.