Documentation
¶
Overview ¶
Package errors provides a structured and extensible way to create, wrap, and manage errors in Go applications. It includes support for adding contextual information, managing error hierarchies, and setting attributes such as severity, HTTP status codes, and custom error codes.
The package is designed to enhance error handling by allowing developers to attach additional metadata to errors, wrap underlying errors with more context, and facilitate debugging and logging. It also supports integration with alerting systems through the Alarm method.
Key features include: - Wrapping errors with additional context. - Setting custom attributes like severity, status codes, and business codes. - Managing error stacks and hierarchies. - Sending alerts for critical errors. - Support for custom key-value pairs to enrich error information. - Integration with predefined error types for common scenarios. - Serialization errors for easy logging.
Index ¶
- Constants
- Variables
- func As(err error, target any) bool
- func AsType[E error](err error) (E, bool)
- func Is(err error, target error) bool
- func Join(errs ...error) error
- func New(msg string) error
- func SetAlarmer(a Alarmer)
- func ToJSON(err error, opts ...Option) []byte
- func Unwrap(err error) error
- type Alarmer
- type Error
- func (e *Error) Alarm()
- func (e *Error) Code(code string) *Error
- func (e *Error) Error() string
- func (e *Error) Is(target error) bool
- func (e *Error) Msg(s string) *Error
- func (e *Error) Protected(protected bool) *Error
- func (e *Error) Set(key string, value any) *Error
- func (e *Error) Severity(severity SeverityLevel) *Error
- func (e *Error) StatusCode(statusCode int) *Error
- func (e *Error) Unwrap() error
- func (e *Error) Wrap(err error) *Error
- func (err *Error) WrappedErrors() []Error
- type ErrorFormattingOptions
- type ErrorSerializationRule
- type ErrorTemplate
- func (et *ErrorTemplate) Code(code string) *ErrorTemplate
- func (et *ErrorTemplate) Error() string
- func (et *ErrorTemplate) New() *Error
- func (et *ErrorTemplate) Protected(protected bool) *ErrorTemplate
- func (et *ErrorTemplate) Set(key string, value any) *ErrorTemplate
- func (et *ErrorTemplate) Severity(severity SeverityLevel) *ErrorTemplate
- func (et *ErrorTemplate) StatusCode(statusCode int) *ErrorTemplate
- func (et *ErrorTemplate) Wrap(err error) *Error
- type Option
- type SerializedError
- type SeverityLevel
- type StackFrame
Examples ¶
Constants ¶
const ( ServerOutputFormat = AddProtected | AddStack | AddFields | AddWrappedErrors ServerDebugOutputFormat = AddProtected | AddStack | AddFields | AddWrappedErrors | IndentJSON ClientDebugOutputFormat = AddProtected | AddStack | AddFields | AddWrappedErrors ClientOutputFormat = 0 // no fields, no stack, no wrapped errors, only message. )
Predefined sets of serialization rules. A typical setup writes ServerOutputFormat to the server log and sends ClientOutputFormat to the client in production or ClientDebugOutputFormat in development, so the client gets the same JSON as the log.
Variables ¶
var ( // CallerFramesFunc holds the function used to collect call frames // when an error is created or wrapped. The offset has the same meaning // as the skip argument of runtime.Callers called inside the collector. CallerFramesFunc func(offset int) []StackFrame = DefaultCallerFrames // CallingStackMaxLen holds maximum elements in the call frames. CallingStackMaxLen int = 16 )
var ErrMarshalError = Template("error marshaling failed").Severity(Critical).StatusCode(500)
var ErrUnsupported = se.ErrUnsupported
ErrUnsupported is the standard errors.ErrUnsupported, so errors.Is works the same with both packages.
Functions ¶
func As ¶ added in v0.0.2
As finds the first error in err's chain that matches target, and if one is found, sets target to that error value and returns true.
If target is a pointer to a nil *Error, any *Error matches. If it points to a non-nil *Error, the error must match it by the rules of Is. Other targets are handled as by the standard errors.As.
func AsType ¶ added in v1.1.0
AsType finds the first error in err's chain that matches the type E, and if one is found, returns that error value and true. It works the same way as As and mirrors errors.AsType added in Go 1.26.
func Is ¶ added in v0.0.2
Is reports whether any error in err's chain matches target.
An *Error matches an *ErrorTemplate if it was created from the template by New or Wrap, even if Msg, StatusCode and others changed its attributes, or if all attributes (message, severity, status code, code, protected) are equal. Two *Error values match if they are the same, were created from the same template or have equal attributes. Other errors are compared as by the standard errors.Is.
func Join ¶ added in v1.1.0
Join returns an error that wraps the given errors. Nil errors are discarded. Join returns nil if every value in errs is nil. It is the standard errors.Join.
func New ¶
New creates and returns a standard Go error using the built-in errors.New function.
This is implemented to maintain compatibility with existing Go error handling practices. However, the design philosophy of this package does not encourage the use of errors.New(msg) as commonly practiced in Go. Instead, it promotes the use of structured and enriched error handling mechanisms provided by this package.
func SetAlarmer ¶ added in v1.0.0
func SetAlarmer(a Alarmer)
SetAlarmer sets Alarmer implementation to be used by Error.Alarm and ToJSON.
func ToJSON ¶ added in v0.0.2
ToJSON serializes the error to JSON format.
Example ¶
ExampleToJSON demonstrates generating JSON output for an error.
package main
import (
"fmt"
"github.com/axkit/errors"
)
func main() {
jsonErr := errors.Template("User not found").Code("E404").StatusCode(404).Severity(errors.Tiny)
jsonOutput := errors.ToJSON(jsonErr, errors.WithAttributes(errors.AddFields))
fmt.Println("JSON Error:", string(jsonOutput))
}
Output: JSON Error: {"msg":"User not found","severity":"tiny","code":"E404","statusCode":404}
Types ¶
type Alarmer ¶ added in v0.0.2
type Alarmer interface {
Alarm(err error)
}
Alarmer is an interface wrapping a single method Alarm.
Alarm is called by Error.Alarm and when ToJSON fails to marshal an error, if alarmer is set.
Example ¶
package main
import (
"fmt"
"github.com/axkit/errors"
)
type CustomAlarmer struct{}
func (c *CustomAlarmer) Alarm(err error) {
fmt.Println("Critical error:", err)
}
func main() {
errors.SetAlarmer(&CustomAlarmer{})
var ErrSystemFailure = errors.Template("system failure").Severity(errors.Critical)
ErrSystemFailure.New().Set("path", "/var/lib").Alarm()
}
Output: Critical error: system failure
type Error ¶ added in v1.0.0
type Error struct {
// contains filtered or unexported fields
}
Error represents a structured error with metadata, custom fields, stack trace, and optional wrapping.
func Wrap ¶ added in v0.0.6
Wrap wraps an existing error with a new message, effectively creating a new error that includes the previous error.
If err is an *Error or *ErrorTemplate, the new error inherits its severity, status code, code, protected flag, fields and stack trace. The wrapped error stays in the chain, so Error() returns "message: <err.Error()>". The wrapped error itself is not modified.
Example ¶
ExampleWrap demonstrates wrapping an error.
package main
import (
"fmt"
"github.com/axkit/errors"
)
func main() {
innerErr := errors.Template("Database connection failed")
outerErr := errors.Template("Service initialization failed").Wrap(innerErr)
fmt.Println("Wrapped Error:", outerErr.Error())
}
Output: Wrapped Error: Service initialization failed: Database connection failed
func (*Error) Alarm ¶ added in v1.0.0
func (e *Error) Alarm()
Alarm triggers an alert for the error if an alarmer is configured.
func (*Error) Error ¶ added in v1.0.0
Error returns the error message, including any wrapped error messages.
Example ¶
package main
import (
"fmt"
"github.com/axkit/errors"
)
func main() {
type Input struct {
ID int `json:"id"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
var ErrEmptyAttribute = errors.Template("empty attribute value").Code("CMN-0400")
var ErrInvalidInput = errors.Template("invalid input").Code("CMN-0400")
validateInput := func(inp *Input) error {
if inp.ID == 0 {
return ErrEmptyAttribute.New().Set("emptyFields", []string{"id"})
}
return nil
}
if err := validateInput(&Input{}); err != nil {
returnErr := ErrInvalidInput.Wrap(err)
fmt.Println(returnErr.Error())
}
}
Output: invalid input: empty attribute value
func (*Error) Is ¶ added in v1.1.0
Is reports whether the error matches target using the same rules as the package Is. It lets the standard errors.Is match templates through other wrappers, for example fmt.Errorf("...: %w", err).
func (*Error) Msg ¶ added in v1.0.0
Msg sets the error message and marks the error as not being a pure wrapper.
func (*Error) Protected ¶ added in v1.0.0
Protected marks the error as protected to prevent certain modifications or exposure.
func (*Error) Set ¶ added in v1.0.0
Set adds or updates a custom key-value pair in the error's fields.
func (*Error) Severity ¶ added in v1.0.0
func (e *Error) Severity(severity SeverityLevel) *Error
Severity sets the severity level for the error.
func (*Error) StatusCode ¶ added in v1.0.0
StatusCode sets the associated HTTP status code for the error.
func (*Error) Unwrap ¶ added in v1.1.0
Unwrap returns the wrapped error, so the standard errors.Is and errors.As can walk the chain.
func (*Error) Wrap ¶ added in v1.0.0
Wrap returns a new Error that wraps the given error while retaining the current error's metadata and fields. It also preserves the stack trace of the wrapped error if available. The new error is marked as a pure wrapper if the original error is of type ErrorTemplate or Error. If the original error is nil, it returns the current error. This method is useful for chaining errors and maintaining context. It supports wrapping both ErrorTemplate and Error types, preserving their fields and stack trace.
func (*Error) WrappedErrors ¶ added in v1.0.0
WrappedErrors returns a slice of all wrapped errors, including the current one if it's not a pure wrapper.
type ErrorFormattingOptions ¶ added in v1.0.0
type ErrorFormattingOptions struct {
// contains filtered or unexported fields
}
type ErrorSerializationRule ¶ added in v1.0.0
type ErrorSerializationRule uint8
const ( // AddStack - add stack in the JSON. AddStack ErrorSerializationRule = 1 << iota // AddProtected - add protected errors to the "wrapped" list in the JSON. // Without it, wrapped errors marked with Protected(true) are skipped. // The top-level error is always written as is: it should not be protected, // wrap it with a public template before returning it to the client. AddProtected // AddFields - add custom fields set by Set() in the JSON. // Fields listed in WithRootLevelFields are written regardless of this rule. AddFields // AddWrappedErrors - add previous errors in the JSON. AddWrappedErrors // IndentJSON - write indented JSON. IndentJSON )
type ErrorTemplate ¶ added in v1.0.0
type ErrorTemplate struct {
// contains filtered or unexported fields
}
ErrorTemplate defines a reusable error blueprint that includes metadata and custom key-value fields. It is designed for creating structured errors with consistent attributes such as severity and HTTP status code.
Example ¶
ExamplePredefinedErrors demonstrates using predefined errors.
package main
import (
"fmt"
"github.com/axkit/errors"
)
func main() {
var ErrDatabaseDown = errors.Template("Database is unreachable").
Code("DB-500").
StatusCode(500).
Severity(errors.Critical)
if err := openDatabase("pg:5432"); err != nil {
fmt.Println("Error:", ErrDatabaseDown.Wrap(err).Error())
}
}
func openDatabase(connStr string) error {
var dbErr error
return errors.Wrap(dbErr, "unable to connect to database").Set("connectionString", connStr)
}
Output: Error: Database is unreachable: unable to connect to database
func Template ¶ added in v1.0.0
func Template(msg string) *ErrorTemplate
Template returns a new ErrorTemplate initialized with the given message. It can be extended with additional attributes and reused to create multiple error instances.
func (*ErrorTemplate) Code ¶ added in v1.0.0
func (et *ErrorTemplate) Code(code string) *ErrorTemplate
Code sets an application-specific error code on the template.
func (*ErrorTemplate) Error ¶ added in v1.0.0
func (et *ErrorTemplate) Error() string
Error returns the error message from the template.
func (*ErrorTemplate) New ¶ added in v1.0.0
func (et *ErrorTemplate) New() *Error
New creates a new Error instance using the template's metadata and fields. A new stack trace is captured at the point of the call.
func (*ErrorTemplate) Protected ¶ added in v1.0.0
func (et *ErrorTemplate) Protected(protected bool) *ErrorTemplate
Protected marks the error as protected, indicating it should not be exposed externally.
func (*ErrorTemplate) Set ¶ added in v1.0.0
func (et *ErrorTemplate) Set(key string, value any) *ErrorTemplate
Set adds a custom key-value pair to the template's fields.
func (*ErrorTemplate) Severity ¶ added in v1.0.0
func (et *ErrorTemplate) Severity(severity SeverityLevel) *ErrorTemplate
Severity sets the severity level for the error template.
func (*ErrorTemplate) StatusCode ¶ added in v1.0.0
func (et *ErrorTemplate) StatusCode(statusCode int) *ErrorTemplate
StatusCode sets the HTTP status code associated with the error.
func (*ErrorTemplate) Wrap ¶ added in v1.0.0
func (et *ErrorTemplate) Wrap(err error) *Error
Wrap wraps an existing error with the ErrorTemplate's metadata and fields. It supports wrapping both ErrorTemplate and Error types, preserving their fields and stack trace.
type Option ¶ added in v1.0.0
type Option func(*ErrorFormattingOptions)
func WithAttributes ¶ added in v1.0.0
func WithAttributes(rule ErrorSerializationRule) Option
WithAttributes sets which parts of the error are written to the output. Without it only message, severity, code and status code are written.
func WithRootLevelFields ¶ added in v1.0.0
WithRootLevelFields moves the listed fields from "fields" to the root of the JSON object. The listed fields are written even if AddFields is not set.
func WithStopStackOn ¶ added in v1.0.0
WithStopStackOn sets the function name to stop the adding stack frames. The first frame whose function name contains the string and all frames after it are not written. As instance: WithStopStackOn("fasthttp") will stop adding stack frames when the function name contains "fasthttp". It's useful to avoid adding stack frames of the libraries which are not interesting for the user.
type SerializedError ¶ added in v1.0.0
type SerializedError struct {
Message string `json:"msg"`
Severity string `json:"severity,omitempty"`
Code string `json:"code,omitempty"`
StatusCode int `json:"statusCode,omitempty"`
Fields map[string]any `json:"fields,omitempty"`
Wrapped []SerializedError `json:"wrapped,omitempty"`
Stack []StackFrame `json:"stack,omitempty"`
}
SerializedError is serialization ready error.
func Serialize ¶ added in v1.0.0
func Serialize(err error, opts ...Option) *SerializedError
Serialize serializes the error to a SerializedError struct.
type SeverityLevel ¶
type SeverityLevel int
SeverityLevel describes error severity levels.
const ( Unknown SeverityLevel = iota // Tiny classifies expected, managed errors that do not require administrator attention. // Writing a call stack to the journal file is not recommended. // // Example: error related to validation of entered form fields. Tiny // Medium classifies a regular error. A call stack is written to the log. Medium // Critical classifies a significant error, requiring immediate attention. // The occurrence of the error should be communicated to the administrator // through all available channels. A call stack is written to the log. // If Alarmer is set, it will be called. Critical )
func (SeverityLevel) MarshalJSON ¶
func (sl SeverityLevel) MarshalJSON() ([]byte, error)
MarshalJSON implements json/Marshaller interface.
func (SeverityLevel) String ¶
func (sl SeverityLevel) String() string
String returns severity level string representation.
func (*SeverityLevel) UnmarshalJSON ¶ added in v1.0.0
func (sl *SeverityLevel) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json/Unmarshaller interface.
type StackFrame ¶ added in v1.0.0
type StackFrame struct {
Function string `json:"func"`
File string `json:"file"`
Line int `json:"-"`
}
StackFrame describes content of a single stack frame stored with error.
File holds "path:line", so IDEs and terminals open it on click. Line holds the same line number for use in Go code. It is not written to JSON to avoid duplication and is restored from File on unmarshal.
func DefaultCallerFrames ¶ added in v0.0.2
func DefaultCallerFrames(offset int) []StackFrame
DefaultCallerFrames returns default implementation of call frames collector. The offset is the number of frames to skip, as in runtime.Callers: 0 is runtime.Callers itself, 1 is DefaultCallerFrames, 2 is its caller. The runtime.goexit frame is never included.
func (StackFrame) String ¶ added in v1.0.0
func (s StackFrame) String() string
String returns the frame as "file:line function". File collected by DefaultCallerFrames already ends with ":line", in that case the line is not appended twice.
func (*StackFrame) UnmarshalJSON ¶ added in v1.1.0
func (s *StackFrame) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. Line is taken from the "line" key if present (JSON written before v1.1.0), otherwise it is parsed from the ":line" suffix of File.