Documentation ¶
Overview ¶
Package stacktrace provides functions for wrapping an error to include line number and/or error code information.
A stacktrace produced by this package looks like this:
Failed to register for villain discovery --- at github.com/palantir/shield/agent/discovery.go:265 (ShieldAgent.reallyRegister) --- --- at github.com/palantir/shield/connector/impl.go:89 (Connector.Register) --- Caused by: Failed to load S.H.I.E.L.D. config from /opt/shield/conf/shield.yaml --- at github.com/palantir/shield/connector/config.go:44 (withShieldConfig) --- Caused by: There isn't enough time (4 picoseconds required) --- at github.com/palantir/shield/axiom/pseudo/resource.go:46 (PseudoResource.Adjust) --- --- at github.com/palantir/shield/axiom/pseudo/growth.go:110 (reciprocatingPseudo.growDown) --- --- at github.com/palantir/shield/axiom/pseudo/growth.go:121 (reciprocatingPseudo.verify) --- Caused by: Inverse tachyon pulse failed --- at github.com/palantir/shield/metaphysic/tachyon.go:72 (TryPulse) ---
Note that stack traces are not designed to be user-visible. They can be valuable in a log file of a server application, but nobody wants to see one of them in CLI output or a web interface or a return value from library code.
Index ¶
- Variables
- func NewError(msg string, vals ...interface{}) error
- func NewErrorWithCode(code ErrorCode, msg string, vals ...interface{}) error
- func NewMessageWithCode(code ErrorCode, msg string, vals ...interface{}) error
- func Propagate(cause error, msg string, vals ...interface{}) error
- func PropagateWithCode(cause error, code ErrorCode, msg string, vals ...interface{}) error
- func RootCause(err error) error
- type ErrorCode
- type Format
Constants ¶
This section is empty.
Variables ¶
var CleanPath = cleanpath.RemoveGoPath
CleanPath function is applied to file paths before adding them to a stacktrace. By default, it makes the path relative to the $GOPATH environment variable.
To remove some additional prefix like "github.com" from file paths in stacktraces, use something like:
stacktrace.CleanPath = func(path string) string { path = cleanpath.RemoveGoPath(path) path = strings.TrimPrefix(path, "github.com/") return path }
var DefaultFormat = FormatFull
DefaultFormat defines the behavior of err.Error() when called on a stacktrace, as well as the default behavior of the "%v", "%s" and "%q" formatting specifiers. By default, all of these produce a full stacktrace including line number information. To have them produce a condensed single-line output, set this value to stacktrace.FormatBrief.
The formatting specifier "%+s" can be used to force a full stacktrace regardless of the value of DefaultFormat. Similarly, the formatting specifier "%#s" can be used to force a brief output.
Functions ¶
func NewError ¶
NewError is a drop-in replacement for fmt.Errorf that includes line number information. The canonical call looks like this:
if !IsOkay(arg) { return stacktrace.NewError("Expected %v to be okay", arg) }
func NewErrorWithCode ¶
NewErrorWithCode is similar to NewError but also attaches an error code.
func NewMessageWithCode ¶
NewMessageWithCode returns an error that prints just like fmt.Errorf with no line number, but including a code. The error code mechanism can be useful by itself even where stack traces with line numbers are not warranted.
ttl := req.URL.Query().Get("ttl") if ttl == "" { return 0, stacktrace.NewMessageWithCode(EcodeBadInput, "Missing ttl query parameter") }
func Propagate ¶
Propagate wraps an error to include line number information. The msg and vals arguments work like the ones for fmt.Errorf.
The message passed to Propagate should describe the action that failed, resulting in the cause. The canonical call looks like this:
result, err := process(arg) if err != nil { return nil, stacktrace.Propagate(err, "Failed to process %v", arg) }
To write the message, ask yourself "what does this call do?" What does process(arg) do? It processes ${arg}, so the message is that we failed to process ${arg}.
Pay attention that the message is not redundant with the one in err. If it is not possible to add any useful contextual information beyond what is already included in an error, msg can be an empty string:
func Something() error { mutex.Lock() defer mutex.Unlock() err := reallySomething() return stacktrace.Propagate(err, "") }
If cause is nil, Propagate returns nil. This allows elision of some "if err != nil" checks.
func PropagateWithCode ¶
PropagateWithCode is similar to Propagate but also attaches an error code.
_, err := os.Stat(manifestPath) if os.IsNotExist(err) { return stacktrace.PropagateWithCode(err, EcodeManifestNotFound, "") }
Types ¶
type ErrorCode ¶
type ErrorCode uint16
ErrorCode is a code that can be attached to an error as it is passed/propagated up the stack.
There is no predefined set of error codes. You define the ones relevant to your application:
const ( EcodeManifestNotFound = stacktrace.ErrorCode(iota) EcodeBadInput EcodeTimeout )
The one predefined error code is NoCode, which has a value of math.MaxUint16. Avoid using that value as an error code.
An ordinary stacktrace.Propagate call preserves the error code of an error.
NoCode is the error code of errors with no code explicitly attached.
func GetCode ¶
GetCode extracts the error code from an error.
for i := 0; i < attempts; i++ { err := Do() if stacktrace.GetCode(err) != EcodeTimeout { return err } // try a few more times } return stacktrace.NewError("timed out after %d attempts", attempts)
GetCode returns the special value stacktrace.NoCode if err is nil or if there is no error code attached to err.