github.com/cockroachdb/errors@v1.11.1/errbase/format_error.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. See the License for the specific language governing 13 // permissions and limitations under the License. 14 15 // This file is forked and modified from golang.org/x/xerrors, 16 // at commit 3ee3066db522c6628d440a3a91c4abdd7f5ef22f (2019-05-10). 17 // From the original code: 18 // Copyright 2018 The Go Authors. All rights reserved. 19 // Use of this source code is governed by a BSD-style 20 // license that can be found in the LICENSE file. 21 // 22 // Changes specific to this fork marked as inline comments. 23 24 package errbase 25 26 import ( 27 "bytes" 28 "fmt" 29 "io" 30 "reflect" 31 "strings" 32 33 "github.com/cockroachdb/redact" 34 "github.com/kr/pretty" 35 pkgErr "github.com/pkg/errors" 36 ) 37 38 // FormatError formats an error according to s and verb. 39 // This is a helper meant for use when implementing the fmt.Formatter 40 // interface on custom error objects. 41 // 42 // If the error implements errors.Formatter, FormatError calls its 43 // FormatError method of f with an errors.Printer configured according 44 // to s and verb, and writes the result to s. 45 // 46 // Otherwise, if it is a wrapper, FormatError prints out its error prefix, 47 // then recurses on its cause. 48 // 49 // Otherwise, its Error() text is printed. 50 func FormatError(err error, s fmt.State, verb rune) { 51 formatErrorInternal(err, s, verb, false /* redactableOutput */) 52 } 53 54 // FormatRedactableError formats an error as a safe object. 55 // 56 // Note that certain verb/flags combinations are currently not 57 // supported, and result in a rendering that considers the entire 58 // object as unsafe. For example, %q, %#v are not yet supported. 59 func FormatRedactableError(err error, s redact.SafePrinter, verb rune) { 60 formatErrorInternal(err, s, verb, true /* redactable */) 61 } 62 63 func init() { 64 // Also inform the redact package of how to print an error 65 // safely. This is used when an error is passed as argument 66 // to one of the redact print functions. 67 redact.RegisterRedactErrorFn(FormatRedactableError) 68 } 69 70 // Formattable wraps an error into a fmt.Formatter which 71 // will provide "smart" formatting even if the outer layer 72 // of the error does not implement the Formatter interface. 73 func Formattable(err error) fmt.Formatter { 74 return &errorFormatter{err} 75 } 76 77 // formatErrorInternal is the shared logic between FormatError 78 // and FormatErrorRedactable. 79 // 80 // When the redactableOutput argument is true, the fmt.State argument 81 // is really a redact.SafePrinter and casted down as necessary. 82 // 83 // If verb and flags are not one of the supported error formatting 84 // combinations (in particular, %q, %#v etc), then the redactableOutput 85 // argument is ignored. This limitation may be lifted in a later 86 // version. 87 func formatErrorInternal(err error, s fmt.State, verb rune, redactableOutput bool) { 88 // Assuming this function is only called from the Format method, and given 89 // that FormatError takes precedence over Format, it cannot be called from 90 // any package that supports errors.Formatter. It is therefore safe to 91 // disregard that State may be a specific printer implementation and use one 92 // of our choice instead. 93 94 p := state{State: s, redactableOutput: redactableOutput} 95 96 switch { 97 case verb == 'v' && s.Flag('+') && !s.Flag('#'): 98 // Here we are going to format as per %+v, into p.buf. 99 // 100 // We need to start with the innermost (root cause) error first, 101 // then the layers of wrapping from innermost to outermost, so as 102 // to enable stack trace de-duplication. This requires a 103 // post-order traversal. Since we have a linked list, the best we 104 // can do is a recursion. 105 p.formatRecursive( 106 err, 107 true, /* isOutermost */ 108 true, /* withDetail */ 109 false, /* withDepth */ 110 0, /* depth */ 111 ) 112 113 // We now have all the data, we can render the result. 114 p.formatEntries(err) 115 116 // We're done formatting. Apply width/precision parameters. 117 p.finishDisplay(verb) 118 119 case !redactableOutput && verb == 'v' && s.Flag('#'): 120 // We only know how to process %#v if redactable output is not 121 // requested. This is because the structured output may emit 122 // arbitrary unsafe strings without redaction markers, 123 // or improperly balanced/escaped redaction markers. 124 if stringer, ok := err.(fmt.GoStringer); ok { 125 io.WriteString(&p.finalBuf, stringer.GoString()) 126 } else { 127 // Not a GoStringer: delegate to the pretty library. 128 fmt.Fprintf(&p.finalBuf, "%# v", pretty.Formatter(err)) 129 } 130 p.finishDisplay(verb) 131 132 case verb == 's' || 133 // We only handle %v/%+v or other combinations here; %#v is unsupported. 134 (verb == 'v' && !s.Flag('#')) || 135 // If redactable output is not requested, then we also 136 // know how to format %x/%X (print bytes of error message in hex) 137 // and %q (quote the result). 138 // If redactable output is requested, then we don't know 139 // how to perform these exotic verbs, because they 140 // may muck with the redaction markers. In this case, 141 // we simply refuse the format as per the default clause below. 142 (!redactableOutput && (verb == 'x' || verb == 'X' || verb == 'q')): 143 // Only the error message. 144 // 145 // Use an intermediate buffer because there may be alignment 146 // instructions to obey in the final rendering or 147 // quotes to add (for %q). 148 // 149 // Conceptually, we could just do 150 // p.buf.WriteString(err.Error()) 151 // However we also advertise that Error() can be implemented 152 // by calling FormatError(), in which case we'd get an infinite 153 // recursion. So we have no choice but to peel the data 154 // and then assemble the pieces ourselves. 155 p.formatRecursive( 156 err, 157 true, /* isOutermost */ 158 false, /* withDetail */ 159 false, /* withDepth */ 160 0, /* depth */ 161 ) 162 p.formatSingleLineOutput() 163 p.finishDisplay(verb) 164 165 default: 166 // Unknown verb. Do like fmt.Printf and tell the user we're 167 // confused. 168 // 169 // Note that the following logic is correct regardless of the 170 // value of 'redactableOutput', because the display of the verb and type 171 // are always safe for redaction. If/when this code is changed to 172 // print more details, care is to be taken to add redaction 173 // markers if s.redactableOutput is set. 174 p.finalBuf.WriteString("%!") 175 p.finalBuf.WriteRune(verb) 176 p.finalBuf.WriteByte('(') 177 switch { 178 case err != nil: 179 p.finalBuf.WriteString(reflect.TypeOf(err).String()) 180 default: 181 p.finalBuf.WriteString("<nil>") 182 } 183 p.finalBuf.WriteByte(')') 184 io.Copy(s, &p.finalBuf) 185 } 186 } 187 188 // formatEntries reads the entries from s.entries and produces a 189 // detailed rendering in s.finalBuf. 190 // 191 // Note that if s.redactableOutput is true, s.finalBuf is to contain a 192 // RedactableBytes. However, we are not using the helper facilities 193 // from redact.SafePrinter to do this, so care should be taken below 194 // to properly escape markers, etc. 195 func (s *state) formatEntries(err error) { 196 // The first entry at the top is special. We format it as follows: 197 // 198 // <complete error message> 199 // (1) <details> 200 s.formatSingleLineOutput() 201 s.finalBuf.WriteString("\n(1)") 202 203 s.printEntry(s.entries[len(s.entries)-1]) 204 205 // All the entries that follow are printed as follows: 206 // 207 // Wraps: (N) <details> 208 // 209 for i, j := len(s.entries)-2, 2; i >= 0; i, j = i-1, j+1 { 210 s.finalBuf.WriteByte('\n') 211 // Extra indentation starts at depth==2 because the direct 212 // children of the root error area already printed on separate 213 // newlines. 214 for m := 0; m < s.entries[i].depth-1; m += 1 { 215 if m == s.entries[i].depth-2 { 216 s.finalBuf.WriteString("└─ ") 217 } else { 218 s.finalBuf.WriteByte(' ') 219 s.finalBuf.WriteByte(' ') 220 } 221 } 222 fmt.Fprintf(&s.finalBuf, "Wraps: (%d)", j) 223 entry := s.entries[i] 224 s.printEntry(entry) 225 } 226 227 // At the end, we link all the (N) references to the Go type of the 228 // error. 229 s.finalBuf.WriteString("\nError types:") 230 for i, j := len(s.entries)-1, 1; i >= 0; i, j = i-1, j+1 { 231 fmt.Fprintf(&s.finalBuf, " (%d) %T", j, s.entries[i].err) 232 } 233 } 234 235 // printEntry renders the entry given as argument 236 // into s.finalBuf. 237 // 238 // If s.redactableOutput is set, then s.finalBuf is to contain 239 // a RedactableBytes, with redaction markers. In that 240 // case, we must be careful to escape (or not) the entry 241 // depending on entry.redactable. 242 // 243 // If s.redactableOutput is unset, then we are not caring about 244 // redactability. In that case entry.redactable is not set 245 // anyway and we can pass contents through. 246 func (s *state) printEntry(entry formatEntry) { 247 if len(entry.head) > 0 { 248 if entry.head[0] != '\n' { 249 s.finalBuf.WriteByte(' ') 250 } 251 if len(entry.head) > 0 { 252 if !s.redactableOutput || entry.redactable { 253 // If we don't care about redaction, then we can pass the string 254 // through. 255 // 256 // If we do care about redaction, and entry.redactable is true, 257 // then entry.head is already a RedactableBytes. Then we can 258 // also pass it through. 259 s.finalBuf.Write(entry.head) 260 } else { 261 // We care about redaction, and the head is unsafe. Escape it 262 // and enclose the result within redaction markers. 263 s.finalBuf.Write([]byte(redact.EscapeBytes(entry.head))) 264 } 265 } 266 } 267 if len(entry.details) > 0 { 268 if len(entry.head) == 0 { 269 if entry.details[0] != '\n' { 270 s.finalBuf.WriteByte(' ') 271 } 272 } 273 if !s.redactableOutput || entry.redactable { 274 // If we don't care about redaction, then we can pass the string 275 // through. 276 // 277 // If we do care about redaction, and entry.redactable is true, 278 // then entry.details is already a RedactableBytes. Then we can 279 // also pass it through. 280 s.finalBuf.Write(entry.details) 281 } else { 282 // We care about redaction, and the details are unsafe. Escape 283 // them and enclose the result within redaction markers. 284 s.finalBuf.Write([]byte(redact.EscapeBytes(entry.details))) 285 } 286 } 287 if entry.stackTrace != nil { 288 s.finalBuf.WriteString("\n -- stack trace:") 289 s.finalBuf.WriteString(strings.ReplaceAll( 290 fmt.Sprintf("%+v", entry.stackTrace), 291 "\n", string(detailSep))) 292 if entry.elidedStackTrace { 293 fmt.Fprintf(&s.finalBuf, "%s[...repeated from below...]", detailSep) 294 } 295 } 296 } 297 298 // formatSingleLineOutput prints the details extracted via 299 // formatRecursive() through the chain of errors as if .Error() has 300 // been called: it only prints the non-detail parts and prints them on 301 // one line with ": " separators. 302 // 303 // This function is used both when FormatError() is called indirectly 304 // from .Error(), e.g. in: 305 // 306 // (e *myType) Error() { return fmt.Sprintf("%v", e) } 307 // (e *myType) Format(s fmt.State, verb rune) { errors.FormatError(s, verb, e) } 308 // 309 // and also to print the first line in the output of a %+v format. 310 // 311 // It reads from s.entries and writes to s.finalBuf. 312 // s.buf is left untouched. 313 // 314 // Note that if s.redactableOutput is true, s.finalBuf is to contain a 315 // RedactableBytes. However, we are not using the helper facilities 316 // from redact.SafePrinter to do this, so care should be taken below 317 // to properly escape markers, etc. 318 func (s *state) formatSingleLineOutput() { 319 for i := len(s.entries) - 1; i >= 0; i-- { 320 entry := &s.entries[i] 321 if entry.elideShort { 322 continue 323 } 324 if s.finalBuf.Len() > 0 && len(entry.head) > 0 { 325 s.finalBuf.WriteString(": ") 326 } 327 if len(entry.head) == 0 { 328 // shortcut, to avoid the copy below. 329 continue 330 } 331 if !s.redactableOutput || entry.redactable { 332 // If we don't care about redaction, then we can pass the string 333 // through. 334 // 335 // If we do care about redaction, and entry.redactable is true, 336 // then entry.head is already a RedactableBytes. Then we can 337 // also pass it through. 338 s.finalBuf.Write(entry.head) 339 } else { 340 // We do care about redaction, but entry.redactable is unset. 341 // This means entry.head is unsafe. We need to escape it. 342 s.finalBuf.Write([]byte(redact.EscapeBytes(entry.head))) 343 } 344 } 345 } 346 347 // formatRecursive performs a post-order traversal on the chain of 348 // errors to collect error details from innermost to outermost. 349 // 350 // It uses s.buf as an intermediate buffer to collect strings. 351 // It populates s.entries as a result. 352 // Between each layer of error, s.buf is reset. 353 // 354 // s.finalBuf is untouched. The conversion of s.entries 355 // to s.finalBuf is done by formatSingleLineOutput() and/or 356 // formatEntries(). 357 // 358 // `withDepth` and `depth` are used to tag subtrees of multi-cause 359 // errors for added indentation during printing. Once a multi-cause 360 // error is encountered, all subsequent calls with set `withDepth` to 361 // true, and increment `depth` during recursion. This information is 362 // persisted into the generated entries and used later to display the 363 // error with increased indentation based in the depth. 364 func (s *state) formatRecursive(err error, isOutermost, withDetail, withDepth bool, depth int) int { 365 cause := UnwrapOnce(err) 366 numChildren := 0 367 if cause != nil { 368 // Recurse first, which populates entries list starting from innermost 369 // entry. If we've previously seen a multi-cause wrapper, `withDepth` 370 // will be true, and we'll record the depth below ensuring that extra 371 // indentation is applied to this inner cause during printing. 372 // Otherwise, we maintain "straight" vertical formatting by keeping the 373 // parent callers `withDepth` value of `false` by default. 374 numChildren += s.formatRecursive(cause, false, withDetail, withDepth, depth+1) 375 } 376 377 causes := UnwrapMulti(err) 378 for _, c := range causes { 379 // Override `withDepth` to true for all child entries ensuring they have 380 // indentation applied during formatting to distinguish them from 381 // parents. 382 numChildren += s.formatRecursive(c, false, withDetail, true, depth+1) 383 } 384 // inserted := len(s.entries) - 1 - startChildren 385 386 // Reinitialize the state for this stage of wrapping. 387 s.wantDetail = withDetail 388 s.needSpace = false 389 s.needNewline = 0 390 s.multiLine = false 391 s.notEmpty = false 392 s.hasDetail = false 393 s.headBuf = nil 394 395 seenTrace := false 396 397 bufIsRedactable := false 398 399 switch v := err.(type) { 400 case SafeFormatter: 401 bufIsRedactable = true 402 desiredShortening := v.SafeFormatError((*safePrinter)(s)) 403 if desiredShortening == nil { 404 // The error wants to elide the short messages from inner causes. 405 // Read backwards through list of entries up to the number of new 406 // entries created "under" this one amount and mark `elideShort` 407 // true. 408 s.elideShortChildren(numChildren) 409 } 410 411 case Formatter: 412 desiredShortening := v.FormatError((*printer)(s)) 413 if desiredShortening == nil { 414 // The error wants to elide the short messages from inner 415 // causes. Do it. 416 s.elideShortChildren(numChildren) 417 } 418 419 case fmt.Formatter: 420 // We can only use a fmt.Formatter when both the following 421 // conditions are true: 422 // - when it is the leaf error, because a fmt.Formatter 423 // on a wrapper also recurses. 424 // - when it is not the outermost wrapper, because 425 // the Format() method is likely to be calling FormatError() 426 // to do its job and we want to avoid an infinite recursion. 427 if !isOutermost && cause == nil { 428 v.Format(s, 'v') 429 if st, ok := err.(StackTraceProvider); ok { 430 // This is likely a leaf error from github/pkg/errors. 431 // The thing probably printed its stack trace on its own. 432 seenTrace = true 433 // We'll subsequently simplify stack traces in wrappers. 434 s.lastStack = st.StackTrace() 435 } 436 } else { 437 if elideCauseMsg := s.formatSimple(err, cause); elideCauseMsg { 438 // The error wants to elide the short messages from inner 439 // causes. Do it. 440 s.elideShortChildren(numChildren) 441 } 442 } 443 444 default: 445 // Handle the special case overrides for context.Canceled, 446 // os.PathError, etc for which we know how to extract some safe 447 // strings. 448 // 449 // We need to do this in the `default` branch, instead of doing 450 // this above the switch, because the special handler could call a 451 // .Error() that delegates its implementation to fmt.Formatter, 452 // errors.Safeformatter or errors.Formattable, which brings us 453 // back to this method in a call cycle. So we need to handle the 454 // various interfaces first. 455 printDone := false 456 for _, fn := range specialCases { 457 if handled, desiredShortening := fn(err, (*safePrinter)(s), cause == nil /* leaf */); handled { 458 printDone = true 459 bufIsRedactable = true 460 if desiredShortening == nil { 461 // The error wants to elide the short messages from inner 462 // causes. Do it. 463 s.elideShortChildren(numChildren) 464 } 465 break 466 } 467 } 468 if !printDone { 469 // If the error did not implement errors.Formatter nor 470 // fmt.Formatter, but it is a wrapper, still attempt best effort: 471 // print what we can at this level. 472 elideChildren := s.formatSimple(err, cause) 473 // always elideChildren when dealing with multi-cause errors. 474 if len(causes) > 0 { 475 elideChildren = true 476 } 477 if elideChildren { 478 // The error wants to elide the short messages from inner 479 // causes. Do it. 480 s.elideShortChildren(numChildren) 481 } 482 } 483 } 484 485 // Collect the result. 486 entry := s.collectEntry(err, bufIsRedactable, withDepth, depth) 487 488 // If there's an embedded stack trace, also collect it. 489 // This will get either a stack from pkg/errors, or ours. 490 if !seenTrace { 491 if st, ok := err.(StackTraceProvider); ok { 492 entry.stackTrace, entry.elidedStackTrace = ElideSharedStackTraceSuffix(s.lastStack, st.StackTrace()) 493 s.lastStack = entry.stackTrace 494 } 495 } 496 497 // Remember the entry for later rendering. 498 s.entries = append(s.entries, entry) 499 s.buf = bytes.Buffer{} 500 501 return numChildren + 1 502 } 503 504 // elideShortChildren takes a number of entries to set `elideShort` to 505 // false. The reason a number of entries is needed is that we may be 506 // eliding a subtree of causes in the case of a multi-cause error. In 507 // the multi-cause case, we need to know how many of the prior errors 508 // in the list of entries is a child of this subtree. 509 func (s *state) elideShortChildren(newEntries int) { 510 for i := 0; i < newEntries; i++ { 511 s.entries[len(s.entries)-1-i].elideShort = true 512 } 513 } 514 515 func (s *state) collectEntry(err error, bufIsRedactable bool, withDepth bool, depth int) formatEntry { 516 entry := formatEntry{err: err} 517 if s.wantDetail { 518 // The buffer has been populated as a result of formatting with 519 // %+v. In that case, if the printer has separated detail 520 // from non-detail, we can use the split. 521 if s.hasDetail { 522 entry.head = s.headBuf 523 entry.details = s.buf.Bytes() 524 } else { 525 entry.head = s.buf.Bytes() 526 } 527 } else { 528 entry.head = s.headBuf 529 if len(entry.head) > 0 && entry.head[len(entry.head)-1] != '\n' && 530 s.buf.Len() > 0 && s.buf.Bytes()[0] != '\n' { 531 entry.head = append(entry.head, '\n') 532 } 533 entry.head = append(entry.head, s.buf.Bytes()...) 534 } 535 536 if bufIsRedactable { 537 // In this case, we've produced entry.head/entry.details using a 538 // SafeFormatError() invocation. The strings in 539 // entry.head/entry.detail contain redaction markers at this 540 // point. 541 if s.redactableOutput { 542 // Redaction markers desired in the final output. Keep the 543 // redaction markers. 544 entry.redactable = true 545 } else { 546 // Markers not desired in the final output: strip the markers. 547 entry.head = redact.RedactableBytes(entry.head).StripMarkers() 548 entry.details = redact.RedactableBytes(entry.details).StripMarkers() 549 } 550 } 551 552 if withDepth { 553 entry.depth = depth 554 } 555 556 return entry 557 } 558 559 // safeErrorPrinterFn is the type of a function that can take 560 // over the safe printing of an error. This is used to inject special 561 // cases into the formatting in errutil. We need this machinery to 562 // prevent import cycles. 563 type safeErrorPrinterFn = func(err error, p Printer, isLeaf bool) (handled bool, next error) 564 565 // specialCases is a list of functions to apply for special cases. 566 var specialCases []safeErrorPrinterFn 567 568 // RegisterSpecialCasePrinter registers a handler. 569 func RegisterSpecialCasePrinter(fn safeErrorPrinterFn) { 570 specialCases = append(specialCases, fn) 571 } 572 573 // formatSimple performs a best effort at extracting the details at a 574 // given level of wrapping when the error object does not implement 575 // the Formatter interface. 576 // Returns true if we want to elide errors from causal chain. 577 func (s *state) formatSimple(err, cause error) bool { 578 var pref string 579 elideCauses := false 580 if cause != nil { 581 var messageType MessageType 582 pref, messageType = extractPrefix(err, cause) 583 if messageType == FullMessage { 584 elideCauses = true 585 } 586 } else { 587 pref = err.Error() 588 } 589 if len(pref) > 0 { 590 s.Write([]byte(pref)) 591 } 592 return elideCauses 593 } 594 595 // finishDisplay renders s.finalBuf into s.State. 596 func (p *state) finishDisplay(verb rune) { 597 if p.redactableOutput { 598 // If we're rendering in redactable form, then s.finalBuf contains 599 // a RedactableBytes. We can emit that directly. 600 sp := p.State.(redact.SafePrinter) 601 sp.Print(redact.RedactableBytes(p.finalBuf.Bytes())) 602 return 603 } 604 // Not redactable: render depending on flags and verb. 605 606 width, okW := p.Width() 607 _, okP := p.Precision() 608 609 // If `direct` is set to false, then the buffer is always 610 // passed through fmt.Printf regardless of the width and alignment 611 // settings. This is important for e.g. %q where quotes must be added 612 // in any case. 613 // If `direct` is set to true, then the detour via 614 // fmt.Printf only occurs if there is a width or alignment 615 // specifier. 616 direct := verb == 'v' || verb == 's' 617 618 if !direct || (okW && width > 0) || okP { 619 _, format := redact.MakeFormat(p, verb) 620 fmt.Fprintf(p.State, format, p.finalBuf.String()) 621 } else { 622 io.Copy(p.State, &p.finalBuf) 623 } 624 } 625 626 var detailSep = []byte("\n | ") 627 628 // state tracks error printing state. It implements fmt.State. 629 type state struct { 630 // state inherits fmt.State. 631 // 632 // If we are rendering with redactableOutput=true, then fmt.State 633 // can be downcasted to redact.SafePrinter. 634 fmt.State 635 636 // redactableOutput indicates whether we want the output 637 // to use redaction markers. When set to true, 638 // the fmt.State above is actually a redact.SafePrinter. 639 redactableOutput bool 640 641 // finalBuf contains the final rendered string, prior to being 642 // copied to the fmt.State above. 643 // 644 // If redactableOutput is true, then finalBuf contains a RedactableBytes 645 // and safe redaction markers. Otherwise, it can be considered 646 // an unsafe string. 647 finalBuf bytes.Buffer 648 649 // entries collect the result of formatRecursive(). They are 650 // consumed by formatSingleLineOutput() and formatEntries() to 651 // produce the contents of finalBuf. 652 entries []formatEntry 653 654 // buf collects the details of the current error object at a given 655 // stage of recursion in formatRecursive(). 656 // 657 // At each stage of recursion (level of wrapping), buf contains 658 // successively: 659 // 660 // - at the beginning, the "simple" part of the error message -- 661 // either the pre-Detail() string if the error implements Formatter, 662 // or the result of Error(). 663 // 664 // - after the first call to Detail(), buf is copied to headBuf, 665 // then reset, then starts collecting the "advanced" part of the 666 // error message. 667 // 668 // At the end of an error layer, the contents of buf and headBuf 669 // are collected into a formatEntry by collectEntry(). 670 // This collection does not touch finalBuf above. 671 // 672 // The entries are later consumed by formatSingleLineOutput() or 673 // formatEntries() to produce the contents of finalBuf. 674 // 675 // 676 // Notes regarding redaction markers and string safety. Throughout a 677 // single "level" of error, there are three cases to consider: 678 // 679 // - the error level implements SafeErrorFormatter and 680 // s.redactableOutput is set. In that case, the error's 681 // SafeErrorFormat() is used to produce a RedactableBytes in 682 // buf/headBuf via safePrinter{}, and an entry is collected at the 683 // end of that with the redactable bit set on the entry. 684 // 685 // - the error level implements SafeErrorFormatter 686 // and s.redactableOutput is *not* set. In this case, 687 // for convenience we implement non-redactable output by using 688 // SafeErrorFormat() to generate a RedactableBytes into 689 // buf/headBuf via safePrinter{}, and then stripping the redaction 690 // markers to produce the entry. The entry is not marked as 691 // redactable. 692 // 693 // - in the remaining case (s.redactableOutput is not set or the 694 // error only implements Formatter), then we use FormatError() 695 // to produce a non-redactable string into buf/headBuf, 696 // and mark the resulting entry as non-redactable. 697 buf bytes.Buffer 698 // When an error's FormatError() calls Detail(), the current 699 // value of buf above is copied to headBuf, and a new 700 // buf is initialized. 701 headBuf []byte 702 703 // lastStack tracks the last stack trace observed when looking at 704 // the errors from innermost to outermost. This is used to elide 705 // redundant stack trace entries. 706 lastStack StackTrace 707 708 // --------------------------------------------------------------- 709 // The following attributes organize the synchronization of writes 710 // to buf and headBuf, during the rendering of a single error 711 // layer. They get reset between layers. 712 713 // hasDetail becomes true at each level of the formatRecursive() 714 // recursion after the first call to .Detail(). It is used to 715 // determine how to translate buf/headBuf into a formatEntry. 716 hasDetail bool 717 718 // wantDetail is set to true when the error is formatted via %+v. 719 // When false, printer.Detail() will always return false and the 720 // error's .FormatError() method can perform less work. (This is an 721 // optimization for the common case when an error's .Error() method 722 // delegates its work to its .FormatError() via fmt.Format and 723 // errors.FormatError().) 724 wantDetail bool 725 726 // collectingRedactableString is true iff the data being accumulated 727 // into buf comes from a redact string. It ensures that newline 728 // characters are not included inside redaction markers. 729 collectingRedactableString bool 730 731 // notEmpty tracks, at each level of recursion of formatRecursive(), 732 // whether there were any details printed by an error's 733 // .FormatError() method. It is used to properly determine whether 734 // the printout should start with a newline and padding. 735 notEmpty bool 736 // needSpace tracks whether the next character displayed should pad 737 // using a space character. 738 needSpace bool 739 // needNewline tracks whether the next character displayed should 740 // pad using a newline and indentation. 741 needNewline int 742 // multiLine tracks whether the details so far contain multiple 743 // lines. It is used to determine whether an enclosed stack trace, 744 // if any, should be introduced with a separator. 745 multiLine bool 746 } 747 748 // formatEntry collects the textual details about one level of 749 // wrapping or the leaf error in an error chain. 750 type formatEntry struct { 751 err error 752 // redactable is true iff the data in head and details 753 // are RedactableBytes. See the explanatory comments 754 // on (state).buf for when this is set. 755 redactable bool 756 // head is the part of the text that is suitable for printing in the 757 // one-liner summary, or when producing the output of .Error(). 758 head []byte 759 // details is the part of the text produced in the advanced output 760 // included for `%+v` formats. 761 details []byte 762 // elideShort, if true, elides the value of 'head' from concatenated 763 // "short" messages produced by formatSingleLineOutput(). 764 elideShort bool 765 766 // stackTrace, if non-nil, reports the stack trace embedded at this 767 // level of error. 768 stackTrace StackTrace 769 // elidedStackTrace, if true, indicates that the stack trace was 770 // truncated to avoid duplication of entries. This is used to 771 // display a truncation indicator during verbose rendering. 772 elidedStackTrace bool 773 774 // depth, if positive, represents a nesting depth of this error as 775 // a causer of others. This is used with verbose printing to 776 // illustrate the nesting depth for multi-cause error wrappers. 777 depth int 778 } 779 780 // String is used for debugging only. 781 func (e formatEntry) String() string { 782 return fmt.Sprintf("formatEntry{%T, %q, %q}", e.err, e.head, e.details) 783 } 784 785 // Write implements io.Writer. 786 func (s *state) Write(b []byte) (n int, err error) { 787 if len(b) == 0 { 788 return 0, nil 789 } 790 k := 0 791 792 sep := detailSep 793 if !s.wantDetail { 794 sep = []byte("\n") 795 } 796 797 for i, c := range b { 798 if c == '\n' { 799 //if s.needNewline > 0 { 800 // for i := 0; i < s.needNewline-1; i++ { 801 // s.buf.Write(detailSep[:len(sep)-1]) 802 // } 803 // s.needNewline = 0 804 //} 805 // Flush all the bytes seen so far. 806 s.buf.Write(b[k:i]) 807 // Don't print the newline itself; instead, prepare the state so 808 // that the _next_ character encountered will pad with a newline. 809 // This algorithm avoids terminating error details with excess 810 // newline characters. 811 k = i + 1 812 s.needNewline++ 813 s.needSpace = false 814 s.multiLine = true 815 if s.wantDetail { 816 s.switchOver() 817 } 818 } else { 819 if s.needNewline > 0 && s.notEmpty { 820 // If newline chars were pending, display them now. 821 for i := 0; i < s.needNewline-1; i++ { 822 s.buf.Write(detailSep[:len(sep)-1]) 823 } 824 s.buf.Write(sep) 825 s.needNewline = 0 826 s.needSpace = false 827 } else if s.needSpace { 828 s.buf.WriteByte(' ') 829 s.needSpace = false 830 } 831 s.notEmpty = true 832 } 833 } 834 //if s.needNewline > 0 { 835 // for i := 0; i < s.needNewline-1; i++ { 836 // s.buf.Write(detailSep[:len(sep)-1]) 837 // } 838 //} 839 s.buf.Write(b[k:]) 840 return len(b), nil 841 } 842 843 // printer wraps a state to implement an xerrors.Printer. 844 type printer state 845 846 func (p *state) detail() bool { 847 if !p.wantDetail { 848 return false 849 } 850 if p.notEmpty { 851 p.needNewline = 1 852 } 853 p.switchOver() 854 return true 855 } 856 857 func (p *state) switchOver() { 858 if p.hasDetail { 859 return 860 } 861 p.headBuf = p.buf.Bytes() 862 p.buf = bytes.Buffer{} 863 p.notEmpty = false 864 p.hasDetail = true 865 866 // One of the newlines is accounted for in the switch over. 867 // p.needNewline -= 1 868 } 869 870 func (s *printer) Detail() bool { 871 return ((*state)(s)).detail() 872 } 873 874 func (s *printer) Print(args ...interface{}) { 875 s.enhanceArgs(args) 876 fmt.Fprint((*state)(s), args...) 877 } 878 879 func (s *printer) Printf(format string, args ...interface{}) { 880 s.enhanceArgs(args) 881 fmt.Fprintf((*state)(s), format, args...) 882 } 883 884 func (s *printer) enhanceArgs(args []interface{}) { 885 prevStack := s.lastStack 886 lastSeen := prevStack 887 for i := range args { 888 if st, ok := args[i].(pkgErr.StackTrace); ok { 889 args[i], _ = ElideSharedStackTraceSuffix(prevStack, st) 890 lastSeen = st 891 } 892 if err, ok := args[i].(error); ok { 893 args[i] = &errorFormatter{err} 894 } 895 } 896 s.lastStack = lastSeen 897 } 898 899 // safePrinter is a variant to printer used when the current error 900 // level implements SafeFormatter. 901 // 902 // In any case, it uses the error's SafeFormatError() method to 903 // prepare a RedactableBytes into s.buf / s.headBuf. 904 // The the explanation for `buf` in the state struct. 905 type safePrinter state 906 907 func (s *safePrinter) Detail() bool { 908 return ((*state)(s)).detail() 909 } 910 911 func (s *safePrinter) Print(args ...interface{}) { 912 s.enhanceArgs(args) 913 redact.Fprint((*state)(s), args...) 914 } 915 916 func (s *safePrinter) Printf(format string, args ...interface{}) { 917 s.enhanceArgs(args) 918 redact.Fprintf((*state)(s), format, args...) 919 } 920 921 func (s *safePrinter) enhanceArgs(args []interface{}) { 922 prevStack := s.lastStack 923 lastSeen := prevStack 924 for i := range args { 925 if st, ok := args[i].(pkgErr.StackTrace); ok { 926 thisStack, _ := ElideSharedStackTraceSuffix(prevStack, st) 927 // Stack traces are safe strings. 928 args[i] = redact.Safe(thisStack) 929 lastSeen = st 930 } 931 // In contrast with (*printer).enhanceArgs(), we don't use a 932 // special case for `error` here, because the redact package 933 // already helps us recursing into a safe print for 934 // error objects. 935 } 936 s.lastStack = lastSeen 937 } 938 939 type errorFormatter struct{ err error } 940 941 // Format implements the fmt.Formatter interface. 942 func (ef *errorFormatter) Format(s fmt.State, verb rune) { FormatError(ef.err, s, verb) } 943 944 // Error implements error, so that `redact` knows what to do with it. 945 func (ef *errorFormatter) Error() string { return ef.err.Error() } 946 947 // Unwrap makes it a wrapper. 948 func (ef *errorFormatter) Unwrap() error { return ef.err } 949 950 // Cause makes it a wrapper. 951 func (ef *errorFormatter) Cause() error { return ef.err } 952 953 // ElideSharedStackTraceSuffix removes the suffix of newStack that's already 954 // present in prevStack. The function returns true if some entries 955 // were elided. 956 func ElideSharedStackTraceSuffix(prevStack, newStack StackTrace) (StackTrace, bool) { 957 if len(prevStack) == 0 { 958 return newStack, false 959 } 960 if len(newStack) == 0 { 961 return newStack, false 962 } 963 964 // Skip over the common suffix. 965 var i, j int 966 for i, j = len(newStack)-1, len(prevStack)-1; i > 0 && j > 0; i, j = i-1, j-1 { 967 if newStack[i] != prevStack[j] { 968 break 969 } 970 } 971 if i == 0 { 972 // Keep at least one entry. 973 i = 1 974 } 975 return newStack[:i], i < len(newStack)-1 976 } 977 978 // StackTrace is the type of the data for a call stack. 979 // This mirrors the type of the same name in github.com/pkg/errors. 980 type StackTrace = pkgErr.StackTrace 981 982 // StackFrame is the type of a single call frame entry. 983 // This mirrors the type of the same name in github.com/pkg/errors. 984 type StackFrame = pkgErr.Frame 985 986 // StackTraceProvider is a provider of StackTraces. 987 // This is, intendedly, defined to be implemented by pkg/errors.stack. 988 type StackTraceProvider interface { 989 StackTrace() StackTrace 990 }