diff --git a/app/main.go b/app/main.go index 1978a55..a57da92 100644 --- a/app/main.go +++ b/app/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "errs" "fmt" ) @@ -34,52 +35,26 @@ func (m MiCustomErr) Unwrap () error { func main() { - - - //var MC MiCustomErr - - //errs.G.Formatter.(*errs.FmtText).SetErrorFormatter(reflect.TypeOf(MC),fm) - - eA := errs.ErrCode("1") - eB := errs.ErrCode("2")//.ToErrTrace(0) - eC := eA.ToErrCause( - eB.ToErrInfo(errs.ErrInfoWithCause(errs.ErrCode("--ARRROR---").ToErrInfo(errs.ErrInfoWithMessage("Mi Mensage"), - errs.ErrInfoWithStackTrace(3))))) - eM := errs.MakeErrMulti(MiCustomErr{ - error: errs.NewErrInfo(eC, - errs.ErrInfoWithMessage("Esto es el mensaje"), - errs.ErrInfoWithInfo ("Informacion del error"), - errs.ErrInfoWithMeta("Mi-Meta",3434), - errs.ErrInfoWithMeta("Tu-Meta",22.34)), - Link : "mi-enlacea", - }, - errs.ErrCode("Otros errrores")) - - - fmt.Print(string(errs.G.Formatter.Format(eM))) - - -/* - ercode := errs.ErrCode("err-code") + ercode := errs.ErrCode("error->err-code") fmt.Print(ercode.String()) fmt.Print("\n") - erpanic := errs.NewErrPanic("err-mensaje-panico") + erpanic := errs.NewErrPanic("error->err-mensaje-panico") fmt.Print(erpanic.String()) fmt.Print("\n") - ercause := ercode.ToErrCause(errs.ErrCode("err-code-with-cause")) + ercause := ercode.ToErrCause(errs.ErrCode("error->err-code-with-cause")) fmt.Print(ercause.String()) fmt.Print("\n") - erInfo := errs.ErrCode("err-code-with-info").ToErrInfo(errs.ErrInfoWithMessage("Esto es un mensaje")) + erInfo := errs.ErrCode("err-code-with-info").ToErrInfo(errs.ErrInfoWithMessage("Esto es un mensaje")) fmt.Print(erInfo.String()) fmt.Print("\n") - ertrace := errs.ErrCode("err-code-with-trace").ToErrTrace(0) - fmt.Print(ertrace.String()) - fmt.Print("\n") - -*/ + /* + ertrace := errs.ErrCode("err-code-with-trace").ToErrTrace(0) + fmt.Print(ertrace.String()) + fmt.Print("\n") + */ } diff --git a/core/errs/active.go b/core/errs/active.go index 23cb6b6..dbed57c 100644 --- a/core/errs/active.go +++ b/core/errs/active.go @@ -52,6 +52,8 @@ var ( ErrParamNil ErrCode ErrParamInvalid ErrCode ErrParamOutOfRange ErrCode + ErrFormat ErrCode + ErrFormatLevel ErrCode errCodeRT reflect.Type errCauseRT reflect.Type @@ -64,13 +66,15 @@ var ( stackTraceRType reflect.Type }{ - //Formatter : NewFmtText(), + Formatter : NewFormatText(), ErrGroup : ErrCode("group-error"), ErrPanic : ErrCode("panic-error"), ErrParamNil : ErrCode("param-nil"), ErrParamInvalid : ErrCode("param-invalid"), ErrParamOutOfRange : ErrCode("param-out-of-range"), + ErrFormat : ErrCode("format-error"), + ErrFormatLevel : ErrCode("format-invalid-level"), stackTraceRType : reflect.TypeOf(StackTrace(nil)), diff --git a/core/errs/err_cause.go b/core/errs/err_cause.go index ec0a6fc..7019509 100644 --- a/core/errs/err_cause.go +++ b/core/errs/err_cause.go @@ -53,10 +53,17 @@ func (e ErrCause) Cause () error { return e.cause } +func (e ErrCause) String () string { + return string(G.Formatter.Format(e)) } -func (e ErrCause) Format (builder FormatBuilder) { + +func (e ErrCause) BuildFormat (builder FormatBuilder) { builder.AddCode(e.Error()) builder.AddType("core.errs.ErrCause") + + builder.AddWrapped(e.error) builder.AddCause(e.cause) } + + diff --git a/core/errs/err_code.go b/core/errs/err_code.go index 9a4cf13..688a74d 100644 --- a/core/errs/err_code.go +++ b/core/errs/err_code.go @@ -49,11 +49,19 @@ func (_ ErrCode) UnwrapAll() []error { return nil } +func (e ErrCode) String () string { + return string(G.Formatter.Format(e)) } - -func (e ErrCode) Format (builder FormatBuilder) { +func (e ErrCode) BuildFormat (builder FormatBuilder) { builder.AddCode(string(e)) builder.AddType("core.errs.ErrCode") } + +func (e ErrCode) ToErrCause (cause error) ErrCause { + return *NewErrCause(e,cause) } + +func (e ErrCode) ToErrInfo (options ...ErrInfoFnc) ErrInfo { + return *NewErrInfo(e,options...) +} diff --git a/core/errs/err_info.go b/core/errs/err_info.go index 186a658..7fe07ee 100644 --- a/core/errs/err_info.go +++ b/core/errs/err_info.go @@ -80,46 +80,32 @@ func (e ErrInfo) Unwrap () error { +func (e ErrInfo) String () string { + return string(G.Formatter.Format(e)) } + -func (e ErrInfo) Format (builder FormatBuilder) { - o := builder.Options() - n := e.Unwrap() - if !o.ShowWrapped() { - e.formatWrapped(builder, n) - return - } +func (e ErrInfo) BuildFormat (builder FormatBuilder) { builder.AddCode(e.Error()) builder.AddType("core.errs.ErrInfo") - e.formatWrapped(builder, n) - - if o.ShowCause() { - if c := UnwrapCause(n); c != nil { - builder.AddCause(c) - } - } - if o.ShowTrace() { - if t := UnwrapTrace(n); t != nil { - builder.AddTrace(t) + builder.AddFieldString("message",e.message) + builder.AddFieldString("info",e.info) + builder.AddFieldTime ("date",e.date) + if len(e.metas) > 0 { + for n,v := range e.metas { + builder.AddFieldString(n,v) } } + builder.AddWrapped (e.error) + builder.AddCause(UnwrapCause(e)) + builder.AddTrace(UnwrapTrace(e)) } -func (e ErrInfo) formatWrapped (builder FormatBuilder, next error) { - if builder.Options().ShowDetails() { - builder.AddFieldString("message",e.message) - builder.AddFieldString("info",e.info) - builder.AddFieldTime ("date",e.date) - if len(e.metas) > 0 { - for n,v := range e.metas { - builder.AddFieldString(n,v) - } - } - if next != nil { - builder.AddWrapped(next) - } - } -} + + + +func (e ErrInfo) ToErrCause (cause error) ErrCause { + return *NewErrCause(e,cause) } diff --git a/core/errs/err_panic.go b/core/errs/err_panic.go index 50f7677..706624a 100644 --- a/core/errs/err_panic.go +++ b/core/errs/err_panic.go @@ -46,9 +46,13 @@ func (e ErrPanic) Unwrap () error { return e.error } +func (e ErrPanic) String () string { + return string(G.Formatter.Format(e)) } -func (e ErrPanic) Format (builder FormatBuilder) { - builder.AddCode(e.Error()) - builder.AddType("core.errs.ErrPanic") +func (e ErrPanic) BuildFormat (builder FormatBuilder) { + builder.AddCode (e.Error()) + builder.AddType ("core.errs.ErrPanic") + + builder.AddWrapped(e.error) } \ No newline at end of file diff --git a/core/errs/fomat_builder.go b/core/errs/fomat_builder.go index 04643b5..4a8461f 100644 --- a/core/errs/fomat_builder.go +++ b/core/errs/fomat_builder.go @@ -47,12 +47,11 @@ type ( AddTrace (trace StackTrace, options ...FormatOpsFnc) AddString (str string, options ...FormatOpsFnc) - AddStringLn (str string, options ...FormatOpsFnc) + AddStrings (str []string, options ...FormatOpsFnc) AddFieldString (name string, value string , options ...FormatOpsFnc) AddFieldInt (name string, value int , options ...FormatOpsFnc) AddFieldFloat (name string, value float64 , options ...FormatOpsFnc) - AddFieldDate (name string, value time.Time, options ...FormatOpsFnc) AddFieldTime (name string, value time.Time, options ...FormatOpsFnc) } diff --git a/core/errs/format_ops.go b/core/errs/format_ops.go index 5d8c083..9711552 100644 --- a/core/errs/format_ops.go +++ b/core/errs/format_ops.go @@ -23,6 +23,10 @@ package errs +import ( + "time" + "typex" +) type ( @@ -30,24 +34,34 @@ type ( FormatShow Indent string - DateLayout string + FieldSep string + TimeLayout string + IntLayout string + FloatLayout string Color FormatColor CodeColor FormatColor FieldNameColor FormatColor FieldValueColor FormatColor - FieldNameAdapter func(string) string + StringAdapters typex.StringAdapters + ValueAdapters typex.StringAdapters + NameAdapters typex.StringAdapters } - FormatOpsFnc func (ops *FormatOps) + FormatOpsFnc func (ops any) ) func NewFormatOps (options ...FormatOpsFnc) *FormatOps { os := &FormatOps { + Indent : " ", + FieldSep : " : ", + TimeLayout : time.RFC822Z, + IntLayout : "%d", + FloatLayout: "%-10s: %.2f", } for _,o := range options { o(os) diff --git a/core/errs/format_text.go b/core/errs/format_text.go index 0fc2729..29f4cbd 100644 --- a/core/errs/format_text.go +++ b/core/errs/format_text.go @@ -23,12 +23,10 @@ package errs - - type ( - FormatText struct { - options *FormatTextOps + FormatText struct { + options *FormatTextOps } ) @@ -43,41 +41,32 @@ func NewFormatText (options ...any) *FormatText { } -func (f *FormatText) Format (err error) (r []byte) { +func (f *FormatText) Format (err error) []byte { if err == nil { return nil } - dn := false st := newFormatTextState (f.options) + defer st.Reset() - defer func(d *bool, s *formatTextState){ - st.Reset() - if !(*d) { - if e := NewErrPanic(recover()); e != nil { - e.Format() - } - } - }(&dn,st) + st.format(err) + if st.error != nil { + e := st.error + //st.Reset() + st.format(e) + } + return st.Bytes() +} - if bl,is := err.(Formattable); is { - bl.Build(st) - } else { - f.build (st,err) - } - dn = true -} -func (f *FormatText) build (s *formatTextState, err error) { -} diff --git a/core/errs/format_text_ops.go b/core/errs/format_text_ops.go index fc42689..3aa07e9 100644 --- a/core/errs/format_text_ops.go +++ b/core/errs/format_text_ops.go @@ -23,32 +23,62 @@ package errs - +import ( + "time" + "typex" +) type ( FormatTextOps struct { - FormatOps + FormatShow + + Indent string + FieldSep string + + TimeLayout string + IntLayout string + FloatLayout string + + Color FormatColor + CodeColor FormatColor + FieldNameColor FormatColor + FieldValueColor FormatColor + + StringAdapters typex.StringAdapters + ValueAdapters typex.StringAdapters + NameAdapters typex.StringAdapters } FormatTextOpsFnc func (ops *FormatTextOps) ) -func NewFormatTextOps (options ...any) *FormatTextOps { +func NewFormatTextOps (options ...FormatTextOpsFnc) *FormatTextOps { os := &FormatTextOps { - FormatOps: *NewFormatOps(), + Indent : " ", + FieldSep : " : ", + + TimeLayout : time.RFC822Z, + IntLayout : "%d", + FloatLayout: "%-10s: %.2f", } - for i,o := range options { - switch t := o.(type) { - case func(ops *FormatTextOps): t(os) - case func(ops *FormatOps) : t(&os.FormatOps) - default: - //todo errPanic invalid parameter - } + for _,o := range options { + o(os) } return os } + +func (o *FormatTextOps) Clone (options ...FormatTextOpsFnc) *FormatTextOps { + if len(options) == 0 { + return o + } + no := *o + for _,op := range options { + op(&no) + } + return &no +} diff --git a/core/errs/format_text_state.go b/core/errs/format_text_state.go index 2384860..a534cec 100644 --- a/core/errs/format_text_state.go +++ b/core/errs/format_text_state.go @@ -25,13 +25,15 @@ package errs import ( "bytes" + "fmt" + "reflect" "time" ) type ( formatTextState struct { - options *FormatTextOps + options FormatTextOps buffer bytes.Buffer level int error error @@ -41,7 +43,7 @@ type ( func newFormatTextState (options *FormatTextOps) *formatTextState { st := &formatTextState{ - options : options, + options : *options, } return st } @@ -54,7 +56,13 @@ func newFormatTextState (options *FormatTextOps) *formatTextState { func (f *formatTextState) Options() FormatOps { return f.options.FormatOps } -func (f *formatTextState) Reset () {} +func (f *formatTextState) Reset () { + f.buffer.Reset() + f.level = 0 + f.error = nil +} + + func (f *formatTextState) Level () int { return f.level } @@ -66,24 +74,146 @@ func (f *formatTextState) Error () error { func (f *formatTextState) Bytes () []byte { return f.buffer.Bytes() } -func (f *formatTextState) AddError (err error, options ...FormatOpsFnc) {} -func (f *formatTextState) AddCause (err error, options ...FormatOpsFnc) {} -func (f *formatTextState) AddWrapped(err error, options ...FormatOpsFnc) {} -func (f *formatTextState) AddCode (code string, options ...FormatOpsFnc) {} -func (f *formatTextState) AddType (ter string , options ...FormatOpsFnc) {} +func (f *formatTextState) AddError (err error, options ...FormatOpsFnc) { + if err == nil { + return + } +} + +func (f *formatTextState) AddCause (err error, options ...FormatOpsFnc) { + if err == nil || !f.options.ShowCause() { + return + } + +} + +func (f *formatTextState) AddTrace (trace StackTrace, options ...FormatOpsFnc) { + if trace == nil || !f.options.ShowTrace() { + return + } +} + +func (f *formatTextState) AddWrapped(err error, options ...FormatOpsFnc) { + if err == nil || !f.options.ShowWrapped() { + return + } +} + + +func (f *formatTextState) AddCode (code string, options ...FormatOpsFnc) { + f.writeField("error",f.options.ValueAdapters.Apply(code),options...) } + +func (f *formatTextState) AddType (ter string , options ...FormatOpsFnc) { + f.writeField("error-type",ter, options ...) } + + + + +func (f *formatTextState) AddString (str string, options ...FormatOpsFnc) { + f.writeString(f.options.StringAdapters.Apply(str),options...) +} + +func (f *formatTextState) AddStrings(str []string, options ...FormatOpsFnc) { + for _,s := range str { + f.writeString(f.options.StringAdapters.Apply(s)) + } +} + + +func (f *formatTextState) AddFieldString (name string, value string , options ...FormatOpsFnc) { + value = f.options.ValueAdapters.Apply(value) + if len(value) == 0 && !f.options.ShowFieldEmpty() { + return + } + f.writeField(name,value) } + +func (f *formatTextState) AddFieldInt (name string, value int , options ...FormatOpsFnc) { + f.writeField(name,fmt.Sprintf(f.options.IntLayout,value),options...) } + +func (f *formatTextState) AddFieldFloat (name string, value float64 , options ...FormatOpsFnc) { + f.writeField(name,fmt.Sprintf(f.options.FloatLayout,value),options ...) } + +func (f *formatTextState) AddFieldTime (name string, value time.Time, options ...FormatOpsFnc) { + f.writeField(name,value.Format(f.options.TimeLayout),options ...) } + + + +func (f *formatTextState) writeField (name string, value string, options ...FormatOpsFnc) { + name = f.options.NameAdapters.Apply (name) + if !f.options.ShowColors() { + f.writeString(name) + f.writeString(f.options.FieldSep) + f.writeString(value) + f.buffer.WriteString("\n") + } +} + + +func (f *formatTextState) writeString(str string, options ...FormatOpsFnc) { + f.buffer.WriteString(str) +} + + + + + +func (f *formatTextState) format (er error) { + dn := false + defer func(d *bool, s *formatTextState){ + if !(*d) { + if s.error == nil { + s.error = NewErrCause(G.ErrFormat,NewErrPanic(recover())) + } else { + s.error = NewErrCause(G.ErrFormat,s.error) + } + } else if s.level != 0 { + s.error = G.ErrFormatLevel + } + }(&dn,f) -func (f *formatTextState) AddTrace (trace StackTrace, options ...FormatOpsFnc) {} + if fm,is := er.(Formattable); is { + fm.BuildFormat(f) + } else { + f.build(er) + } + dn=true +} + + + + +func (f *formatTextState) build (er error) { + rt := reflect.TypeOf(er) + if rt.Kind() == reflect.Pointer { + er = reflect.ValueOf(er).Elem().Interface().(error) + if er == nil { + return + } + rt = rt.Elem() + } + + f.AddCode(er.Error()) + f.AddType(rt.String()) + + if ms,is := er.(interface { Message() string }); is { + f.AddFieldString("message",ms.Message()) + } + if in,is := er.(interface { Info () string }); is { + f.AddFieldString("info",in.Info()) + } + if tm,is := er.(interface { Time() time.Time }); is { + f.AddFieldTime("time",tm.Time()) + } + + + f.AddWrapped(Unwrap(er)) + f.AddCause(UnwrapCause(er)) + f.AddTrace(UnwrapTrace(er)) +} -func (f *formatTextState) AddString (str string, options ...FormatOpsFnc) {} -func (f *formatTextState) AddStringLn (str string, options ...FormatOpsFnc) {} -func (f *formatTextState) AddFieldString (name string, value string , options ...FormatOpsFnc) {} -func (f *formatTextState) AddFieldInt (name string, value int , options ...FormatOpsFnc) {} -func (f *formatTextState) AddFieldFloat (name string, value float64 , options ...FormatOpsFnc) {} -func (f *formatTextState) AddFieldDate (name string, value time.Time, options ...FormatOpsFnc) {} -func (f *formatTextState) AddFieldTime (name string, value time.Time, options ...FormatOpsFnc) {} diff --git a/core/errs/formattable.go b/core/errs/formattable.go index c881844..03b6da3 100644 --- a/core/errs/formattable.go +++ b/core/errs/formattable.go @@ -28,7 +28,7 @@ type ( Formattable interface { - Build (builder FormatBuilder) + BuildFormat (builder FormatBuilder) } @@ -37,7 +37,7 @@ type ( ) -func (f FormattableFnc) Build (builder FormatBuilder) { +func (f FormattableFnc) BuildFormat (builder FormatBuilder) { f(builder) } diff --git a/core/typex/string.go b/core/typex/string.go index e372e7b..95ca329 100644 --- a/core/typex/string.go +++ b/core/typex/string.go @@ -25,6 +25,8 @@ package typex + + func SplitString (source string, size int) []string { var lines []string for i := 0; i < len(source); i += size { diff --git a/core/typex/string_adapter.go b/core/typex/string_adapter.go new file mode 100644 index 0000000..8333735 --- /dev/null +++ b/core/typex/string_adapter.go @@ -0,0 +1,48 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name string_adapter.go +// Created by DEV +// Modified 31/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 typex + + + +type ( + + StringAdapter func (string) string + + + StringAdapters []StringAdapter +) + + + +func (a StringAdapters) Apply (value string) string { + if len(a) == 0 { + return value + } + s := value + for _,f := range a { + s = f(s) + } + return s +} +