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

235 lines
5.0 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"
"sync"
"time"
)
type (
FmtText struct {
FmtTextAtt
indent string
traceFmt func(s *FmtTextState, t StackTrace)
providers sync.Map
}
FmtTextFnc func(f *FmtText)
)
func NewFmtText(options ...FmtTextFnc) *FmtText {
return applyFmtTextOptions(&FmtText{
FmtTextAtt: FmtTextAttIndent | FmtTextAttVerbose | FmtTextAttTrace,
indent : " ",
traceFmt : formatStackTrace ,
}, options...) }
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) {
ls := UnwrapAll(err)
for _,e := range ls {
f.format(s,e)
}
if c := UnwrapCause(err); c != nil {
s.WriteString("\n")
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)
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.WriteFieldString( "date-time", ei.Date().Format(time.RFC822Z))
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.Buffer.WriteString(f.Package)
s.Buffer.WriteByte(':')
s.Buffer.WriteString(f.FuncName)
s.Buffer.WriteByte('\n')
s.Buffer.WriteByte('\t')
s.Buffer.WriteString(f.File)
s.Buffer.WriteByte(':')
s.Buffer.WriteString(fmt.Sprintf("%d\n",f.LineNumber))
if sc,er := f.SourceLine(); er == nil {
s.Buffer.WriteString(ColorMagenta.Sprint(sc))
//s.Buffer.WriteString(fmt.Sprintf("\t\x1b[%dm%s\x1b[0m\b\n", uint8(Green), sc))
//s.Buffer.WriteByte('\t')
//s.Buffer.WriteString(sc)
//s.Buffer.WriteByte('\n')
}
}
}

Powered by TurnKey Linux.