From c03a0c749d9f66b1ab437a278abe6361b0007af1 Mon Sep 17 00:00:00 2001 From: David Hartunian Date: Tue, 1 Aug 2023 09:57:14 -0400 Subject: [PATCH] add formatting for multi-cause errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, error formatting logic was based on a single linear chain of causality. Error causes would be printed vertically down the page, and their interpretation was natural. This commit adds multi-cause formatting support with two goals in mind: 1. Preserve output exactly as before for single-cause error chains 2. Format multi-errors in a way that preserves the existing vertical layout style. For non-verbose error display (`.Error()`, `%s`, `%v`) there are no changes implemented here. We rely on the error's own display logic and typically a multi-cause error will have a message within that has been constructed from all of its causes during instantiation. For verbose error display (`%+v`) which relies on object introspection, whenever we encounter a multi-cause error in the chain, we mark that subtree as being displayed with markers for the "depth" of various causes. All child errors of the parent, will be at depth "1", their child errors will be at depth "2", etc. During display, we indent the error by its "depth" and add a `└─` symbol to illustrate the parent/child relationship. Example: Printing the error produced by this construction using the format directive `%+v` ``` fmt.Errorf( "prefix1: %w", fmt.Errorf( "prefix2 %w", goErr.Join( fmt.Errorf("a%w", fmt.Errorf("b%w", fmt.Errorf("c%w", goErr.New("d")))), fmt.Errorf("e%w", fmt.Errorf("f%w", fmt.Errorf("g%w", goErr.New("h")))), ))) ``` Produces the following output: ``` prefix1: prefix2: abcd (1) prefix1 Wraps: (2) prefix2 Wraps: (3) abcd | efgh └─ Wraps: (4) efgh └─ Wraps: (5) fgh └─ Wraps: (6) gh └─ Wraps: (7) h └─ Wraps: (8) abcd └─ Wraps: (9) bcd └─ Wraps: (10) cd └─ Wraps: (11) d Error types: (1) *fmt.wrapError (2) *fmt.wrapError (3) *errors.joinError (4) *fmt.wrapError (5) *fmt.wrapError (6) *fmt.wrapError (7) *errors.errorString (8) *fmt.wrapError (9) *fmt.wrapError (10) *fmt.wrapError (11) *errors.errorString`, ``` Note the following properties of the output: * The top-level single cause chain maintains the left-aligned `Wrap` lines which contain each cause one at a time. * As soon as we hit the multi-cause errors within the `joinError` struct (`(3)`), we add new indentation to show that The child errors of `(3)` are `(4)` and `(8)` * Subsequent causes of errors after `joinError`, are also indented to disambiguate the causal chain * The `Error types` section at the bottom remains the same and the numbering of the types can be matched to the errors above using the integers next to the `Wrap` lines. * No special effort has been made to number the errors in a way that describes the causal chain or tree. This keeps it easy to match up the error to its type descriptor. --- errbase/format_error.go | 125 +++++++++--- errbase/format_error_internal_test.go | 171 ++++++++++++++++ fmttests/testdata/format/wrap-fmt | 96 ++++++++- fmttests/testdata/format/wrap-fmt-via-network | 111 +++++++++- fmttests/testdata/format/wrap-goerr | 87 +++++++- .../testdata/format/wrap-goerr-via-network | 102 +++++++++- fmttests/testdata/format/wrap-newf | 165 ++++++++++++++- .../testdata/format/wrap-newf-via-network | 189 +++++++++++++++++- fmttests/testdata/format/wrap-nofmt | 87 +++++++- .../testdata/format/wrap-nofmt-via-network | 111 +++++++++- fmttests/testdata/format/wrap-pkgerr | 159 ++++++++++++++- .../testdata/format/wrap-pkgerr-via-network | 189 +++++++++++++++++- report/report.go | 20 +- 13 files changed, 1549 insertions(+), 63 deletions(-) diff --git a/errbase/format_error.go b/errbase/format_error.go index c6d50c8..049ab75 100644 --- a/errbase/format_error.go +++ b/errbase/format_error.go @@ -102,7 +102,13 @@ func formatErrorInternal(err error, s fmt.State, verb rune, redactableOutput boo // to enable stack trace de-duplication. This requires a // post-order traversal. Since we have a linked list, the best we // can do is a recursion. - p.formatRecursive(err, true /* isOutermost */, true /* withDetail */) + p.formatRecursive( + err, + true, /* isOutermost */ + true, /* withDetail */ + false, /* withDepth */ + 0, /* depth */ + ) // We now have all the data, we can render the result. p.formatEntries(err) @@ -146,7 +152,7 @@ func formatErrorInternal(err error, s fmt.State, verb rune, redactableOutput boo // by calling FormatError(), in which case we'd get an infinite // recursion. So we have no choice but to peel the data // and then assemble the pieces ourselves. - p.formatRecursive(err, true /* isOutermost */, false /* withDetail */) + p.formatRecursive(err, true, false, false, 0) p.formatSingleLineOutput() p.finishDisplay(verb) @@ -195,7 +201,19 @@ func (s *state) formatEntries(err error) { // Wraps: (N)
// for i, j := len(s.entries)-2, 2; i >= 0; i, j = i-1, j+1 { - fmt.Fprintf(&s.finalBuf, "\nWraps: (%d)", j) + s.finalBuf.WriteByte('\n') + // Extra indentation starts at depth==2 because the direct + // children of the root error area already printed on separate + // newlines. + for m := 0; m < s.entries[i].depth-1; m += 1 { + if m == s.entries[i].depth-2 { + s.finalBuf.WriteString("└─ ") + } else { + s.finalBuf.WriteByte(' ') + s.finalBuf.WriteByte(' ') + } + } + fmt.Fprintf(&s.finalBuf, "Wraps: (%d)", j) entry := s.entries[i] s.printEntry(entry) } @@ -330,12 +348,34 @@ func (s *state) formatSingleLineOutput() { // s.finalBuf is untouched. The conversion of s.entries // to s.finalBuf is done by formatSingleLineOutput() and/or // formatEntries(). -func (s *state) formatRecursive(err error, isOutermost, withDetail bool) { +// +// `withDepth` and `depth` are used to tag subtrees of multi-cause +// errors for added indentation during printing. Once a multi-cause +// error is encountered, all subsequent calls with set `withDepth` to +// true, and increment `depth` during recursion. This information is +// persisted into the generated entries and used later to display the +// error with increased indentation based in the depth. +func (s *state) formatRecursive(err error, isOutermost, withDetail, withDepth bool, depth int) int { cause := UnwrapOnce(err) + numChildren := 0 if cause != nil { - // Recurse first. - s.formatRecursive(cause, false /*isOutermost*/, withDetail) + // Recurse first, which populates entries list starting from innermost + // entry. If we've previously seen a multi-cause wrapper, `withDepth` + // will be true, and we'll record the depth below ensuring that extra + // indentation is applied to this inner cause during printing. + // Otherwise, we maintain "straight" vertical formatting by keeping the + // parent callers `withDepth` value of `false` by default. + numChildren += s.formatRecursive(cause, false, withDetail, withDepth, depth+1) + } + + causes := UnwrapMulti(err) + for _, c := range causes { + // Override `withDepth` to true for all child entries ensuring they have + // indentation applied during formatting to distinguish them from + // parents. + numChildren += s.formatRecursive(c, false, withDetail, true, depth+1) } + // inserted := len(s.entries) - 1 - startChildren // Reinitialize the state for this stage of wrapping. s.wantDetail = withDetail @@ -355,9 +395,11 @@ func (s *state) formatRecursive(err error, isOutermost, withDetail bool) { bufIsRedactable = true desiredShortening := v.SafeFormatError((*safePrinter)(s)) if desiredShortening == nil { - // The error wants to elide the short messages from inner - // causes. Do it. - s.elideFurtherCauseMsgs() + // The error wants to elide the short messages from inner causes. + // Read backwards through list of entries up to the number of new + // entries created "under" this one amount and mark `elideShort` + // true. + s.elideShortChildren(numChildren) } case Formatter: @@ -365,7 +407,7 @@ func (s *state) formatRecursive(err error, isOutermost, withDetail bool) { if desiredShortening == nil { // The error wants to elide the short messages from inner // causes. Do it. - s.elideFurtherCauseMsgs() + s.elideShortChildren(numChildren) } case fmt.Formatter: @@ -389,7 +431,7 @@ func (s *state) formatRecursive(err error, isOutermost, withDetail bool) { if elideCauseMsg := s.formatSimple(err, cause); elideCauseMsg { // The error wants to elide the short messages from inner // causes. Do it. - s.elideFurtherCauseMsgs() + s.elideShortChildren(numChildren) } } @@ -412,7 +454,7 @@ func (s *state) formatRecursive(err error, isOutermost, withDetail bool) { if desiredShortening == nil { // The error wants to elide the short messages from inner // causes. Do it. - s.elideFurtherCauseMsgs() + s.elideShortChildren(numChildren) } break } @@ -421,16 +463,21 @@ func (s *state) formatRecursive(err error, isOutermost, withDetail bool) { // If the error did not implement errors.Formatter nor // fmt.Formatter, but it is a wrapper, still attempt best effort: // print what we can at this level. - if elideCauseMsg := s.formatSimple(err, cause); elideCauseMsg { + elideChildren := s.formatSimple(err, cause) + // always elideChildren when dealing with multi-cause errors. + if len(causes) > 0 { + elideChildren = true + } + if elideChildren { // The error wants to elide the short messages from inner // causes. Do it. - s.elideFurtherCauseMsgs() + s.elideShortChildren(numChildren) } } } // Collect the result. - entry := s.collectEntry(err, bufIsRedactable) + entry := s.collectEntry(err, bufIsRedactable, withDepth, depth) // If there's an embedded stack trace, also collect it. // This will get either a stack from pkg/errors, or ours. @@ -444,21 +491,26 @@ func (s *state) formatRecursive(err error, isOutermost, withDetail bool) { // Remember the entry for later rendering. s.entries = append(s.entries, entry) s.buf = bytes.Buffer{} + + return numChildren + 1 } -// elideFurtherCauseMsgs sets the `elideShort` field -// on all entries added so far to `true`. Because these -// entries are added recursively from the innermost -// cause outward, we can iterate through all entries -// without bound because the caller is guaranteed not -// to see entries that it is the causer of. -func (s *state) elideFurtherCauseMsgs() { - for i := range s.entries { - s.entries[i].elideShort = true +// elideShortChildren takes a number of entries to set `elideShort` to +// false. The reason a number of entries is needed is because +// +// TODO(davidh): I have a hypothesis that the `newEntries` arg is +// unnecessary and it's correct to elide all children whenever this is +// called, even with multi-cause scenarios. This is because it's +// impossible for a multi-cause tree to later "switch" to a +// single-cause chain, so any time a multi-cause error is recursing +// you're guaranteed to only have its children within. +func (s *state) elideShortChildren(newEntries int) { + for i := 0; i < newEntries; i++ { + s.entries[len(s.entries)-1-i].elideShort = true } } -func (s *state) collectEntry(err error, bufIsRedactable bool) formatEntry { +func (s *state) collectEntry(err error, bufIsRedactable bool, withDepth bool, depth int) formatEntry { entry := formatEntry{err: err} if s.wantDetail { // The buffer has been populated as a result of formatting with @@ -495,6 +547,10 @@ func (s *state) collectEntry(err error, bufIsRedactable bool) formatEntry { } } + if withDepth { + entry.depth = depth + } + return entry } @@ -712,6 +768,11 @@ type formatEntry struct { // truncated to avoid duplication of entries. This is used to // display a truncation indicator during verbose rendering. elidedStackTrace bool + + // depth, if positive, represents a nesting depth of this error as + // a causer of others. This is used with verbose printing to + // illustrate the nesting depth for multi-cause error wrappers. + depth int } // String is used for debugging only. @@ -733,6 +794,12 @@ func (s *state) Write(b []byte) (n int, err error) { for i, c := range b { if c == '\n' { + //if s.needNewline > 0 { + // for i := 0; i < s.needNewline-1; i++ { + // s.buf.Write(detailSep[:len(sep)-1]) + // } + // s.needNewline = 0 + //} // Flush all the bytes seen so far. s.buf.Write(b[k:i]) // Don't print the newline itself; instead, prepare the state so @@ -762,6 +829,11 @@ func (s *state) Write(b []byte) (n int, err error) { s.notEmpty = true } } + //if s.needNewline > 0 { + // for i := 0; i < s.needNewline-1; i++ { + // s.buf.Write(detailSep[:len(sep)-1]) + // } + //} s.buf.Write(b[k:]) return len(b), nil } @@ -788,6 +860,9 @@ func (p *state) switchOver() { p.buf = bytes.Buffer{} p.notEmpty = false p.hasDetail = true + + // One of the newlines is accounted for in the switch over. + // p.needNewline -= 1 } func (s *printer) Detail() bool { diff --git a/errbase/format_error_internal_test.go b/errbase/format_error_internal_test.go index 0e4f93e..34ba496 100644 --- a/errbase/format_error_internal_test.go +++ b/errbase/format_error_internal_test.go @@ -15,11 +15,182 @@ package errbase import ( + goErr "errors" + "fmt" "testing" "github.com/cockroachdb/redact" ) +type wrapMini struct { + msg string + cause error +} + +func (e *wrapMini) Error() string { + return e.msg +} + +func (e *wrapMini) Unwrap() error { + return e.cause +} + +// TestFormatErrorInternal attempts to highlight some idiosyncrasies of +// the error formatting especially when used with multi-cause error +// structures. Comments on specific cases below outline some gaps that +// still require formatting tweaks. +func TestFormatErrorInternal(t *testing.T) { + tests := []struct { + name string + err error + expectedSimple string + expectedVerbose string + }{ + { + name: "single wrapper", + err: fmt.Errorf("%w", fmt.Errorf("a%w", goErr.New("b"))), + expectedSimple: "ab", + expectedVerbose: `ab +(1) +Wraps: (2) ab +Wraps: (3) b +Error types: (1) *fmt.wrapError (2) *fmt.wrapError (3) *errors.errorString`, + }, + { + name: "simple multi-wrapper", + err: goErr.Join(goErr.New("a"), goErr.New("b")), + expectedSimple: "a\nb", + // TODO(davidh): verbose test case should have line break + // between `a` and `b` on second line. + expectedVerbose: `a +(1) ab +Wraps: (2) b +Wraps: (3) a +Error types: (1) *errors.joinError (2) *errors.errorString (3) *errors.errorString`, + }, + { + name: "simple multi-line error", + err: goErr.New("a\nb\nc\nd"), + expectedSimple: "a\nb\nc\nd", + // TODO(davidh): verbose test case should preserve all 3 + // linebreaks in original error. + expectedVerbose: `a +(1) ab + | + | c + | d +Error types: (1) *errors.errorString`, + }, + { + name: "two-level multi-wrapper", + err: goErr.Join( + goErr.Join(goErr.New("a"), goErr.New("b")), + goErr.Join(goErr.New("c"), goErr.New("d")), + ), + expectedSimple: "a\nb\nc\nd", + // TODO(davidh): verbose output should preserve line breaks after (1) + // and also after (2) and (5) in `c\nd` and `a\nb`. + expectedVerbose: `a +(1) ab + | + | c + | d +Wraps: (2) cd +└─ Wraps: (3) d +└─ Wraps: (4) c +Wraps: (5) ab +└─ Wraps: (6) b +└─ Wraps: (7) a +Error types: (1) *errors.joinError (2) *errors.joinError (3) *errors.errorString (4) *errors.errorString (5) *errors.joinError (6) *errors.errorString (7) *errors.errorString`, + }, + { + name: "simple multi-wrapper with single-cause chains inside", + err: goErr.Join( + fmt.Errorf("a%w", goErr.New("b")), + fmt.Errorf("c%w", goErr.New("d")), + ), + expectedSimple: "ab\ncd", + expectedVerbose: `ab +(1) ab + | cd +Wraps: (2) cd +└─ Wraps: (3) d +Wraps: (4) ab +└─ Wraps: (5) b +Error types: (1) *errors.joinError (2) *fmt.wrapError (3) *errors.errorString (4) *fmt.wrapError (5) *errors.errorString`, + }, + { + name: "multi-cause wrapper with single-cause chains inside", + err: goErr.Join( + fmt.Errorf("a%w", fmt.Errorf("b%w", fmt.Errorf("c%w", goErr.New("d")))), + fmt.Errorf("e%w", fmt.Errorf("f%w", fmt.Errorf("g%w", goErr.New("h")))), + ), + expectedSimple: `abcd +efgh`, + expectedVerbose: `abcd +(1) abcd + | efgh +Wraps: (2) efgh +└─ Wraps: (3) fgh + └─ Wraps: (4) gh + └─ Wraps: (5) h +Wraps: (6) abcd +└─ Wraps: (7) bcd + └─ Wraps: (8) cd + └─ Wraps: (9) d +Error types: (1) *errors.joinError (2) *fmt.wrapError (3) *fmt.wrapError (4) *fmt.wrapError (5) *errors.errorString (6) *fmt.wrapError (7) *fmt.wrapError (8) *fmt.wrapError (9) *errors.errorString`}, + { + name: "single cause chain with multi-cause wrapper inside with single-cause chains inside", + err: fmt.Errorf( + "prefix1: %w", + fmt.Errorf( + "prefix2: %w", + goErr.Join( + fmt.Errorf("a%w", fmt.Errorf("b%w", fmt.Errorf("c%w", goErr.New("d")))), + fmt.Errorf("e%w", fmt.Errorf("f%w", fmt.Errorf("g%w", goErr.New("h")))), + ))), + expectedSimple: `prefix1: prefix2: abcd +efgh`, + expectedVerbose: `prefix1: prefix2: abcd +(1) prefix1 +Wraps: (2) prefix2 +Wraps: (3) abcd + | efgh + └─ Wraps: (4) efgh + └─ Wraps: (5) fgh + └─ Wraps: (6) gh + └─ Wraps: (7) h + └─ Wraps: (8) abcd + └─ Wraps: (9) bcd + └─ Wraps: (10) cd + └─ Wraps: (11) d +Error types: (1) *fmt.wrapError (2) *fmt.wrapError (3) *errors.joinError (4) *fmt.wrapError (5) *fmt.wrapError (6) *fmt.wrapError (7) *errors.errorString (8) *fmt.wrapError (9) *fmt.wrapError (10) *fmt.wrapError (11) *errors.errorString`, + }, + { + name: "test wrapMini elides cause error string", + err: &wrapMini{"whoa: d", goErr.New("d")}, + expectedSimple: "whoa: d", + expectedVerbose: `whoa: d +(1) whoa +Wraps: (2) d +Error types: (1) *errbase.wrapMini (2) *errors.errorString`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fe := Formattable(tt.err) + s := fmt.Sprintf("%s", fe) + if s != tt.expectedSimple { + t.Errorf("\nexpected: \n%s\nbut got:\n%s\n", tt.expectedSimple, s) + } + s = fmt.Sprintf("%+v", fe) + if s != tt.expectedVerbose { + t.Errorf("\nexpected: \n%s\nbut got:\n%s\n", tt.expectedVerbose, s) + } + }) + } +} + func TestPrintEntry(t *testing.T) { b := func(s string) []byte { return []byte(s) } diff --git a/fmttests/testdata/format/wrap-fmt b/fmttests/testdata/format/wrap-fmt index 91f1008..1911862 100644 --- a/fmttests/testdata/format/wrap-fmt +++ b/fmttests/testdata/format/wrap-fmt @@ -1658,7 +1658,37 @@ outerthree (1) outerthree | outerfour - innerone | innertwo sibling error in wrapper -Error types: (1) *fmt.wrapErrors +Wraps: (2) sibling error in wrapper + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo + | -- this is innerone + | innertwo's + | multi-line leaf payload +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *fmttests.errFmt ===== ===== redactable formats ===== @@ -1676,7 +1706,37 @@ Error types: (1) *fmt.wrapErrors (1) ‹outerthree› ‹ | outerfour - innerone› ‹ | innertwo sibling error in wrapper› -Error types: (1) *fmt.wrapErrors +Wraps: (2) ‹sibling error in wrapper› +‹ | github.com/cockroachdb/errors/fmttests.glob..func23› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective.func1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirectiveOrSubTest› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runTestInternal› +‹ | :› +‹ | github.com/cockroachdb/datadriven.RunTest› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk.func1› +‹ | :› +‹ | testing.tRunner› +‹ | :› +‹ | runtime.goexit› +‹ | :› +Wraps: (3) ‹innerone› +‹ | innertwo› +‹ | -- this is innerone› +‹ | innertwo's› +‹ | multi-line leaf payload› +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *fmttests.errFmt ===== ===== Sentry reporting ===== @@ -1685,7 +1745,37 @@ Error types: (1) *fmt.wrapErrors (1) × × × -Error types: (1) *fmt.wrapErrors +Wraps: (2) × +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +Wraps: (3) × +× +× +× +× +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *fmttests.errFmt -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-fmt-via-network b/fmttests/testdata/format/wrap-fmt-via-network index c653d87..c152248 100644 --- a/fmttests/testdata/format/wrap-fmt-via-network +++ b/fmttests/testdata/format/wrap-fmt-via-network @@ -2165,7 +2165,42 @@ outerthree | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) sibling error in wrapper + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo + | + | (opaque error leaf) + | type name: github.com/cockroachdb/errors/fmttests/*fmttests.errFmt +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf == %#v via Formattable() = %#v, good == %v via Formattable() = Error(), good == %s via Formattable() = %v via Formattable(), good @@ -2191,7 +2226,42 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) ‹sibling error in wrapper› + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) ‹innerone› + | ‹innertwo› + | + | (opaque error leaf) + | type name: github.com/cockroachdb/errors/fmttests/*fmttests.errFmt +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf ===== ===== Sentry reporting ===== @@ -2203,7 +2273,42 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) × + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) × + | × + | + | (opaque error leaf) + | type name: github.com/cockroachdb/errors/fmttests/*fmttests.errFmt +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-goerr b/fmttests/testdata/format/wrap-goerr index e3594ef..fd97e94 100644 --- a/fmttests/testdata/format/wrap-goerr +++ b/fmttests/testdata/format/wrap-goerr @@ -1513,7 +1513,34 @@ outerthree (1) outerthree | outerfour - innerone | innertwo sibling error in wrapper -Error types: (1) *fmt.wrapErrors +Wraps: (2) sibling error in wrapper + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *errors.errorString ===== ===== redactable formats ===== @@ -1531,7 +1558,34 @@ Error types: (1) *fmt.wrapErrors (1) ‹outerthree› ‹ | outerfour - innerone› ‹ | innertwo sibling error in wrapper› -Error types: (1) *fmt.wrapErrors +Wraps: (2) ‹sibling error in wrapper› +‹ | github.com/cockroachdb/errors/fmttests.glob..func23› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective.func1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirectiveOrSubTest› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runTestInternal› +‹ | :› +‹ | github.com/cockroachdb/datadriven.RunTest› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk.func1› +‹ | :› +‹ | testing.tRunner› +‹ | :› +‹ | runtime.goexit› +‹ | :› +Wraps: (3) ‹innerone› +‹ | innertwo› +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *errors.errorString ===== ===== Sentry reporting ===== @@ -1540,7 +1594,34 @@ Error types: (1) *fmt.wrapErrors (1) × × × -Error types: (1) *fmt.wrapErrors +Wraps: (2) × +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +Wraps: (3) × +× +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *errors.errorString -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-goerr-via-network b/fmttests/testdata/format/wrap-goerr-via-network index 159524e..05a8e43 100644 --- a/fmttests/testdata/format/wrap-goerr-via-network +++ b/fmttests/testdata/format/wrap-goerr-via-network @@ -1774,7 +1774,39 @@ outerthree | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) sibling error in wrapper + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errors.errorString == %#v via Formattable() = %#v, good == %v via Formattable() = Error(), good == %s via Formattable() = %v via Formattable(), good @@ -1800,7 +1832,39 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) ‹sibling error in wrapper› + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) ‹innerone› +‹ | innertwo› +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errors.errorString ===== ===== Sentry reporting ===== @@ -1812,7 +1876,39 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) × + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) × +× +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errors.errorString -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-newf b/fmttests/testdata/format/wrap-newf index 6567b1c..823f653 100644 --- a/fmttests/testdata/format/wrap-newf +++ b/fmttests/testdata/format/wrap-newf @@ -3135,7 +3135,60 @@ outerthree (1) outerthree | outerfour - new-style innerone | innertwo sibling error in wrapper -Error types: (1) *fmt.wrapErrors +Wraps: (2) sibling error in wrapper + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) attached stack trace + -- stack trace: + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +└─ Wraps: (4) new-style innerone + | innertwo +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *withstack.withStack (4) *errutil.leafError ===== ===== redactable formats ===== @@ -3153,7 +3206,60 @@ Error types: (1) *fmt.wrapErrors (1) ‹outerthree› ‹ | outerfour - new-style innerone› ‹ | innertwo sibling error in wrapper› -Error types: (1) *fmt.wrapErrors +Wraps: (2) ‹sibling error in wrapper› +‹ | github.com/cockroachdb/errors/fmttests.glob..func23› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective.func1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirectiveOrSubTest› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runTestInternal› +‹ | :› +‹ | github.com/cockroachdb/datadriven.RunTest› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk.func1› +‹ | :› +‹ | testing.tRunner› +‹ | :› +‹ | runtime.goexit› +‹ | :› +Wraps: (3) attached stack trace + -- stack trace: + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +└─ Wraps: (4) new-style ‹innerone› + | ‹innertwo› +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *withstack.withStack (4) *errutil.leafError ===== ===== Sentry reporting ===== @@ -3162,7 +3268,60 @@ Error types: (1) *fmt.wrapErrors (1) × × × -Error types: (1) *fmt.wrapErrors +Wraps: (2) × +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +Wraps: (3) attached stack trace + -- stack trace: + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +└─ Wraps: (4) new-style × + | × +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *withstack.withStack (4) *errutil.leafError -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-newf-via-network b/fmttests/testdata/format/wrap-newf-via-network index df5e711..57ebc9a 100644 --- a/fmttests/testdata/format/wrap-newf-via-network +++ b/fmttests/testdata/format/wrap-newf-via-network @@ -3699,7 +3699,68 @@ outerthree | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) sibling error in wrapper + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) + | (opaque error wrapper) + | type name: github.com/cockroachdb/errors/withstack/*withstack.withStack + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +└─ Wraps: (4) new-style innerone + | innertwo +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueWrapper (4) *errutil.leafError == %#v via Formattable() = %#v, good == %v via Formattable() = Error(), good == %s via Formattable() = %v via Formattable(), good @@ -3725,7 +3786,68 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) ‹sibling error in wrapper› + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) + | (opaque error wrapper) + | type name: github.com/cockroachdb/errors/withstack/*withstack.withStack + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +└─ Wraps: (4) new-style ‹innerone› + | ‹innertwo› +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueWrapper (4) *errutil.leafError ===== ===== Sentry reporting ===== @@ -3737,7 +3859,68 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) × + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) + | (opaque error wrapper) + | type name: github.com/cockroachdb/errors/withstack/*withstack.withStack + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +└─ Wraps: (4) new-style × + | × +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueWrapper (4) *errutil.leafError -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-nofmt b/fmttests/testdata/format/wrap-nofmt index 666d4e9..c643809 100644 --- a/fmttests/testdata/format/wrap-nofmt +++ b/fmttests/testdata/format/wrap-nofmt @@ -1513,7 +1513,34 @@ outerthree (1) outerthree | outerfour - innerone | innertwo sibling error in wrapper -Error types: (1) *fmt.wrapErrors +Wraps: (2) sibling error in wrapper + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *fmttests.errNoFmt ===== ===== redactable formats ===== @@ -1531,7 +1558,34 @@ Error types: (1) *fmt.wrapErrors (1) ‹outerthree› ‹ | outerfour - innerone› ‹ | innertwo sibling error in wrapper› -Error types: (1) *fmt.wrapErrors +Wraps: (2) ‹sibling error in wrapper› +‹ | github.com/cockroachdb/errors/fmttests.glob..func23› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective.func1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirectiveOrSubTest› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runTestInternal› +‹ | :› +‹ | github.com/cockroachdb/datadriven.RunTest› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk.func1› +‹ | :› +‹ | testing.tRunner› +‹ | :› +‹ | runtime.goexit› +‹ | :› +Wraps: (3) ‹innerone› +‹ | innertwo› +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *fmttests.errNoFmt ===== ===== Sentry reporting ===== @@ -1540,7 +1594,34 @@ Error types: (1) *fmt.wrapErrors (1) × × × -Error types: (1) *fmt.wrapErrors +Wraps: (2) × +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +Wraps: (3) × +× +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *fmttests.errNoFmt -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-nofmt-via-network b/fmttests/testdata/format/wrap-nofmt-via-network index 71fc4b2..e9e84c5 100644 --- a/fmttests/testdata/format/wrap-nofmt-via-network +++ b/fmttests/testdata/format/wrap-nofmt-via-network @@ -2165,7 +2165,42 @@ outerthree | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) sibling error in wrapper + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo + | + | (opaque error leaf) + | type name: github.com/cockroachdb/errors/fmttests/*fmttests.errNoFmt +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf == %#v via Formattable() = %#v, good == %v via Formattable() = Error(), good == %s via Formattable() = %v via Formattable(), good @@ -2191,7 +2226,42 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) ‹sibling error in wrapper› + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) ‹innerone› + | ‹innertwo› + | + | (opaque error leaf) + | type name: github.com/cockroachdb/errors/fmttests/*fmttests.errNoFmt +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf ===== ===== Sentry reporting ===== @@ -2203,7 +2273,42 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) × + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) × + | × + | + | (opaque error leaf) + | type name: github.com/cockroachdb/errors/fmttests/*fmttests.errNoFmt +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-pkgerr b/fmttests/testdata/format/wrap-pkgerr index 3bfc433..3a351ff 100644 --- a/fmttests/testdata/format/wrap-pkgerr +++ b/fmttests/testdata/format/wrap-pkgerr @@ -3022,7 +3022,58 @@ outerthree (1) outerthree | outerfour - innerone | innertwo sibling error in wrapper -Error types: (1) *fmt.wrapErrors +Wraps: (2) sibling error in wrapper + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *errors.fundamental ===== ===== redactable formats ===== @@ -3040,7 +3091,58 @@ Error types: (1) *fmt.wrapErrors (1) ‹outerthree› ‹ | outerfour - innerone› ‹ | innertwo sibling error in wrapper› -Error types: (1) *fmt.wrapErrors +Wraps: (2) ‹sibling error in wrapper› +‹ | github.com/cockroachdb/errors/fmttests.glob..func23› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective.func1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirectiveOrSubTest› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runTestInternal› +‹ | :› +‹ | github.com/cockroachdb/datadriven.RunTest› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk.func1› +‹ | :› +‹ | testing.tRunner› +‹ | :› +‹ | runtime.goexit› +‹ | :› +Wraps: (3) ‹innerone› +‹ | innertwo› +‹ | github.com/cockroachdb/errors/fmttests.glob..func9› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective.func1› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirective› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runDirectiveOrSubTest› +‹ | :› +‹ | github.com/cockroachdb/datadriven.runTestInternal› +‹ | :› +‹ | github.com/cockroachdb/datadriven.RunTest› +‹ | :› +‹ | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk› +‹ | :› +‹ | github.com/cockroachdb/datadriven.Walk.func1› +‹ | :› +‹ | testing.tRunner› +‹ | :› +‹ | runtime.goexit› +‹ | :› +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *errors.fundamental ===== ===== Sentry reporting ===== @@ -3049,7 +3151,58 @@ Error types: (1) *fmt.wrapErrors (1) × × × -Error types: (1) *fmt.wrapErrors +Wraps: (2) × +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +Wraps: (3) × +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +× +Error types: (1) *fmt.wrapErrors (2) *errors.fundamental (3) *errors.fundamental -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/fmttests/testdata/format/wrap-pkgerr-via-network b/fmttests/testdata/format/wrap-pkgerr-via-network index d9376e1..5a4cae3 100644 --- a/fmttests/testdata/format/wrap-pkgerr-via-network +++ b/fmttests/testdata/format/wrap-pkgerr-via-network @@ -3611,7 +3611,68 @@ outerthree | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) sibling error in wrapper + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) innerone + | innertwo + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf == %#v via Formattable() = %#v, good == %v via Formattable() = Error(), good == %s via Formattable() = %v via Formattable(), good @@ -3637,7 +3698,68 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) ‹sibling error in wrapper› + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) ‹innerone› + | ‹innertwo› + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf ===== ===== Sentry reporting ===== @@ -3649,7 +3771,68 @@ Error types: (1) *errbase.opaqueLeafCauses | | (opaque error leaf) | type name: fmt/*fmt.wrapErrors -Error types: (1) *errbase.opaqueLeafCauses +Wraps: (2) × + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Wraps: (3) × + | × + | + | (opaque error leaf) + | type name: github.com/pkg/errors/*errors.fundamental + | reportable 0: + | + | github.com/cockroachdb/errors/fmttests.glob...funcNN... + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2.1 + | : + | github.com/cockroachdb/datadriven.runDirective.func1 + | : + | github.com/cockroachdb/datadriven.runDirective + | : + | github.com/cockroachdb/datadriven.runDirectiveOrSubTest + | : + | github.com/cockroachdb/datadriven.runTestInternal + | : + | github.com/cockroachdb/datadriven.RunTest + | : + | github.com/cockroachdb/errors/fmttests.TestDatadriven.func2 + | : + | github.com/cockroachdb/datadriven.Walk + | : + | github.com/cockroachdb/datadriven.Walk.func1 + | : + | testing.tRunner + | : + | runtime.goexit + | : +Error types: (1) *errbase.opaqueLeafCauses (2) *errbase.opaqueLeaf (3) *errbase.opaqueLeaf -- report composition: *fmt.wrapErrors == Extra "error types" diff --git a/report/report.go b/report/report.go index 0211722..cba95b0 100644 --- a/report/report.go +++ b/report/report.go @@ -34,7 +34,7 @@ import ( // // A Sentry report is displayed visually in the Sentry UI as follows: // -//////////////// +// ////////////// // Title: (1) some prefix in bold (2) one line for a stack trace // (3) a single-line subtitle // @@ -44,21 +44,24 @@ import ( // (5) a "message" // // (6) zero or more "exceptions", each composed of: -// (7) a bold title -// (8) some freeform text -// (9) a stack trace +// +// (7) a bold title +// (8) some freeform text +// (9) a stack trace // // (10) metadata fields: environment, arch, etc // // (11) "Additional data" fields // // (12) SDK version -///////////////// +// /////////////// // // These visual items map to the Sentry Event object as follows: // // (1) the Type field of the 1st Exception object, if any -// otherwise the Message field +// +// otherwise the Message field +// // (2) the topmost entry from the Stacktrace field of the 1st Exception object, if any // (3) the Value field of the 1st Exception object, if any, unwrapped as a single line // (4) the Tags field @@ -78,7 +81,9 @@ import ( // (3)/(8): first line of verbose error printout // (4): not populated in this function, caller is to manage this // (5): detailed structure of the entire error object, with references to -// additional "exception" objects +// +// additional "exception" objects +// // (9): generated from innermost stack trace // (6): every exception object after the 1st reports additional stack trace contexts // (11): the detailed error types and their error mark. @@ -92,7 +97,6 @@ import ( // is included in the Sentry report. This does not affect error types // provided by the library, but could impact error types defined by // 3rd parties. This limitation may be lifted in a later version. -// func BuildSentryReport(err error) (event *sentry.Event, extraDetails map[string]interface{}) { if err == nil { // No error: do nothing.