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.
active/core/errs/fmt_text.go

262 lines
5.7 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"
"typex"
)
type (
FmtText struct {
FmtTextAtt
dateLayout string
fixName int
fieldSep string
indent string
fmtField string
traceFmt func(s *FmtTextState, t StackTrace)
providers sync.Map
}
FmtTextFnc func(f *FmtText)
)
func NewFmtText(options ...FmtTextFnc) *FmtText {
fm := applyFmtTextOptions(&FmtText{
FmtTextAtt: FmtTextAttIndent | FmtTextAttVerbose | FmtTextAttTrace | FmtTextAttColors,
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) []byte {
if err == nil {
return nil
}
st := newFmtTextState(f)
dn := false
defer func(d *bool, s *FmtTextState) {
s.Buffer.Reset()
if !(*d) {
e := NewErrPanic(recover())
if e != nil {
s.WriteFieldString("panic",e.Error() )
}
}
}(&dn,st)
f.formatAll(st,err)
if f.AddStackTrace() {
if tc := UnwrapStackTrace(err); st != nil {
st.WriteString("\nStack Trace\n")
f.traceFmt(st, tc.StackTrace())
}
}
dn=true
return st.Buffer.Bytes()
}
func (f *FmtText) formatAll (s *FmtTextState, err error) {
s.WriteFieldString("error",err.Error())
s.WriteFieldString("error-type",reflect.TypeOf(err).String())
ls := UnwrapAll(err)
for _,e := range ls {
f.format(s,e)
}
if c := UnwrapCause(err); c != nil {
s.writeString("-Previous-----------------------------------------\n",[]FmtTextColor{FmtTextColorCyan})
s.IncLevel()
if f.Verbose() {
f.formatAll(s, c.Cause())
} else {
f.format(s,c.Cause())
}
s.DecLevel()
}
}
func (f *FmtText) format (s *FmtTextState, err error) {
rt := reflect.TypeOf(err)
//s.WriteFieldString("error",err.Error())
//s.WriteFieldString("error-type",rt.String())
if rt.Kind() == reflect.Pointer {
rt = rt.Elem()
err = reflect.ValueOf(err).Elem().Interface().(error)
if err == nil {
return
}
}
f.getFmtTextProvider(rt).Format(s,err)
}
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 )
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.WriteFieldString("error-Trace",e.(ErrTrace).Error())
}
func formatErrCause (s *FmtTextState, e error) {
//s.WriteFieldString("error-cause",e.(ErrCause).Error())
}
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(),FmtTextColorRed,FmtTextColorMagenta)
s.WriteFieldTime("date-time",ei.Date(),FmtTextColorGreen)
s.WriteFieldTime("date-time",ei.Date())
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,FmtTextColorYellow)
s.WriteString(fmt.Sprintf(" %.90s:%d",f.File,f.LineNumber),FmtTextColorBlue)
if sc,er := f.SourceLine(); er == nil {
if len(sc) > 80 {
ls := typex.SplitString(sc,80)
for _,l := range ls {
FmtTextColorMagenta.BeginString()
s.Buffer.WriteString(l)
s.Buffer.WriteByte('\n')
FmtTextColorMagenta.EndString()
}
continue
}
s.Buffer.WriteString(" ")
s.Buffer.WriteString(FmtTextColorMagenta.Sprintf(sc))
s.Buffer.WriteByte('\n')
}
}
}

Powered by TurnKey Linux.