errkit

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

README

Release Reference DeepWiki Test

Insights Insights

go-errkit

Go library for errors and exceptions.

Features

  • Simple and structural error (Error).
  • Error definition and instanciation features(ErrDefinition, ErrInstance).
  • SLogger integration.
  • Easy stack frames manipulation.
  • Application-wide error handlers.

Usages

Error definition and instanciation

Use NewErrDefinition to create a new definition. New and NewStack creates a new error instance from the defition.

// Define error.
// Definition has code, kind, message, attributes and instance id generation func.
E123 := errkit.NewErrDefinition("E123", "KindXXX", "example error. foo=%s", map[string]string{"type": "server"}, instanceID)

// Instanciate an error from definition.
// "FOO" will be the args for message. 
//   i.e. fmt.Sprintf("example error. foo=%s", "FOO)
ins123 := E123.New(nil, "FOO")

The ins123 can be used for logging.

fmt.Println(ins123)
// E123 KindXXX :example error. foo=FOO (type=server)

fmt.Println(ins123.Error())
// E123 KindXXX :example error. foo=FOO (type=server)

lgJSON := slog.New(slog.NewJSONHandler(os.Stdout, nil))
lgJSON.InfoContext(context.Background(), "JSON logger.",ins123.SlogAttr())
// {"time":"2026-08-06T08:31:03.6992616+09:00","level":"INFO","msg":"JSON logger.","error":{"code":"E123","kind":"KindXXX","message":"example error. foo=FOO","attrs":{"type":"server"}}}

lgText := slog.New(slog.NewTextHandler(os.Stdout, nil))
lgText.InfoContext(context.Background(), "Text logger.", ins123.SlogAttr())
// time=2026-08-06T08:31:03.732+09:00 level=INFO msg="Text logger." error.code=E123 error.kind=KindXXX error.message="example error. foo=FOO" error.attrs.type=server
Enviromental Variables
  • GO_ERRKIT_TRACE_ENABLED: enables ErrDefinition to output tracing info of instanciation.

Docs & Examples

References

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ToMap

func ToMap(err error) map[string]any

ToMap converts error into map. If the err implements `Map() map[string]any`, it calls Map(). ToMap returns nil when the err is nil.

Example
package main

import (
	"errors"
	"fmt"

	"github.com/aileron-projects/go-errkit"
)

func main() {
	e1 := errors.New("example1")
	e2 := errors.New("example2")

	fmt.Println(errkit.ToMap(e1))
	fmt.Println(errkit.ToMap(fmt.Errorf("example3 [%w]", e1)))
	fmt.Println(errkit.ToMap(errors.Join(e1, e2)))
}
Output:
map[message:example1]
map[causes:[map[message:example1]] message:example3 [example1]]
map[causes:[map[message:example1] map[message:example2]] message:example1
example2]

func ToSlogAttr

func ToSlogAttr(err error) slog.Attr

ToSlogAttr converts error into slog.Attr. ToSlogAttr is the alias for slog.GroupAttrs("error", ToSlogAttrs(err)...)

Example
package main

import (
	"errors"
	"fmt"

	"github.com/aileron-projects/go-errkit"
)

func main() {
	e1 := errors.New("example1")
	e2 := errors.New("example2")

	fmt.Println(errkit.ToSlogAttr(e1))
	fmt.Println(errkit.ToSlogAttr(fmt.Errorf("example3 [%w]", e1)))
	fmt.Println(errkit.ToSlogAttr(errors.Join(e1, e2)))
}
Output:
error=[message=example1]
error=[message=example3 [example1] cause=[message=example1]]
error=[message=example1
example2 cause.1=[message=example1] cause.2=[message=example2]]

func ToSlogAttrs

func ToSlogAttrs(err error) []slog.Attr

ToSlogAttrs converts error into slog.Attr. If the err implements `SlogAttrs() []slog.Attr`, it calls SlogAttrs(). ToSlogAttrs returns nil when the err is nil.

Example
package main

import (
	"errors"
	"fmt"

	"github.com/aileron-projects/go-errkit"
)

