Documentation ¶
Overview ¶
Package terror is an error-handling library.
Errors wrapped by this package include the code location that the error was wrapped at. They print detailed stack information when formatted via the "%v" printf directive. Otherwise, they print only the message prefix.
That is, given:
err := terror.New("some error") err = terror.Wrap(err, "loading config") err = terror.Wrap(err, "initializing %s", "system")
Then
fmt.Println(err) fmt.Println(err.Error()) fmt.Printf("%s", err)
will each print
initializing system: loading config: some error
But
fmt.Printf("%v", err) fmt.Printf("%+v", err) fmt.Printf("%#v", err)
will print
initializing system --- at path/to/my/pkg/system.go:123 (system.Initialize) --- caused by loading config --- at path/to/my/pkg/config.go:37 (system.LoadConfig) --- caused by some error --- at path/to/my/pkg/config.go:62 (system.ReadConfig) ---
Error formatting notes ¶
Most error libraries that include call site information have settled on only printing stack details when the error is formatted via "%+v". However, much existing code at Tanium only logs error using "%v". We therefore strongly encourage users to use "%+v" when logging errors and wanting to show detailed stack information, but we will support "%v" until a satisfactory auditing mechanism can be achieved.
Using fmt.Errorf to wrap an error commits to using the detailed format.
This library is inspired by github.com/palantir/stacktrace.
Example ¶
package main import ( "fmt" "os" "github.com/Tanium-OSS/terror" ) type Config struct{} func ReadConfig(filename string) (Config, error) { _, err := os.ReadFile(filename) return Config{}, terror.WrapWithCode(err, 123, "loading config") } type System struct{} func InitializeSystem(configPath string) (System, error) { _, err := ReadConfig(configPath) return System{}, terror.Wrap(err, "initializing system") } func main() { _, err := InitializeSystem("oops where mah bucket?") fmt.Println(err) // prints stack details fmt.Println(err.Error()) // prints short message only fmt.Printf("%s\n", err) // prints short message only fmt.Printf("%+v\n", err) // prints stack details fmt.Printf("Error code: %d\n", terror.GetCode(err)) }
Output: initializing system --- at terror/example_test.go:21 (InitializeSystem) --- caused by loading config --- at terror/example_test.go:14 (ReadConfig) --- caused by open oops where mah bucket?: no such file or directory initializing system: loading config: open oops where mah bucket?: no such file or directory initializing system: loading config: open oops where mah bucket?: no such file or directory initializing system --- at terror/example_test.go:21 (InitializeSystem) --- caused by loading config --- at terror/example_test.go:14 (ReadConfig) --- caused by open oops where mah bucket?: no such file or directory Error code: 123
Index ¶
- Variables
- func Annotate(err error) error
- func CloseAndAppendOnError(pErr *error, c io.Closer, format string, args ...interface{})
- func CloseAndLogOnError(fn func(template string, args ...interface{}), closers ...io.Closer)
- func GetCode(err error) int
- func New(format string, args ...interface{}) error
- func NewWithCode(code int, format string, args ...interface{}) error
- func Wrap(err error, format string, args ...interface{}) error
- func WrapInto(pErr *error, format string, args ...interface{})
- func WrapWithCode(err error, code int, format string, args ...interface{}) error
- type Const
- type Error
- type Location
- type TError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var CleanFileName = func(filename string) string {
return filename
}
CleanFileName is a process global hook that enables sanitizing filenames in stack traces.
Functions ¶
func Annotate ¶
Annotate annotates the provided error with the file and line of the call. If err is nil, Annotate returns nil.
func CloseAndAppendOnError ¶
CloseAndAppendOnError is a helper function that makes it easier to close Closers in defer statements and still capture any errors that arise during closing. Use this function when a failure to Close() indicates that something has gone wrong and it should not be ignored. For example, when writing to a file, a failure to Close() the file may indicate that not all of the bytes were in fact written, even if the call to Write() did not return an error. This should always be used with named return variables. See https://play.golang.org/p/ECMc6EfWXxt for examples of what can go wrong if a local variable is used instead.
Example ¶
errExample := func() (err error) { file := allocateExampleResource() defer CloseAndAppendOnError(&err, file, "close file") if err := file.Use(); err != nil { return Wrap(err, "first use") } if err := file.Use(); err != nil { return Wrap(err, "second use") } return nil }() fmt.Println(errExample)
Output: first use: could not use; close file: could not close
func CloseAndLogOnError ¶
CloseAndLogOnError is a helper function that makes it easier to close Closers in defer statements and still log any errors that arise during closing. Use this function when closing closers where a failure to Close() can happen and the errors cannot be handled.
func GetCode ¶
GetCode returns the error code most recently added via WrapWithCode or NewWithCode. If no error code is present or the error is not created by this package, 0 is returned.
func New ¶
New creates an error with the specified message as well as the location of this call. This is a drop-in replacement for fmt.Errorf.
func NewWithCode ¶
NewWithCode creates an error with the specified message as well as the location of this call and a specified error code. The error code can be retrieved using GetCode().
func Wrap ¶
Wrap annotates the provided error with the file and line of the call along with the provided message. The format and args are formatted printf style. If err is nil, Wrap returns nil.
func WrapInto ¶
WrapInto annotates the provided error with the file and line of the call along with the provided message. The format and args are formatted printf style. If * pErr is nil, WrapInto is a no-op.
The intended use is to use defer with a named return variable to provide additional context. If deferred, it will capture the line of the return statement, not the line of the defer statement.
Example ¶
checkComputer := func() error { return nil } getQuestionForAnswer := func(answer string) (question string, err error) { // Set up error handling for this function. defer WrapInto(&err, "getQuestionForAnswer(%q)", answer) err = checkComputer() if err != nil { // Can also call Wrap here, if there is additional context to provide for this one error. return "", err } // Can defer another WrapInto, if there is additional context to provide for all subsequent errors. if answer == "42" { return "What is the answer to the ultimate question of life, the universe, and everything?", nil } return "", New("insufficient cheese") } _, errExample := getQuestionForAnswer("five tons of flax") fmt.Println(errExample.Error())
Output: getQuestionForAnswer("five tons of flax"): insufficient cheese
func WrapWithCode ¶
WrapWithCode annotates the provided error with the file and line of the call along with the provided message and a specified error code. The error code can be retrieved using GetCode(). The format and args are formatted printf style. If err is nil, Wrap returns nil.
Types ¶
type Const ¶
type Const string
Const defines a type of error without capturing the line where it was defined. To use it in a function, call terror.Wrap func to capture the line where it is being wrapped, within the function. It can be returned directly to improve performance in tight loops if necessary. Compared to combining errors.New, it can be assigned to a const.
Example ¶
package main import ( "fmt" ) const errTestError = Const("test error") func main() { err := Wrap(errTestError, "in test %q", "ExampleConstError") fmt.Println(err.Error()) }
Output: in test "ExampleConstError": test error
type Error ¶
Error represents the terror-wrapped error which includes additional information such as the stack trace.
type TError ¶
type TError struct {
// contains filtered or unexported fields
}
TError is the wrapped error implementation.
func (TError) Format ¶
Format implements fmt.Formatter so that we know when we're being formatted by a Printf-style func. This detects when we're being printed specifically by "%v" in which case we output the detailed stack trace.