formatErrorInternal is the shared logic between FormatError and FormatErrorRedactable. When the redactableOutput argument is true, the fmt.State argument is really a redact.SafePrinter and casted down as necessary. If verb and flags are not one of the supported error formatting combinations (in pa
(err error, s fmt.State, verb rune, redactableOutput bool)
| 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 | // |
no test coverage detected
searching dependent graphs…