func main() {
	e1 := errors.New("example1")
	e2 := errors.New("example2")

	fmt.Println(errkit.ToSlogAttrs(e1))
	fmt.Println(errkit.ToSlogAttrs(fmt.Errorf("example3 [%w]", e1)))
	fmt.Println(errkit.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". UnwrapErrs can unwrap errors returned by errors.Join. See also UnwrapErr and errors.Unwrap.

Types

type ErrDefinition

type ErrDefinition struct {
	// Code is the error code.
	Code string
	// Kind is the error kind of this error.
	Kind string
	// Message is the error message.
	// Message will be formatted by [fmt.Sprintf].
	Message string
	// Attrs is the list of attributions.
	// Attrs will be copied to all instances.
	Attrs map[string]string
	// Instance returns an instance identifier.
	Instance func() string
}

ErrDefinition is the error definition. Error instances are created from the definition.

func NewErrDefinition

func NewErrDefinition(code, kind, message string, attrs map[string]string, instance func() string) *ErrDefinition

NewErrDefinition returns a new instance of ErrDefinition. See ErrDefinition.

func (*ErrDefinition) Instanciated

func (d *ErrDefinition) Instanciated(err error) bool

Instanciated returns if this definition instanciated the err. The err will be unwrapped if possible.

func (*ErrDefinition) New

func (d *ErrDefinition) New(cause error, values ...any) *ErrInstance

New returns a new error instance from the definition. Use ErrDefinition.NewStack when stack frames are necessary.

Example
package main

import (
	"fmt"
	"io"

	"github.com/aileron-projects/go-errkit"
)

func main() {
	def := errkit.NewErrDefinition("E123", "KindXXX", "example error. foo=%s bar=%s.", map[string]string{"foo": "bar"}, nil)

	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 (*ErrDefinition) NewStack

func (d *ErrDefinition) NewStack(cause error, values ...any) *ErrInstance

NewStack returns a new error instance from the definition. Use ErrDefinition.New when stack frames are not necessary.

type ErrInstance

type ErrInstance struct {
	// Cause is the error cause, or inner error.
	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 [Errors.Is].
	Code string `json:"code" msgpack:"code" xml:"code" yaml:"code"`
	// Kind is the error kind.
	// Kind is compared in [Errors.Is].
	Kind string `json:"kind" msgpack:"kind" xml:"kind" yaml:"kind"`
	// Instance is the instance identifier.
	// Instance is NOT compared in [Errors.Is].
	Instance string `json:"instance,omitempty" msgpack:"instance,omitempty" xml:"instance,omitempty" yaml:"instance,omitempty"`
	// 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.
	Frames []Frame `json:"frames,omitempty" msgpack:"frames,omitempty" xml:"frames,omitempty" yaml:"frames,omitempty"`
}

Error is the general error type.

func (*ErrInstance) Error

func (e *ErrInstance) Error() string

Error implements [error] interface.

func (*ErrInstance) Is

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

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

func (*ErrInstance) Map

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

Map returns error information as map.

func (*ErrInstance) SlogAttr

func (e *ErrInstance) SlogAttr() slog.Attr

SlogAttr returns error information as slog.Attr. SlogAttr is the alias for slog.GroupAttrs("error", e.SlogAttrs()...)

Example
package main

import (
	"context"
	"io"
	"log/slog"
	"os"

	"github.com/aileron-projects/go-errkit"
)

func removeTime(groups []string, a slog.Attr) slog.Attr {
	if a.Key == slog.TimeKey && len(groups) == 0 {
		return slog.Attr{}
	}
	return a
}

func main() {
	opts := &slog.HandlerOptions{
		ReplaceAttr: removeTime,
	}
	lgJSON := slog.New(slog.NewJSONHandler(os.Stdout, opts))
	lgText := slog.New(slog.NewTextHandler(os.Stdout, opts))

	def := errkit.NewErrDefinition("E123", "KindXXX", "example. foo=%s", map[string]string{"tag": "val"}, func() string { return "ABC" })
	err := def.New(io.EOF, "bar")

	lgJSON.InfoContext(context.Background(), "message.", err.SlogAttr())
	lgText.InfoContext(context.Background(), "message.", err.SlogAttr())
}
Output:
{"level":"INFO","msg":"message.","error":{"code":"E123","kind":"KindXXX","message":"example. foo=bar","attrs":{"tag":"val"},"instance":"ABC","cause":{"message":"EOF"}}}
level=INFO msg=message. error.code=E123 error.kind=KindXXX error.message="example. foo=bar" error.attrs.tag=val error.instance=ABC error.cause.message=EOF

func (*ErrInstance) SlogAttrs

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

SlogAttrs returns error information as slog.Attr.

Example
package main

import (
	"context"
	"io"
	"log/slog"
	"os"

	"github.com/aileron-projects/go-errkit"
)

func removeTime(groups []string, a slog.Attr) slog.Attr {
	if a.Key == slog.TimeKey && len(groups) == 0 {
		return slog.Attr{}
	}
	return a
}

func main() {
	opts := &slog.HandlerOptions{
		ReplaceAttr: removeTime,
	}
	lgJSON := slog.New(slog.NewJSONHandler(os.Stdout, opts))
	lgText := slog.New(slog.NewTextHandler(os.Stdout, opts))

	def := errkit.NewErrDefinition("E123", "KindXXX", "example. foo=%s", map[string]string{"tag": "val"}, func() string { return "ABC" })
	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"},"instance":"ABC","cause":{"message":"EOF"}}}
level=INFO msg=message. error.code=E123 error.kind=KindXXX error.message="example. foo=bar" error.attrs.tag=val error.instance=ABC error.cause.message=EOF

func (*ErrInstance) Unwrap

func (e *ErrInstance) Unwrap() error

Unwrap returns the inner error if any.

type Error

type Error struct {
	// Cause is the cause of this error, or inner error.
	Cause error
	// Message is the error message.
	// Message is compared in the [Error.Is].
	Message string
	// Detail is the error detail.
	// Detail is NOT compared in the [Error.Is].
	Detail string
}

Error is the basic error struct. Use NewError to create an instance.

func NewError

func NewError(cause error, message, detail string, a ...any) *Error

NewError returns a new instance of Error.

func (*Error) Error

func (e *Error) Error() string

Error implements [error].

func (*Error) Is

func (e *Error) Is(target 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) SlogAttr

func (e *Error) SlogAttr() slog.Attr

SlogAttr returns error information as slog.Attr. SlogAttr is the alias for slog.GroupAttrs("error", e.SlogAttrs()...)

Example
package main

import (
	"context"
	"io"
	"log/slog"
	"os"

	"github.com/aileron-projects/go-errkit"
)

func removeTime(groups []string, a slog.Attr) slog.Attr {
	if a.Key == slog.TimeKey && len(groups) == 0 {
		return slog.Attr{}
	}
	return a
}

func main() {
	opts := &slog.HandlerOptions{
		ReplaceAttr: removeTime,
	}
	lgJSON := slog.New(slog.NewJSONHandler(os.Stdout, opts))
	lgText := slog.New(slog.NewTextHandler(os.Stdout, opts))

	err := errkit.NewError(io.EOF, "example", "foo=%s", "bar")

	lgJSON.InfoContext(context.Background(), "message.", err.SlogAttr())
	lgText.InfoContext(context.Background(), "message.", err.SlogAttr())
}
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 (*Error) SlogAttrs

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

SlogAttrs returns error information as slog.Attr.

Example
package main

import (
	"context"
	"io"
	"log/slog"
	"os"

	"github.com/aileron-projects/go-errkit"
)

func removeTime(groups []string, a slog.Attr) slog.Attr {
	if a.Key == slog.TimeKey && len(groups) == 0 {
		return slog.Attr{}
	}
	return a
}

func main() {
	opts := &slog.HandlerOptions{
		ReplaceAttr: removeTime,
	}
	lgJSON := slog.New(slog.NewJSONHandler(os.Stdout, opts))
	lgText := slog.New(slog.NewTextHandler(os.Stdout, opts))

	err := errkit.NewError(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 (*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 location. See also runtime.Frame.

func (*Frame) String

func (f *Frame) String() string

Directories

Path Synopsis
examples
instanciation command

Jump to

Keyboard shortcuts

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