From f428bee4015fba34f21f2066a0c776e5d95f0628 Mon Sep 17 00:00:00 2001 From: DEV Date: Mon, 8 Apr 2024 03:11:26 +0200 Subject: [PATCH] incluidas las librerias de transformacion de strings --- app/main.go | 3 +- core/errs/err_info.go | 17 ++-- core/errs/err_param.go | 4 +- core/errs/fmts/active.go | 16 ++++ core/errs/fmts/field_extractor.go | 3 + core/errs/fmts/field_extractors.go | 42 +++++++--- core/errs/fmts/format_builder.go | 11 +-- core/errs/fmts/format_field_builder.go | 41 ++++++++++ core/errs/fmts/ftext/active.go | 78 +++++++++++-------- core/errs/fmts/ftext/field_format.go | 19 +++-- core/errs/fmts/ftext/{fmt.go => formatter.go} | 68 +++++++--------- .../ftext/{section.go => section_format.go} | 13 ++-- core/errs/fmts/ftext/show_option.go | 8 +- core/errs/fmts/ftext/state.go | 56 ++++++++----- 14 files changed, 240 insertions(+), 139 deletions(-) create mode 100644 core/errs/fmts/format_field_builder.go rename core/errs/fmts/ftext/{fmt.go => formatter.go} (69%) rename core/errs/fmts/ftext/{section.go => section_format.go} (87%) diff --git a/app/main.go b/app/main.go index 0cd283e..48d1a2a 100644 --- a/app/main.go +++ b/app/main.go @@ -1,7 +1,6 @@ package main import ( - "errors" "errs" "errs/stack" "fmt" @@ -63,7 +62,7 @@ func main() { e := errs.ErrCode("Mi-Error") i := errs.NewErrInfo(e, errs.ErrInfoWithMessage("Esto es un mensage"), - errs.ErrInfoWithCause(errors.New("Un error desconocido")), + errs.ErrInfoWithCause(MiCustomErr{}), errs.ErrInfoWithStackTrace(2), ) diff --git a/core/errs/err_info.go b/core/errs/err_info.go index afcf205..e1d8821 100644 --- a/core/errs/err_info.go +++ b/core/errs/err_info.go @@ -102,14 +102,17 @@ func (e ErrInfo) BuildFormat (builder fmts.FormatBuilder) { builder.AddCode(e.Error()) builder.AddType("core.errs.ErrInfo") - 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.AddFields(func(fb fmts.FormatFieldBuilder){ + fb.AddFieldString("message",e.message) + fb.AddFieldString("info",e.info) + fb.AddFieldTime ("date",e.date) + if len(e.metas) > 0 { + for n,v := range e.metas { + fb.AddFieldString(n,v) + } } - } + }) + } diff --git a/core/errs/err_param.go b/core/errs/err_param.go index 0906870..716aa70 100644 --- a/core/errs/err_param.go +++ b/core/errs/err_param.go @@ -83,6 +83,8 @@ func (e ErrParam) BuildFormat (builder fmts.FormatBuilder) { builder.AddCode(e.code) builder.AddType("core.errs.ErrParam") if len(e.message) > 0 { - builder.AddFieldString(fmts.FieldNameMessage, e.message) + builder.AddFields(func (fb fmts.FormatFieldBuilder) { + fb.AddFieldString(fmts.FieldNameMessage, e.message) + }) } } diff --git a/core/errs/fmts/active.go b/core/errs/fmts/active.go index 37487a8..31df912 100644 --- a/core/errs/fmts/active.go +++ b/core/errs/fmts/active.go @@ -25,6 +25,10 @@ package fmts +const ( + innerErrorNil = "invalid-inner-error" +) + const ( CodeBuilderError string = "format-builder-error" @@ -50,3 +54,15 @@ var ( ) + + +func safeCallToError(err error) (s string) { + dn := false + defer func(d *bool) { + if !(*d) { + recover() + s = innerErrorNil + } + }(&dn) + return err.Error() +} \ No newline at end of file diff --git a/core/errs/fmts/field_extractor.go b/core/errs/fmts/field_extractor.go index 622acf8..0b17c17 100644 --- a/core/errs/fmts/field_extractor.go +++ b/core/errs/fmts/field_extractor.go @@ -23,6 +23,7 @@ package fmts + type ( @@ -39,3 +40,5 @@ func (f FieldExtractorFnc) Extract (builder FormatBuilder, err error) bool { return f(builder,err) } + + diff --git a/core/errs/fmts/field_extractors.go b/core/errs/fmts/field_extractors.go index 0bce709..e43dcf5 100644 --- a/core/errs/fmts/field_extractors.go +++ b/core/errs/fmts/field_extractors.go @@ -23,7 +23,10 @@ package fmts -import "time" +import ( + "reflect" + "time" +) type ( @@ -75,18 +78,23 @@ func (l FieldExtractors) BuildAndCreate (builder FormatBuilder, err error) Field func (l FieldExtractors) build (builder FormatBuilder, err error) { - builder.AddCode(err.Error()) + builder.AddCode(safeCallToError(err)) + builder.AddType(reflect.TypeOf(err).String()) } + + func DefaultsExtractors () FieldExtractors { return []FieldExtractor{ FieldExtractorFnc(func (b FormatBuilder, e error) bool { if ms,is := e.(interface { Code() string }); is { - b.AddFieldString(FieldNameCode,ms.Code()) + b.AddFields(func (fb FormatFieldBuilder) { + fb.AddFieldString(FieldNameCode, ms.Code()) + }) return true } return false @@ -94,49 +102,63 @@ func DefaultsExtractors () FieldExtractors { FieldExtractorFnc(func (b FormatBuilder, e error) bool { if ms,is := e.(interface { Message() string }); is { - b.AddFieldString(FieldNameMessage,ms.Message()) + b.AddFields(func (fb FormatFieldBuilder) { + fb.AddFieldString(FieldNameMessage, ms.Message()) + }) return true } return false }), FieldExtractorFnc(func (b FormatBuilder, e error) bool { if in,is := e.(interface { Info () string }); is { - b.AddFieldString(FieldNameInfo,in.Info()) + b.AddFields(func (fb FormatFieldBuilder){ + fb.AddFieldString(FieldNameInfo,in.Info()) + }) return true } return false }), FieldExtractorFnc(func (b FormatBuilder, e error) bool { if tm,is := e.(interface { Time() time.Time }); is { - b.AddFieldTime(FieldNameTime,tm.Time()) + b.AddFields(func (fb FormatFieldBuilder) { + fb.AddFieldTime(FieldNameTime, tm.Time()) + }) return true } return false }), FieldExtractorFnc(func (b FormatBuilder, e error) bool { if tm,is := e.(interface { Date() time.Time }); is { - b.AddFieldDate(FieldNameDate,tm.Date()) + b.AddFields(func (fb FormatFieldBuilder) { + fb.AddFieldDate(FieldNameDate, tm.Date()) + }) return true } return false }), FieldExtractorFnc(func (b FormatBuilder, e error) bool { if tm,is := e.(interface { Param() string }); is { - b.AddFieldString(FieldNameParam,tm.Param()) + b.AddFields(func (fb FormatFieldBuilder) { + fb.AddFieldString(FieldNameParam, tm.Param()) + }) return true } return false }), FieldExtractorFnc(func (b FormatBuilder, e error) bool { if tm,is := e.(interface { User() string }); is { - b.AddFieldString(FieldNameUser,tm.User()) + b.AddFields(func (fb FormatFieldBuilder) { + fb.AddFieldString(FieldNameUser, tm.User()) + }) return true } return false }), FieldExtractorFnc(func (b FormatBuilder, e error) bool { if tm,is := e.(interface { Source() string }); is { - b.AddFieldString(FieldNameSource,tm.Source()) + b.AddFields(func (fb FormatFieldBuilder) { + fb.AddFieldString(FieldNameSource, tm.Source()) + }) return true } return false diff --git a/core/errs/fmts/format_builder.go b/core/errs/fmts/format_builder.go index 9b1e99b..fd67c96 100644 --- a/core/errs/fmts/format_builder.go +++ b/core/errs/fmts/format_builder.go @@ -23,10 +23,6 @@ package fmts -import ( - "time" -) - type ( FormatBuilder interface { @@ -35,12 +31,7 @@ type ( AddCode (code string) AddType (ter string ) - AddFieldString (name string, value string ) - AddFieldInt (name string, value int ) - AddFieldFloat (name string, value float64 ) - AddFieldTime (name string, value time.Time) - AddFieldDate (name string, value time.Time) - + AddFields (func (fieldBuilder FormatFieldBuilder)) } ) diff --git a/core/errs/fmts/format_field_builder.go b/core/errs/fmts/format_field_builder.go new file mode 100644 index 0000000..6b7f97f --- /dev/null +++ b/core/errs/fmts/format_field_builder.go @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name format_field_builder.go +// Created by DEV +// Modified 08/04/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 fmts + +import "time" + +type ( + + FormatFieldBuilder interface { + AddString (str string) + + AddFieldString (name string, value string ) + AddFieldInt (name string, value int ) + AddFieldFloat (name string, value float64 ) + AddFieldTime (name string, value time.Time) + AddFieldDate (name string, value time.Time) + } +) + + diff --git a/core/errs/fmts/ftext/active.go b/core/errs/fmts/ftext/active.go index 3c1149f..2d7ce21 100644 --- a/core/errs/fmts/ftext/active.go +++ b/core/errs/fmts/ftext/active.go @@ -28,6 +28,7 @@ import ( "atypes/astrings" "errs/fmts" "errs/stack" + "fmt" "sync" ) @@ -56,65 +57,78 @@ var ( G = struct { buildDefault sync.Once - fmtDefault *FmtText + fmtDefault *Formatter }{ } ) -func DefaultFormatter () *FmtText { +func DefaultFormatter () *Formatter { + c := ansi.Code(0).SetFgColor(ansi.ColorHRed).SetStyle(ansi.StyleBold) + G.buildDefault.Do(func() { + G.fmtDefault = NewFmtText( - WithFieldFormat("*",FieldFormat{ - nameTrans: []astrings.Transform{ - astrings.ToKebab, - func(s string) string { return astrings.Pad(s,14,' ',true) }, - }, + //WithShowOptions(ShowAnsi,false), + WithFieldFormat("*",func (fld *FieldFormat) { + fld.NameTrans = []astrings.Transform{ + astrings.ToKebab, + func(s string) string { return astrings.Pad(s,14,' ',true) }, + } + }), + WithFieldFormat("error", func (fm *FieldFormat){ + fm.NameAnsi = c + fm.ValueAnsi = c + fm.ValueTrans = []astrings.Transform {astrings.ToKebab } + fm.BuildAfter = func(b fmts.FormatBuilder){ + b.AddString("-------------------------------------") + } }), - WithFieldFormat("error",FieldFormat{ - nameAnsi : ansi.Code(0).SetFgColor(ansi.ColorGreen).SetStyle(ansi.StyleBold) , - valueTrans : []astrings.Transform {astrings.ToKebab }, + WithSectionFormat(ErrorSection, func (sec *SectionFormat) { + sec.BuildBefore = func (b fmts.FormatBuilder) { + b.AddString("**********************************************************") + } + sec.BuildAfter = sec.BuildBefore }), - WithSection( - ErrorSection, - []string{"**********************************************************"}, - []string{"**********************************************************"}, - ansi.Code(0).SetFgColor(ansi.ColorHRed)), - WithSection( - CauseSection, - []string{"- Prev Cause ---------------"}, - []string(nil), - ansi.Code(0).SetFgColor(ansi.ColorBlue)), - WithSection( - TraceSection, - []string{"\n* Stack Trace Information **"}, - []string(nil), - ansi.Code(0).SetFgColor(ansi.ColorGreen))) + WithSectionFormat(CauseSection, func (sec *SectionFormat) { + sec.BuildBefore = func (b fmts.FormatBuilder) { + b.AddString("- Prev Cause ---------------") + } + }), + WithSectionFormat(TraceSection, func (sec *SectionFormat) { + sec.BuildBefore = func(b fmts.FormatBuilder) { + b.AddString("\n* Stack Trace Information **") + } + })) + }) return G.fmtDefault } -func buildDefaultFrameBuilder (f *FmtText) fmts.FrameFormatBuilder { +func buildDefaultFrameBuilder (f *Formatter) fmts.FrameFormatBuilder { fm := f return fmts.BuildFrameFormatFnc(func (builder fmts.FormatBuilder, frame stack.Frame, num int) { - var c1, c2, c3, c4 ansi.Code + var c1, c2, c3, c4, c5 ansi.Code if fm.ShowAnsi(){ - c1 = c1.SetFgColor(ansi.ColorBlue) + c1 = c1.SetFgColor(ansi.ColorBlue).SetBgColor(ansi.ColorHWhite) c2 = c2.SetFgColor(ansi.ColorMagenta) c3 = c3.SetFgColor(ansi.ColorYellow) c4 = c4.SetFgColor(ansi.ColorRed) + c5 = c5.SetBgColor(ansi.ColorWhite).SetStyle(ansi.StyleBold).SetFgColor(ansi.ColorBlack) } - builder.AddString(c1.Sprintf("%d %s.%s", num, frame.Package, frame.FuncName)) - builder.AddString(c2.Sprintf(" %.90s:%d", frame.File, frame.LineNumber)) + nm := c5.Sprintf(" %d",num) + ln := c1.Sprintf(fmt.Sprintf("%-60s",fmt.Sprintf(" %s.%s", frame.Package, frame.FuncName))) + builder.AddString(fmt.Sprint(nm,ln)) + builder.AddString(c2.Sprintf(" %.90s:%d", frame.File, frame.LineNumber)) f, e := frame.SourceLine() if e == nil { - builder.AddString(c3.Sprintf("%s", f)) + builder.AddString(c3.Sprintf(" %s\n", f)) } else { - builder.AddString(c4.Sprintf("error %s", e.Error())) + builder.AddString(c4.Sprintf("error %s\n", e.Error())) } }) } \ No newline at end of file diff --git a/core/errs/fmts/ftext/field_format.go b/core/errs/fmts/ftext/field_format.go index cbb7384..38c26cc 100644 --- a/core/errs/fmts/ftext/field_format.go +++ b/core/errs/fmts/ftext/field_format.go @@ -26,25 +26,28 @@ package ftext import ( "ansi" "atypes/astrings" + "errs/fmts" ) type ( FieldFormat struct { - nameAnsi ansi.Code - valueAnsi ansi.Code - nameTrans astrings.Transformers - valueTrans astrings.Transformers + NameAnsi ansi.Code + ValueAnsi ansi.Code + NameTrans astrings.Transformers + ValueTrans astrings.Transformers + BuildBefore fmts.FormattableFnc + BuildAfter fmts.FormattableFnc } ) func (f FieldFormat) Clone () FieldFormat { return FieldFormat{ - nameAnsi: f.nameAnsi, - valueAnsi: f.valueAnsi, - nameTrans : append(astrings.Transformers(nil),f.nameTrans...), - valueTrans: append(astrings.Transformers(nil),f.valueTrans...), + NameAnsi: f.NameAnsi, + ValueAnsi: f.ValueAnsi, + NameTrans: append(astrings.Transformers(nil),f.NameTrans...), + ValueTrans: append(astrings.Transformers(nil),f.ValueTrans...), } } diff --git a/core/errs/fmts/ftext/fmt.go b/core/errs/fmts/ftext/formatter.go similarity index 69% rename from core/errs/fmts/ftext/fmt.go rename to core/errs/fmts/ftext/formatter.go index e5c0397..34a2ff6 100644 --- a/core/errs/fmts/ftext/fmt.go +++ b/core/errs/fmts/ftext/formatter.go @@ -24,31 +24,16 @@ package ftext import ( - "ansi" "atypes/astrings" "errs/fmts" "strings" "time" ) -const ( - - FormatShowWrapped uint8 = 1 << iota - FormatShowType - FormatShowColors - FormatShowIndent - FormatShowDetails - FormatShowCause - FormatShowTrace - FormatShowFieldEmpty -) - - - type ( - FmtText struct { + Formatter struct { showOption Indent string @@ -62,7 +47,7 @@ type ( defFieldFormat FieldFormat fieldsFormat map[string]FieldFormat - secs [secsSize]section + secs [secsSize]SectionFormat trans [transSize]astrings.Transformers frameBuilder fmts.FrameFormatBuilder @@ -70,13 +55,13 @@ type ( builders *fmts.TypeFormatBuilders } - FmtTextFnc func (fm *FmtText) + FmtTextFnc func (fm *Formatter) ) -func NewFmtText(options ...FmtTextFnc) *FmtText { - f := &FmtText{ +func NewFmtText(options ...FmtTextFnc) *Formatter { + f := &Formatter{ showOption : showDefault, Indent : " ", FieldSep : " : ", @@ -100,7 +85,7 @@ func NewFmtText(options ...FmtTextFnc) *FmtText { } -func (f *FmtText) Format (err error) []byte { +func (f *Formatter) Format (err error) []byte { if err == nil { return nil } @@ -125,45 +110,48 @@ func (f *FmtText) Format (err error) []byte { } -func (f *FmtText) SetFieldFormat (field string, format FieldFormat) { - if field == "" || field == "*" { - f.defFieldFormat = format - return - } - if f.fieldsFormat == nil { - f.fieldsFormat = make(map[string]FieldFormat) + + +func WithShowOptions (option showOption,enabled bool) FmtTextFnc { + return func(f *Formatter) { + if enabled { + f.showOption |= option + return + } + f.showOption &^=option } - f.fieldsFormat[field]=format } -func WithSection(id int, beginLines, endLines []string, style ansi.Code) FmtTextFnc { + +func WithSectionFormat(id int, config func (s *SectionFormat)) FmtTextFnc { if id < DefaultSection && id > TraceSection { - return func(_ *FmtText){} + return func(_ *Formatter){} } - return func(f *FmtText) { - f.secs[id].bLines = append([]string(nil), beginLines...) - f.secs[id].eLines = append([]string(nil), endLines ...) - f.secs[id].ansi = style + return func(f *Formatter) { + config(&f.secs[id]) } } -func WithFieldFormat(field string, format FieldFormat) FmtTextFnc { - return func(f *FmtText) { +func WithFieldFormat(field string, config func(format *FieldFormat)) FmtTextFnc { + return func(f *Formatter) { if field == "" || field == "*" { - f.defFieldFormat = format + config(&f.defFieldFormat) return } if f.fieldsFormat == nil { f.fieldsFormat = make(map[string]FieldFormat) } + fm := FieldFormat{} + config(&fm) if strings.Index(field,",") == -1 { - f.fieldsFormat[field]=format + f.fieldsFormat[field]=fm return } for _,fn := range strings.SplitAfter(field,",") { - f.fieldsFormat[fn]=format + f.fieldsFormat[fn]=fm } } } + diff --git a/core/errs/fmts/ftext/section.go b/core/errs/fmts/ftext/section_format.go similarity index 87% rename from core/errs/fmts/ftext/section.go rename to core/errs/fmts/ftext/section_format.go index 8a067af..0f7ea6e 100644 --- a/core/errs/fmts/ftext/section.go +++ b/core/errs/fmts/ftext/section_format.go @@ -23,14 +23,17 @@ package ftext -import "ansi" +import ( + "ansi" + "errs/fmts" +) type ( - section struct { - bLines []string - eLines []string - ansi ansi.Code + SectionFormat struct { + BuildBefore fmts.FormattableFnc + BuildAfter fmts.FormattableFnc + Ansi ansi.Code } ) diff --git a/core/errs/fmts/ftext/show_option.go b/core/errs/fmts/ftext/show_option.go index 65d21b4..e6f8a5f 100644 --- a/core/errs/fmts/ftext/show_option.go +++ b/core/errs/fmts/ftext/show_option.go @@ -30,12 +30,12 @@ const ( ShowType ShowAnsi ShowIndent - ShowDetails + ShowFields ShowCause ShowTrace ShowFieldEmpty - showDefault = ShowWrapped | ShowType | ShowAnsi | ShowIndent | ShowDetails | ShowCause | ShowTrace + showDefault = ShowWrapped | ShowType | ShowAnsi | ShowIndent | ShowFields | ShowCause | ShowTrace ) @@ -59,8 +59,8 @@ func (s showOption) ShowAnsi () bool { func (s showOption) ShowIndent () bool { return s&ShowIndent !=0 } -func (s showOption) ShowDetails() bool { - return s&ShowDetails !=0 } +func (s showOption) ShowFields() bool { + return s&ShowFields !=0 } func (s showOption) ShowCause () bool { return s&ShowCause !=0 } diff --git a/core/errs/fmts/ftext/state.go b/core/errs/fmts/ftext/state.go index a89c9e0..4ababc6 100644 --- a/core/errs/fmts/ftext/state.go +++ b/core/errs/fmts/ftext/state.go @@ -39,9 +39,10 @@ import ( type ( fmtTextState struct { - f *FmtText + f *Formatter buffer bytes.Buffer level int + section int indent string error error isWrapped bool @@ -49,7 +50,7 @@ type ( ) -func newFmtTextState(f *FmtText) *fmtTextState { +func newFmtTextState(f *Formatter) *fmtTextState { return &fmtTextState{ f : f } } @@ -146,6 +147,12 @@ func (s *fmtTextState) AddStrings(str []string) { } } +func (s *fmtTextState) AddFields (build func (b fmts.FormatFieldBuilder)) { + if s.f.ShowFields() && build != nil { + build(s) + } +} + func (s *fmtTextState) AddFieldString (name string, value string ) { value = s.f.trans[valuesTrans].Apply(value) @@ -170,20 +177,25 @@ func (s *fmtTextState) AddFieldDate (name string, value time.Time) { func (s *fmtTextState) writeField (name string, value string) { var cn,cv ansi.Code - n := s.f.defFieldFormat.nameTrans.Apply(name) - v := s.f.defFieldFormat.valueTrans.Apply(value) + n := s.f.defFieldFormat.NameTrans.Apply(name) + v := s.f.defFieldFormat.ValueTrans.Apply(value) if s.f.ShowAnsi() { - cn = s.f.defFieldFormat.nameAnsi - cv = s.f.defFieldFormat.valueAnsi + cn = s.f.defFieldFormat.NameAnsi + cv = s.f.defFieldFormat.ValueAnsi } if ff,hs := s.f.fieldsFormat[name]; hs { - n = ff.nameTrans.Apply (n) - v = ff.valueTrans.Apply(v) + n = ff.NameTrans.Apply (n) + v = ff.ValueTrans.Apply(v) if s.f.ShowAnsi() { - cn = ff.nameAnsi - cv = ff.valueAnsi + cn = ff.NameAnsi + cv = ff.ValueAnsi } + defer func(){ + if ff.BuildAfter != nil { + ff.BuildAfter(s) + } + }() } s.buffer.WriteString(s.indent) @@ -191,22 +203,20 @@ func (s *fmtTextState) writeField (name string, value string) { s.buffer.WriteString(cn.Sprint(s.f.FieldSep)) s.buffer.WriteString(cv.Sprint(v)) s.buffer.WriteByte('\n') + + } func (s *fmtTextState) writeSection(sec int, begin bool) { sc := s.f.secs[sec] - var ls []string - if begin { - ls = sc.bLines - } else { - ls = sc.eLines + if begin && sc.BuildBefore != nil { + sc.BuildBefore(s) + return } - if len(ls) > 0 { - for _,l := range ls { - s.writeString(sc.ansi.Sprintln(l)) - } + if sc.BuildAfter != nil { + sc.BuildAfter(s) } } @@ -223,10 +233,14 @@ func (s *fmtTextState) writeString(str string) { func (s *fmtTextState) format (er error) { + if er == nil { + return + } dn := false defer func(d *bool, s *fmtTextState){ if !(*d) { + /* if s.error == nil { var ne error if re := recover(); re != nil { @@ -239,6 +253,8 @@ func (s *fmtTextState) format (er error) { } else { s.error = *fmts.NewErrFormatBuilder(s.error) } + + */ } }(&dn, s) @@ -269,7 +285,7 @@ func (s *fmtTextState) format (er error) { s.addCause(cs.Cause()) } - if s.level == 0 { + if s.level == 0 && !s.isWrapped { s.addTrace(stack.UnwrapTrace(er,true)) if !s.isWrapped { s.writeSection(ErrorSection, false)