Documentation
¶
Overview ¶
zerrors provides additional features to standard errors package.
Build Tags: - zerrorstrace : Enables error tracing to work. Environmental Variables: - GO_ZERRORS=<value> - "file" : Output trace messages into a temporary file (case insensitive). - "stdout" : Output trace messages into the standard output (case insensitive). - "stderr" : Output trace messages into the standard error (case insensitive). - "discard" : Discard all trace messages (case insensitive). - other values are ignored.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Must ¶
Must panics if the given err is not nil. Must exits with panic(err) if the second argument err is not nil. If the err is nil, the value t is returned.
func MustNil ¶
func MustNil(err error)
MustNil panics if the given err is not nil. MustNil exits with panic(err) if the given err is not nil.
func ToMap ¶
ToMap returns the given error in map. If the given error implements the interface { Map() map[string]any }, is call the method Map(). ToMap repeatedly unwraps the given error by interfaxe{ Unwrap() error } or interface{ Unwrap []error }. ToMap returns nil map when the given error was nil.
Example ¶
package main
import (
"errors"
"fmt"
"github.com/aileron-projects/go/zerrors"
)
func main() {
e1 := errors.New("example1")
e2 := errors.New("example2")
fmt.Println(zerrors.ToMap(e1))
fmt.Println(zerrors.ToMap(fmt.Errorf("example3 [%w]", e1)))
fmt.Println(zerrors.ToMap(errors.Join(e1, e2)))
}
Output: map[message:example1] map[cause:map[message:example1] message:example3 [example1]] map[cause:[map[message:example1] map[message:example2]] message:example1 example2]
func ToSlogAttrs ¶
ToSlogAttrs returns the error in slog.Attr format. If the given error implements the interface { SlogAttrs() []slog.Attr }, is call the method SlogAttrs(). ToSlogAttrs repeatedly unwraps the given error by interfaxe{ Unwrap() error } or interface{ Unwrap []error }. ToSlogAttrs returns nil slice when the given error was nil.
Example ¶
package main
import (
"errors"
"fmt"
"github.com/aileron-projects/go/zerrors"
)
func main() {
e1 := errors.New("example1")
e2 := errors.New("example2")
fmt.Println(zerrors.ToSlogAttrs(e1))
fmt.Println(zerrors.ToSlogAttrs(fmt.Errorf("example3 [%w]", e1)))
fmt.Println(zerrors.ToSlogAttrs(errors.Join(e1, e2)))
}
Output: [message=example1] [message=example3 [example1] cause=[message=example1]] [message=example1 example2 cause.1=[message=example1] cause.2=[message=example2]]
func UnwrapErr ¶
UnwrapErr returns the result of calling the Unwrap method on err. If the given err implements Unwrap() that returns an error. Otherwise, UnwrapErr returns nil.
UnwrapErr only calls a method of the form "Unwrap() error". In particular UnwrapErr does not unwrap errors returned by errors.Join. See also UnwrapErrs and errors.Unwrap.
func UnwrapErrs ¶
UnwrapErrs returns the result of calling the Unwrap method on err. If the given err implements Unwrap() that returns a []error. Otherwise, UnwrapErrs returns nil slice.
UnwrapErrs only calls a method of the form "Unwrap() []error". In particular UnwrapErrs does not unwrap errors returned by [Wrap]. UnwrapErrs can unwrap errors returned by errors.Join. See also UnwrapErr and errors.Unwrap.
Types ¶
type Definition ¶
type Definition struct {
// Code is the error code.
// Code is compared in [Definition.Is].
Code string
// Kind is the error kind that this error belongs to.
// Kind is compared in [Definition.Is].
Kind string
// Message is the error message.
// Format string for fmt.Sprintf can be used.
// Message is NOT compared in [Definition.Is].
Message string
// Attrs are the attribution, or extra information, to this kind.
// Attrs are NOT compared in [Definition.Is].
Attrs map[string]string
}
Definition is the error definition.
func NewDefinition ¶
func NewDefinition(code, kind, message string, attrs map[string]string) *Definition
NewDefinition returns a new error definition. See Definition.
func (*Definition) Is ¶
func (d *Definition) Is(err error) bool
Is returns if the target err is the same as this definition.
func (*Definition) New ¶
func (d *Definition) New(cause error, values ...any) *Error
New returns a new Error instance from the definition. New does not fill the [Error.Frames]. Use Definition.NewStack when stack frames are necessary.
Example ¶
package main
import (
"fmt"
"io"
"github.com/aileron-projects/go/zerrors"
)
func main() {
// Define an error with detail template.
def := zerrors.NewDefinition("E123", "KindXXX", "example error. foo=%s bar=%s.", map[string]string{"foo": "bar"})
fmt.Println(def.New(nil, "FOO", "BAR").Error()) // With arguments.
fmt.Println(def.New(nil).Error()) // No arguments.
fmt.Println(def.New(nil, "FOO").Error()) // Insufficient arguments.
fmt.Println(def.New(nil, "FOO", "BAR", "BAZ").Error()) // Too many arguments.
fmt.Println(def.New(io.EOF, "FOO", "BAR").Error()) // With inner error.
}
Output: E123 KindXXX :example error. foo=FOO bar=BAR. (foo=bar) E123 KindXXX :example error. foo=%!s(MISSING) bar=%!s(MISSING). (foo=bar) E123 KindXXX :example error. foo=FOO bar=%!s(MISSING). (foo=bar) E123 KindXXX :example error. foo=FOO bar=BAR.%!(EXTRA string=BAZ) (foo=bar) E123 KindXXX :example error. foo=FOO bar=BAR. (foo=bar) [EOF]
func (*Definition) NewStack ¶
func (d *Definition) NewStack(cause error, values ...any) *Error
NewStack returns a new Error instance from the definition. NewStack fills [Error.Frames] field. Use Definition.New when stack frames are not necessary.
type Err ¶
type Err struct {
// Cause is the cause of this error.
Cause error
// Message is the fixed error message.
// Message is compared in the [Err.Is].
Message string
// Detail is the error detail.
// Detail is NOT compared in the [Err.Is].
Detail string
}
Err is the simple general error object. Use NewErr to create instances.
Example (Slog) ¶
package main
import (
"context"
"io"
"log/slog"
"os"
"github.com/aileron-projects/go/zerrors"
)
func main() {
opts := &slog.HandlerOptions{
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey && len(groups) == 0 { // Remove time to avoid test failure.
return slog.Attr{}
}
return a
},
}
lgJSON := slog.New(slog.NewJSONHandler(os.Stdout, opts))
lgText := slog.New(slog.NewTextHandler(os.Stdout, opts))
err := zerrors.NewErr(io.EOF, "example", "foo=%s", "bar")
lgJSON.InfoContext(context.Background(), "message.", "error", err.SlogAttrs())
lgText.InfoContext(context.Background(), "message.", "error", err.SlogAttrs())
}
Output: {"level":"INFO","msg":"message.","error":{"message":"example","detail":"foo=bar","cause":{"message":"EOF"}}} level=INFO msg=message. error.message=example error.detail="foo=bar" error.cause.message=EOF
func (*Err) Is ¶
Is returns if this error is identical to the given error. This can be used with errors.Is.
type Error ¶
type Error struct {
// Cause is the error cause.
Cause error `json:"cause,omitempty" msgpack:"cause,omitempty" xml:"cause,omitempty" yaml:"cause,omitempty"`
// Code is the error code, name or alias for the error.
// Code is compared in the [Errors.Is] method.
Code string `json:"code" msgpack:"code" xml:"code" yaml:"code"`
// Kind is the error kind.
Kind string `json:"kind" msgpack:"kind" xml:"kind" yaml:"kind"`
// Message is the error message.
Message string `json:"message" msgpack:"message" xml:"message" yaml:"message"`
// Attrs are the attribution, or extra information, to this error.
Attrs map[string]string `json:"attrs" msgpack:"attrs" xml:"attrs" yaml:"attrs"`
// Frames is the list of stack trace frames.
// Use [Error.WithStack] to fill this field.
Frames []Frame `json:"frames,omitempty" msgpack:"frames,omitempty" xml:"frames,omitempty" yaml:"frames,omitempty"`
}
Error is the general error type.
Example (Slog) ¶
package main
import (
"context"
"io"
"log/slog"
"os"
"github.com/aileron-projects/go/zerrors"
)
func main() {
opts := &slog.HandlerOptions{
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey && len(groups) == 0 { // Remove time to avoid test failure.
return slog.Attr{}
}
return a
},
}
lgJSON := slog.New(slog.NewJSONHandler(os.Stdout, opts))
lgText := slog.New(slog.NewTextHandler(os.Stdout, opts))
def := zerrors.NewDefinition("E123", "KindXXX", "example. foo=%s", map[string]string{"tag": "val"})
err := def.New(io.EOF, "bar")
lgJSON.InfoContext(context.Background(), "message.", "error", err.SlogAttrs())
lgText.InfoContext(context.Background(), "message.", "error", err.SlogAttrs())
}
Output: {"level":"INFO","msg":"message.","error":{"code":"E123","kind":"KindXXX","message":"example. foo=bar","attrs":{"tag":"val"},"cause":{"message":"EOF"}}} level=INFO msg=message. error.code=E123 error.kind=KindXXX error.message="example. foo=bar" error.attrs.tag=val error.cause.message=EOF
func (*Error) Is ¶
Is returns if this error is identical to the given error. This can be used with errors.Is.
func (*Error) SlogAttrs ¶
Map returns error information in slice of slog.Attr.
Example:
lg := slog.New(slog.NewJSONHandler(os.Stdout, nil))
def := zerrors.NewDefinition("E123", "KindXXX", "example. foo=%s", map[string]string{"tag": "val"})
err := def.New(io.EOF, "bar")
lg.InfoContext(context.Background(), "message.", "error", err.SlogAttrs())
// JSON logger output >>
// {"level":"INFO","msg":"message.","error":{"code":"E123","kind":"KindXXX","message":"example. foo=bar","attrs":{"tag":"val"},"cause":{"message":"EOF"}}}
// Text logger output >>
// level=INFO msg="message." error.code=E123 error.kind=KindXXX error.message="example. foo=bar" error.attrs.tag=val error.cause.message=EOF
type Frame ¶
type Frame struct {
// Pkg is go package name of the caller.
Pkg string `json:"pkg" msgpack:"pkg" toml:"pkg" xml:"pkg" yaml:"pkg"`
// File is the file name of the caller.
File string `json:"file" msgpack:"file" toml:"file" xml:"file" yaml:"file"`
// Func is the function name of the caller.
Func string `json:"func" msgpack:"func" toml:"func" xml:"func" yaml:"func"`
// Line is the line number of the caller.
Line int `json:"line" msgpack:"line" toml:"line" xml:"line" yaml:"line"`
}
Frame holds stack frame information. See also runtime.Frame.