zerrors

package
v0.0.0-alpha.18 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 31, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

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

func Must[T any](t T, err error) T

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

func ToMap(err error) map[string]any

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

func ToSlogAttrs(err error) []slog.Attr

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

func UnwrapErr(err error) error

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

func UnwrapErrs(err error) []error

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 NewErr

func NewErr(cause error, message, detail string, a ...any) *Err

NewErr returns new Err. Detail is the format string for [smt.Sprintf].

func (*Err) Error

func (e *Err) Error() string

Error implements [error] interface.

func (*Err) Is

func (e *Err) Is(err error) bool

Is returns if this error is identical to the given error. This can be used with errors.Is.

func (*Err) Map

func (e *Err) Map() map[string]any

Map returns error information in map.

func (*Err) SlogAttrs

func (e *Err) SlogAttrs() []slog.Attr

Map returns error information in slice of slog.Attr.

func (*Err) Unwrap

func (e *Err) Unwrap() error

Unwrap returns the inner error if any.

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) Error

func (e *Error) Error() string

Error implements [error] interface.

func (*Error) Is

func (e *Error) Is(err error) bool

Is returns if this error is identical to the given error. This can be used with errors.Is.

func (*Error) Map

func (e *Error) Map() map[string]any

Map returns error information in map.

func (*Error) SlogAttrs

func (e *Error) SlogAttrs() []slog.Attr

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

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the inner error if any.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL