Documentation ¶
Overview ¶
Package xtrace provides the ability to generate a trace of wrapped errors from xerrors. This is facilitated through the Tracer type, the output of which can be customized with a TraceFormatter. For more information on how to wrap errors, see https://godoc.org/golang.org/x/xerrors.
Basic Usage ¶
The following example will print a trace of all of the wrapped errors to stderr.
package main import ( "errors" "github.com/ollien/xtrace" "golang.org/x/xerrors" ) func main() { baseErr := errors.New("aw shucks, something broke") err2 := xerrors.Errorf("things went wrong!: %w", baseErr) traceErr := xtrace.Trace(err2) if traceErr != nil { panic("can not trace") } // aw shucks, something broke // things went wrong! // github.com/ollien/xtrace.ExampleTracer_Format // /home/nick/Documents/code/xtrace/example.go:12 }
If more customization is desired, one can use a Tracer. One of Tracer's key features is its compatibility with fmt.
// ... tracer, err := xtrace.NewTracer(err2) if err != nil { panic("can not make tracer") } fmt.Printf("%v", tracer) // aw shucks, something broke // things went wrong!
You can also add %+v for more detailed information.
// ... fmt.Printf("%+v", tracer) // aw shucks, something broke // things went wrong! // github.com/ollien/xtrace.ExampleTracer_Format // /home/nick/Documents/code/xtrace/example.go:18
Using fmt is not required, though. You may instead read the errors one at a time from the trace with the ReadNext and Read functions.
// ... output, err := tracer.ReadNext() if err != nil { panic("can not read from tracer") } fmt.Println(output) // aw shucks, something broke
Customization ¶
All output of a Tracer can be customized. By default, the Tracer will ensure that all messages end in a newline. If you want more customization than that, then you can create your own TraceFormatter. For instance, to make all of your errors in all caps, you can use the following TraceFormatter.
type capsFormatter struct{} func (formatter capsFormatter) FormatTrace(previous []string, message string) string { return strings.ToUpper(message) }
You can then set a Tracer's TraceFormatter like so
tracer, err := NewTracer(err, Formatter(capsFormatter{}))
Index ¶
- func DetailedOutput(enabled bool) func(*Tracer) error
- func Formatter(formatter TraceFormatter) func(*Tracer) error
- func Naive(naive bool) func(*NewLineFormatter) error
- func NestingIndentation(indentation string) func(*NestedMessageFormatter) error
- func Ordering(method TraceOrderingMethod) func(*Tracer) error
- func Trace(baseErr error) error
- type NestedMessageFormatter
- type NewLineFormatter
- type NilFormatter
- type TraceFormatter
- type TraceOrderingMethod
- type Tracer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DetailedOutput ¶
DetailedOutput will enable detailed output when this is passed to NewTracer. While the specifics of this detailed output is defined by the xerrors.Formatter for the passed error, it will generally provide more detailed information about the error, such as the file and line number of the error. Defaults to true.
func Formatter ¶
func Formatter(formatter TraceFormatter) func(*Tracer) error
Formatter will set the given TracerFormatter as the formatter of the Tracer generated by NewTracer when this is passed to it. Defaults to NewLineFormatter.
func Naive ¶
func Naive(naive bool) func(*NewLineFormatter) error
Naive will set the naive flag when passed to NewNewLineFormatter. This flag, if set, will instruct the formatter to perform the naive version of this algorithm, which simply adds/removes a newline from the end of each message. xerrors has a habit of sending indentation in the previous line (i.e. "<error>\n "), so the naive algorithm produces weird output. Nevertheless, this may be desirable depending on the implementation of xerrors.Formatter, so it is left as an option. Defaults to false.
func NestingIndentation ¶
func NestingIndentation(indentation string) func(*NestedMessageFormatter) error
NestingIndentation sets the string used as indentation for the NestedMessageFormatter that is produced when this is passed to NewNestedMessageFormatter. Defaults to "\t".
func Ordering ¶
func Ordering(method TraceOrderingMethod) func(*Tracer) error
Ordering sets the order in which the traces will be outputted from the Read methods, when passed to NewTracer. Defaults to OldestFirstOrdering.
Example ¶
baseErr := errors.New("aw shucks, something broke") err2 := xerrors.Errorf("things went wrong!: %w", baseErr) tracer, err := NewTracer(err2, Ordering(NewestFirstOrdering)) if err != nil { panic("can not make tracer") } fmt.Printf("%v", tracer)
Output: things went wrong! aw shucks, something broke
Types ¶
type NestedMessageFormatter ¶
type NestedMessageFormatter struct {
// contains filtered or unexported fields
}
NestedMessageFormatter will leave the leading line with no indentation, but indents all lines following, stripping whitespace from the both the left and right of each line and replacing it with a newline, unless it is the last message. In this case, no newline is inserted, but whitespace is still stripped.
func NewNestedMessageFormatter ¶
func NewNestedMessageFormatter(options ...func(*NestedMessageFormatter) error) (*NestedMessageFormatter, error)
NewNestedMessageFormatter makes a new NestedMessageFormatter.
func (NestedMessageFormatter) FormatTrace ¶
func (formatter NestedMessageFormatter) FormatTrace(previousMessages []string, message string) string
FormatTrace formats the message as dictated by the contract for NestedMessageFormatter.
type NewLineFormatter ¶
type NewLineFormatter struct {
// contains filtered or unexported fields
}
NewLineFormatter ensures that all messages except the last end in a newline after all error content.
func NewNewLineFormatter ¶
func NewNewLineFormatter(options ...func(*NewLineFormatter) error) (*NewLineFormatter, error)
NewNewLineFormatter will make a new NewLineFormatter.
func (*NewLineFormatter) FormatTrace ¶
func (formatter *NewLineFormatter) FormatTrace(previousMessages []string, message string) (formatted string)
FormatTrace formats the message as dictated by the contract for NewLineFormatter.
type NilFormatter ¶
type NilFormatter struct{}
NilFormatter applies no formatting and returns the given message as xerrors sends them. Note that the messages that xerrors sends aren't always the most intuitive (e.g. there are no newlines after error messages), and the usage of this formatter is not strictly recommended. It is mainly provided for those that want a simple shim.
func NewNilFormatter ¶
func NewNilFormatter() *NilFormatter
NewNilFormatter makes a new NilFormatter.
func (NilFormatter) FormatTrace ¶
func (formatter NilFormatter) FormatTrace(previousMessages []string, message string) string
FormatTrace applies no formatting and returns the given message as is.
type TraceFormatter ¶
type TraceFormatter interface { // FormatTrace takes all previous messages and a message and will return a formatted message. Any previous message // may be updated based on the current message, and the outputted trace will respect these changes. FormatTrace(previousMessages []string, message string) string }
TraceFormatter allows for the formatting of any message in the given trace.
type TraceOrderingMethod ¶
type TraceOrderingMethod int
TraceOrderingMethod represents a way to order the errors within the produced trace.
const ( // OldestFirstOrdering orders the trace such that the root cause of the error comes first, with all subsequent // errors after it (default). OldestFirstOrdering TraceOrderingMethod = iota // NewestFirstOrdering orders the trace such that the root cause of the error comes last, with all subsequent // errors before it. NewestFirstOrdering )
type Tracer ¶
type Tracer struct {
// contains filtered or unexported fields
}
Tracer gets the trace of errors wrapped by xerrors.
func NewTracer ¶
NewTracer returns a new Tracer for the given error.
Example ¶
baseErr := errors.New("aw shucks, something broke") // capsFormatter is a custom formatter that simply applies strings.ToUpper to all messages tracer, err := NewTracer(baseErr, Formatter(capsFormatter{})) if err != nil { panic("can not make tracer") } output, err := tracer.ReadNext() if err != nil { panic("can not read from tracer") } fmt.Println(output)
Output: AW SHUCKS, SOMETHING BROKE
func (*Tracer) Format ¶
Format allows for tracer to implement fmt.Formatter. This will simply make a clone of the tracer and print out the full trace. DetailedOutput will be given when %+v is provided, and normal output when %v is provided.
Example ¶
baseErr := errors.New("aw shucks, something broke") err2 := xerrors.Errorf("things went wrong!: %w", baseErr) tracer, err := NewTracer(err2) if err != nil { panic("can not make tracer") } fmt.Printf("%v", tracer)
Output: aw shucks, something broke things went wrong!
func (*Tracer) Read ¶
Read implements the io.Reader interface. Will read up to len(dest) bytes of the current error. Note that this means dest will only be filled up the contents of the error, regardless of if there are other errors to be read in the error stack. Returns io.EOF when there are no more errors to read, but notably will not be returned when the last error is returned.
func (*Tracer) ReadNext ¶
ReadNext will read one unwrapped error and its associated trace If Read() has been called, but the buffer has not been exhausted, its contents will be discarded. Returns io.EOF when there are no more errors to read, but notably will not be returned when the last error is returned.