From 45a3f15e009a89994553ef587707a2de816b3c6d Mon Sep 17 00:00:00 2001 From: kazukousen Date: Tue, 9 Jan 2024 12:54:34 +0900 Subject: [PATCH 1/4] Fix order of regexp replacement --- pperr_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pperr_test.go b/pperr_test.go index 29453c4..6ba7cb7 100644 --- a/pperr_test.go +++ b/pperr_test.go @@ -50,8 +50,8 @@ func TestFprint(t *testing.T) { pperr.Fprint(&buf, err) actual := buf.String() - actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m)[^\s>]+/pperr_test.go:\d+$`).ReplaceAllString(actual, ".../pperr_test.go:NN") + actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m):\d+$`).ReplaceAllString(actual, ":NN") expected := strings.TrimPrefix(` @@ -113,8 +113,8 @@ func TestFprint_Indent(t *testing.T) { pperr.FprintFunc(&buf, err, pperr.NewPrinterWithIndent(">>")) actual := buf.String() - actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m)[^\s>]+/pperr_test.go:\d+$`).ReplaceAllString(actual, ".../pperr_test.go:NN") + actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m):\d+$`).ReplaceAllString(actual, ":NN") expected := strings.TrimPrefix(` @@ -154,8 +154,8 @@ func TestSprint(t *testing.T) { err := f1(true) actual := pperr.Sprint(err) - actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m)[^\s>]+/pperr_test.go:\d+$`).ReplaceAllString(actual, ".../pperr_test.go:NN") + actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m):\d+$`).ReplaceAllString(actual, ":NN") expected := strings.TrimPrefix(` @@ -195,8 +195,8 @@ func TestSprintFunc(t *testing.T) { err := f1(true) actual := pperr.SprintFunc(err, pperr.NewPrinterWithIndent(">>")) - actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m)[^\s>]+/pperr_test.go:\d+$`).ReplaceAllString(actual, ".../pperr_test.go:NN") + actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m):\d+$`).ReplaceAllString(actual, ":NN") expected := strings.TrimPrefix(` @@ -261,8 +261,8 @@ func TestFprint_WithoutMessage(t *testing.T) { pperr.FprintFunc(&buf, err, pperr.PrinterWithoutMessage) actual := buf.String() - actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m)[^\s>]+/pperr_test.go:\d+$`).ReplaceAllString(actual, ".../pperr_test.go:NN") + actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") actual = regexp.MustCompile(`(?m):\d+$`).ReplaceAllString(actual, ":NN") expected := strings.TrimPrefix(` From bbb4dd60c53da63ef5b92ae0eb70c88dd9dda6f5 Mon Sep 17 00:00:00 2001 From: kazukousen Date: Tue, 9 Jan 2024 12:55:13 +0900 Subject: [PATCH 2/4] Blank unused variable --- printer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/printer.go b/printer.go index 35f831b..edb0436 100644 --- a/printer.go +++ b/printer.go @@ -24,7 +24,7 @@ var DefaultPrinterWithIndent = func(w io.Writer, err error, frames, parent Frame } } -var PrinterWithoutMessage = func(w io.Writer, err error, frames, parent Frames) { +var PrinterWithoutMessage = func(w io.Writer, _ error, frames, parent Frames) { if frames != nil { if parent != nil { frames = frames.Exclude(parent) From 1c37b9795ce0ac7138d75bb142ed0076a9197cb2 Mon Sep 17 00:00:00 2001 From: kazukousen Date: Tue, 9 Jan 2024 12:57:32 +0900 Subject: [PATCH 3/4] Optimize memory allocation --- frame.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame.go b/frame.go index 3481aaa..f99280e 100644 --- a/frame.go +++ b/frame.go @@ -36,7 +36,7 @@ func ExtractFrames(st errors.StackTrace) Frames { } func (frames Frames) Exclude(excludes Frames) Frames { - newFrames := Frames{} + newFrames := make(Frames, 0, len(frames)) L1: for _, f := range frames { From df4ffb506c4e7b40fb3815ebe51e269d06089c77 Mon Sep 17 00:00:00 2001 From: kazukousen Date: Tue, 9 Jan 2024 12:57:51 +0900 Subject: [PATCH 4/4] Split function into Stack Frame Extraction and Printing --- frame.go | 6 ++++++ pperr.go | 22 +++++++++++++++++----- pperr_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/frame.go b/frame.go index f99280e..c9f41a9 100644 --- a/frame.go +++ b/frame.go @@ -6,6 +6,12 @@ import ( "github.com/pkg/errors" ) +type ErrorSet struct { + Error error + Frames Frames + Parent Frames +} + type Frame struct { File string Line int diff --git a/pperr.go b/pperr.go index 4952ad8..21ba22f 100644 --- a/pperr.go +++ b/pperr.go @@ -34,12 +34,18 @@ func Fprint(w io.Writer, err error) { } func FprintFunc(w io.Writer, err error, puts Printer) { - fprintFuncWithParent(w, err, puts, nil) + for _, e := range extractErrorSet(err, nil) { + puts(w, e.Error, e.Frames, e.Parent) + } +} + +func ExtractErrorSet(err error) []ErrorSet { + return extractErrorSet(err, nil) } -func fprintFuncWithParent(w io.Writer, err error, puts Printer, parent Frames) { +func extractErrorSet(err error, parent Frames) []ErrorSet { if err == nil { - return + return nil } realErr := err @@ -53,6 +59,8 @@ func fprintFuncWithParent(w io.Writer, err error, puts Printer, parent Frames) { } } + var errs []ErrorSet + if withCause, ok := realErr.(interface{ Unwrap() error }); ok { var causeParent Frames @@ -62,10 +70,14 @@ func fprintFuncWithParent(w io.Writer, err error, puts Printer, parent Frames) { causeParent = parent } - fprintFuncWithParent(w, withCause.Unwrap(), puts, causeParent) + if es := extractErrorSet(withCause.Unwrap(), causeParent); es != nil { + errs = es + } } - puts(w, err, frames, parent) + errs = append(errs, ErrorSet{Error: err, Frames: frames, Parent: parent}) + + return errs } func CauseType(err error) string { diff --git a/pperr_test.go b/pperr_test.go index 6ba7cb7..76f6a31 100644 --- a/pperr_test.go +++ b/pperr_test.go @@ -42,6 +42,51 @@ func f3(native bool) error { } } +func TestExtractErrorSet(t *testing.T) { + assert := assert.New(t) + + err := f1(true) + + var buf strings.Builder + for _, e := range pperr.ExtractErrorSet(err) { + pperr.DefaultPrinter(&buf, e.Error, e.Frames, e.Parent) + } + actual := buf.String() + actual = regexp.MustCompile(`(?m)[^\s>]+/pperr_test.go:\d+$`).ReplaceAllString(actual, ".../pperr_test.go:NN") + actual = regexp.MustCompile(`(?m)[^\s>]+/go/.*:\d+$`).ReplaceAllString(actual, ".../go/...:NN") + actual = regexp.MustCompile(`(?m):\d+$`).ReplaceAllString(actual, ":NN") + + expected := strings.TrimPrefix(` +syscall.Errno: no such file or directory +*fs.PathError: open not_found: no such file or directory +*errors.withStack: from f3(): open not_found: no such file or directory + github.com/kanmu/pperr_test.f3 + .../pperr_test.go:NN + github.com/kanmu/pperr_test.f23 + .../pperr_test.go:NN + github.com/kanmu/pperr_test.f22 + .../pperr_test.go:NN + github.com/kanmu/pperr_test.f21 + .../pperr_test.go:NN +*xerrors.wrapError: from f23: from f3(): open not_found: no such file or directory +*fmt.wrapError: from f21(): from f23: from f3(): open not_found: no such file or directory +*errors.withStack: from f2(): from f21(): from f23: from f3(): open not_found: no such file or directory + github.com/kanmu/pperr_test.f2 + .../pperr_test.go:NN +*errors.withStack: from f1(): from f2(): from f21(): from f23: from f3(): open not_found: no such file or directory + github.com/kanmu/pperr_test.f1 + .../pperr_test.go:NN + github.com/kanmu/pperr_test.TestExtractErrorSet + .../pperr_test.go:NN + testing.tRunner + .../go/...:NN + runtime.goexit + .../go/...:NN +`, "\n") + + assert.Equal(expected, actual) +} + func TestFprint(t *testing.T) { assert := assert.New(t)