errors

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2025 License: MIT Imports: 9 Imported by: 0

README

errors

A Go library for working with errors that supports structured context.

Getting started

Add the dependency with:

go get github.com/sirkon/errors@latest

See a minimal setup and usage example in internal/example/main.go.

Features and goals

  • A drop-in replacement for the standard errors package.
  • Avoid the inconsistency in the standard library where you use errors.New but fmt.Errorf.
  • Built-in support for the most common error-wrapping pattern: "annotation: %w".
  • Structured context support, so you don’t have to log the same error at multiple layers just to add details — simply attach context to the error and the extra data will be rendered by default.
  • Optional inclusion of the file:line location where the error was created/handled. See loc.go.
  • A dedicated type for defining constant errors.

Usage examples

if err != nil {
    return errors.Wrap(err, "do something").Int("int", intVal).Str("str", strVal)
}
const (
    Err1 errors.Const = "error 1"
    Err2 = "error 2"
    …
)

…

io.EOF = errors.New("new io.EOF") // This compiles and works.
Err1 = errors.New("new error 1") // This does not compile.
if err != nil {
    return errors.New("new error").Loc(0)
}

Performance

The benchmark produced the following numbers:

Benchmark Name ns/op B/op Allocs/op
errors.Wrap 188.7 760 14
fmt.Errorf without text formatting 240.2 296 9
errors.Wrapf 364.6 1200 20
fmt.Errorf with text formatting 358.8 576 12
errors.Wrap with 4 context values 303.8 1248 B 18
errors.Wrap with large context 1024 4634 49
fmt.Errorf with large context 1495 2769 18

As expected, performance is roughly on par thanks to less reliance on reflection, even in the Wrapf case. It seems that %w itself is relatively heavy. Fewer allocations per operation do not always help.

One reason for the higher number of allocations and memory usage is the chosen design: every operation creates a new error.Error object. The approach can be changed to reuse existing objects, which yields noticeably better performance:

Benchmark Name ns/op B/op Allocs/op
errors.Wrap 101.5 312 6
fmt.Errorf without text formatting 256.1 296 9
errors.Wrapf 307.4 976 14
fmt.Errorf with text formatting 350.1 576 12

This result comes from minimal changes to the library logic. There are additional easy ways to reduce allocations (which would effectively bring the library back to its prototype state, lol). These changes are not part of the current codebase, so the first table should be considered authoritative.

In any case, errors.Wrapf and errors.Newf should have no fewer allocations than Errorf, because they can do everything Errorf("annotation: %w", err) does plus some extra work that costs something.

Memory usage will also be higher because we store more information.

Performance when saving error locations

With saving of error locations enabled, performance drops by roughly 6–7x. This is about 1600 ns/op for errors.Wrap and about 6900 ns/op for errors.Wrap with a long context.

About adding structured context

Currently, the pattern is "<create/wrap error>" followed by a chain of context additions:

errors.New("error").Int("int-val", intVal).Str("str-val", strVal)

We considered the following alternatives:

Like in zap
return errors.Wrap(err, "do something", errors.Int("int-val", intVal), errors.Str("str-val"))

This approach was dismissed because it makes it awkward to provide formatted error messages.

Like in zerolog

In one of the prototypes — to be precise, in a prototype of a prototype — we tried a zerolog-like approach:

return errors.Flt64("x", x).Flt64("y", y).Errorf("do %v", action)

This required keeping both functions and methods with the same names:

func Flt64(name string, value float64) *Context {
    return NewContext().Flt64(name, value)
}

…

func (ctx *Context) Flt64(name, value) *Context {
    ctx.values = append(ctx.values, ctxTouple{name, value})
    return ctx
}

It worked, but the following issues emerged:

  • Such expressions are harder to read, which matters given how often they appear.
  • The package context gitlab.example.com/common/errors became very large, making IDE autocompletion cumbersome. We shouldn’t be fighting the tool while we work.
Summary comparison of approaches
Current Zap Zerolog
Readability High. High. Significantly worse than the others.
Because it reverses the order of "general → specific".
Instead of "error, error details" you get
"error details, error".
Gets very bad when there is a lot of context.
Formatting support Yes. No. Yes.
Library footprint Low. Significant.
You need to maintain many helper functions.
Slightly worse than Zap.
Context composition Somewhat complicated.
Requires a special object.
Somewhat complicated.
Requires a special object.
Supported.
Performance Lowest among the methods.
About 2× slower than the Zerolog-like.
Medium. Mirrors the usual Zerolog vs Zap comparison (for loggers).

Documentation

Overview

Package errors is a drop-in replacement for the standard errors package that provides a consistent API and adds capabilities to make error messages more informative.

Features

  • Add structured context to errors in addition to plain text.
  • Attach the location where an error was created/handled (file:line).
  • Define constant error values via a dedicated type.

Rationale

The standard fmt.Errorf becomes insufficient when you need to attach rich context describing the conditions that led to an error. Once you add more than a couple of values, the quality of the error message tends to suffer:

  • The separation between general and specific information is lost; everything gets mixed together, which makes the message harder to read.

A common workaround is to log at every point where an error is observed, but this has drawbacks:

  • You have to pass a logger into places that otherwise wouldn't need it.
  • Logs become bloated, as the same error (with different annotations) is logged multiple times.
  • Methodologically, each log line combines error + context + system-wide metadata, which hurts the signal-to-noise ratio.

This library lets you attach context to the error itself. As a result, logging preserves the separation of general and specific information without overloading the logs. The final output quality can be higher than with logging at every stage (depending on the logger implementation).

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func As

func As(err error, target any) bool

As is a wrapper for errors.As from the standard library.

Example
package main

import (
	"fmt"

	"github.com/sirkon/errors"
)

func main() {
	err := fmt.Errorf("read data: %w", errors.New("root error"))

	var e *errors.Error
	if errors.As(err, &e) {
		fmt.Println(e.Error())
	}

	var ae errors.Const
	if errors.As(err, &ae) {
		fmt.Println(e.Error())
	}

}
Output:

root error

func AsType added in v1.0.0

func AsType[T error](err error) (T, bool)

AsType is a type-safe generic version of As, allowing usage without pre-declaring a variable.

Example
package main

import (
	"fmt"

	"github.com/sirkon/errors"
)

func main() {
	err := fmt.Errorf("read data: %w", errors.New("root error"))

	if v, ok := errors.AsType[*errors.Error](err); ok {
		fmt.Println(v)
	}

	if _, ok := errors.AsType[errors.Const](err); ok {
		fmt.Println("must not be here with", err)
	}

}
Output:

root error

func DoNotInsertLocations added in v1.0.0

func DoNotInsertLocations()

DoNotInsertLocations disables the insertion of error handling positions. This is the default mode.

func InsertLocations added in v1.0.0

func InsertLocations()

InsertLocations enables the insertion of error handling positions.

WARNING!

Calculating positions is a very expensive operation, so it is highly discouraged to enable position capturing in production. Enable only during local debugging.

The recommended usage pattern is enabling when using "development" logging mode, with colored output and formatting intended for reading.

func Is

func Is(err, target error) bool

Is is a wrapper for errors.Is from the standard library.

Example
package main

import (
	"fmt"
	"io"

	"github.com/sirkon/errors"
)

func main() {
	err := errors.Wrap(io.ErrNoProgress, "read data")
	fmt.Println(errors.Is(err, io.ErrNoProgress))
	fmt.Println(errors.Is(
		errors.Wrap(errors.New("error"), "wrapped"),
		io.EOF,
	))

}
Output:

true
false

func Join added in v0.6.0

func Join(errs ...error) error

Join is a wrapper for errors.Join from the standard library.

func Log added in v1.0.0

func Log(err error) slog.Attr

Log is used to log an error as a field with the key "err" in slog loggers. For some reason, despite the prevalence of this pattern in other structured loggers, similar functionality was not included in slog.

Usage:

	logger.Error("failed to get user data",
     slog.Str("actor-id", actor.ID),
     slog.Str("user-id", user.ID),
     errors.Log(err),
 )

WARNING the purpose is questionable, may be to remove it?

Types

type Const added in v0.2.0

type Const string

Const is a type implementing the error interface and capable of being a constant.

func (Const) As added in v0.2.0

func (c Const) As(target any) bool

As for errors.As.

func (Const) Error added in v0.2.0

func (c Const) Error() string

func (Const) Is added in v0.2.0

func (c Const) Is(err error) bool

Is for errors.Is.

Example
package main

import (
	"fmt"

	"github.com/sirkon/errors"
)

func main() {
	err := errors.Wrap(errors.Const("error"), "message")

	fmt.Println(errors.Is(err, errors.Const("error")))
	fmt.Println(errors.Is(err, errors.Const("another error")))
	fmt.Println(errors.Is(errors.New("error"), errors.Const("error")))

}
Output:

true
false
false

type Context added in v0.1.0

type Context struct {
	// contains filtered or unexported fields
}

Context is an entity for implementing context composition. Using this object implies mutability; for a reuse approach, use Context.WithCtx.

func Ctx added in v1.0.0

func Ctx() *Context

Ctx creates an empty Context.

Example
// Basic demo to show how context is stored and extracted.

errctx := errors.Ctx().
	Bool("true", true).
	Int("int", 12).
	Int8("i8", math.MinInt8).
	Int16("i16", math.MinInt16).
	Int32("i32", math.MinInt32).
	Int64("i64", math.MinInt64).
	Uint("u", math.MaxUint).
	Uint8("u8", math.MaxUint8).
	Uint16("u16", math.MaxUint16).
	Uint32("u32", math.MaxUint32).
	Uint64("u64", math.MaxUint64).
	Flt32("e", math.E).
	Flt64("pi", math.Pi).
	Str("str", "hello world").
	Stg("stringer", testStringer{}).
	Strs("strlist", strings.Split("1 2 3", " ")).
	Bytes("bytes-printable", []byte("123")).
	Bytes("bytes-raw", []byte{1, 2, 3}).
	Type("type", new(bytes.Buffer)).
	Any("map", map[int]int{1: 3, 2: 2, 3: 1})

err := errors.New("error").
	Int("code", 404).
	Pfx("ctx").
	WithCtx(errctx)

LogError(err)
Output:

error message: error
 - code: 404
 - ctx-true: true
 - ctx-int: 12
 - ctx-i8: -128
 - ctx-i16: -32768
 - ctx-i32: -2147483648
 - ctx-i64: -9223372036854775808
 - ctx-u: 18446744073709551615
 - ctx-u8: 255
 - ctx-u16: 65535
 - ctx-u32: 4294967295
 - ctx-u64: 18446744073709551615
 - ctx-e: 2.7182817
 - ctx-pi: 3.141592653589793
 - ctx-str: hello world
 - ctx-stringer: test stringer
 - ctx-strlist: [1 2 3]
 - ctx-bytes-printable: 123
 - ctx-bytes-raw: [1 2 3]
 - ctx-type: *bytes.Buffer
 - ctx-map: map[1:3 2:2 3:1]

func CtxFrom added in v1.0.0

func CtxFrom(ctx *Context) *Context

CtxFrom creates a new context by copying values from an existing one.

func (*Context) Any added in v1.0.0

func (b *Context) Any(name string, value any) *Context

Any adds an arbitrary named value to the context builder.

func (*Context) Bool added in v1.0.0

func (b *Context) Bool(name string, value bool) *Context

Bool adds a named boolean value (bool) to the context builder.

func (*Context) Bytes added in v1.0.0

func (b *Context) Bytes(name string, value []byte) *Context

Bytes adds a named slice of bytes value to the context builder.

Attention:

This operation can be computationally heavy, as it evaluates whether the sequence can be represented as a string, after which it is saved in either string or object format.

func (*Context) Flt32 added in v1.0.0

func (b *Context) Flt32(name string, value float32) *Context

Flt32 adds a named floating-point value (float32) to the context builder.

func (*Context) Flt64 added in v1.0.0

func (b *Context) Flt64(name string, value float64) *Context

Flt64 adds a named floating-point value (float64) to the context builder.

func (*Context) Int added in v1.0.0

func (b *Context) Int(name string, value int) *Context

Int adds a named integer value (int) to the context builder.

func (*Context) Int8 added in v1.0.0

func (b *Context) Int8(name string, value int8) *Context

Int8 adds a named integer value (int8) to the context builder.

func (*Context) Int16 added in v1.0.0

func (b *Context) Int16(name string, value int16) *Context

Int16 adds a named integer value (int16) to the context builder.

func (*Context) Int32 added in v1.0.0

func (b *Context) Int32(name string, value int32) *Context

Int32 adds a named integer value (int32) to the context builder.

func (*Context) Int64 added in v1.0.0

func (b *Context) Int64(name string, value int64) *Context

Int64 adds a named integer value (int64) to the context builder.

func (*Context) Stg added in v1.0.0

func (b *Context) Stg(name string, value fmt.Stringer) *Context

Stg adds a named value implementing fmt.Stringer to the context builder.

func (*Context) Str added in v1.0.0

func (b *Context) Str(name string, value string) *Context

Str adds a named string value to the context builder.

func (*Context) Strs added in v1.0.0

func (b *Context) Strs(name string, value []string) *Context

Strs adds a named slice of strings value to the context builder.

func (*Context) Type added in v1.0.0

func (b *Context) Type(name string, typ any) *Context

Type adds a type name to the context builder.

func (*Context) Uint added in v1.0.0

func (b *Context) Uint(name string, value uint) *Context

Uint adds a named unsigned integer value (uint) to the context builder.

func (*Context) Uint8 added in v1.0.0

func (b *Context) Uint8(name string, value uint8) *Context

Uint8 adds a named unsigned integer value (uint8) to the context builder.

func (*Context) Uint16 added in v1.0.0

func (b *Context) Uint16(name string, value uint16) *Context

Uint16 adds a named unsigned integer value (uint16) to the context builder.

func (*Context) Uint32 added in v1.0.0

func (b *Context) Uint32(name string, value uint32) *Context

Uint32 adds a named unsigned integer value (uint32) to the context builder.

func (*Context) Uint64 added in v1.0.0

func (b *Context) Uint64(name string, value uint64) *Context

Uint64 adds a named unsigned integer value (uint64) to the context builder.

func (*Context) WithCtx added in v1.0.0

func (b *Context) WithCtx(ctx *Context) *Context

WithCtx copies values from the given context into the current one.

This method supports logic where multiple contexts can be used, which may have common parts but differ in others. Something like:

ctx1 := errors.Ctx().Int("code", 404)
ctx2 := ctx1.Str("msg", "not found")
ctx3 := ctx1.Bool("retried", isRetried)

Will not work. Here ctx1, ctx2, and ctx3 will be pointers to the same object and, accordingly, will yield the same context.

See the example for detailed usage.

Example
// Why simply using a variable for context won't work.
ctxBase := errors.Ctx().Int("code", 404)
ctxMsg := ctxBase.Str("msg", "not found")
ctxBool := ctxBase.Bool("found", false)
LogError(errors.New("error-code").WithCtx(ctxBase))
LogError(errors.New("error-msg").WithCtx(ctxMsg))
LogError(errors.New("error-bool").WithCtx(ctxBool))

fmt.Println()
fmt.Println("...reuse context properly...")
ctxBase = errors.Ctx().Int("code", 403)
ctxMsg = errors.CtxFrom(ctxBase).Str("msg", "forbidden")
ctxBool = errors.CtxFrom(ctxBase).Bool("allowed", false)
LogError(errors.New("error-code").WithCtx(ctxBase))
LogError(errors.New("error-msg").WithCtx(ctxMsg))
LogError(errors.New("error-bool").WithCtx(ctxBool))
Output:

error message: error-code
 - code: 404
 - msg: not found
 - found: false
error message: error-msg
 - code: 404
 - msg: not found
 - found: false
error message: error-bool
 - code: 404
 - msg: not found
 - found: false

...reuse context properly...
error message: error-code
 - code: 403
error message: error-msg
 - code: 403
 - msg: forbidden
error message: error-bool
 - code: 403
 - allowed: false

type Error added in v0.2.0

type Error struct {
	// contains filtered or unexported fields
}

Error is an error implementation with structured context support.

func Just added in v0.5.0

func Just(err error) *Error

Just is for when annotation is not needed, but structured context is. This function solves that problem by returning an error with the text from the given one and allowing to add structured values.

Example
err := errors.Just(io.EOF).
	Str("name", "value").
	Int("value", 1)
LogError(err)
Output:

error message: EOF
 - name: value
 - value: 1

func New

func New(msg string) *Error

New creates a new error with the given message.

Example
package main

import (
	"fmt"

	"github.com/sirkon/errors"
)

func main() {
	fmt.Println(errors.New("error example"))

}
Output:

error example

func Newf

func Newf(format string, a ...any) *Error

Newf creates a new error with the given formatted message.

Example
package main

import (
	"fmt"

	"github.com/sirkon/errors"
)

func main() {
	fmt.Println(errors.Newf("error %s", "example"))

}
Output:

error example

func Wrap

func Wrap(err error, msg string) *Error

Wrap annotates an error with a text message.

Example
package main

import (
	"fmt"

	"github.com/sirkon/errors"
)

func main() {
	fmt.Println(errors.Wrap(errors.Const("example"), "error"))

}
Output:

error: example

func Wrapf

func Wrapf(err error, format string, a ...any) *Error

Wrapf annotates an error with a formatted text message.

Example
package main

import (
	"fmt"

	"github.com/sirkon/errors"
)

func main() {
	fmt.Println(errors.Wrapf(errors.Const("example"), "formatted error"))

}
Output:

formatted error: example

func (*Error) Any added in v0.2.0

func (e *Error) Any(name string, value any) *Error

Any adds an arbitrary named value to the context.

func (*Error) As added in v0.2.0

func (e *Error) As(target any) bool

As implements support for As.

func (*Error) Bool added in v0.2.0

func (e *Error) Bool(name string, value bool) *Error

Bool adds a named boolean value to the context.

func (*Error) Bytes added in v1.0.0

func (e *Error) Bytes(name string, value []byte) *Error

Bytes adds a named slice of bytes value to the context.

Attention:

This operation can be computationally heavy, as it evaluates whether the sequence can be represented as a string, after which it is saved in either string or object format.

func (*Error) Error added in v0.2.0

func (e *Error) Error() string

func (*Error) Flt32 added in v1.0.0

func (e *Error) Flt32(name string, value float32) *Error

Flt32 adds a named floating-point value (float32) to the context.

func (*Error) Flt64 added in v1.0.0

func (e *Error) Flt64(name string, value float64) *Error

Flt64 adds a named floating-point value (float64) to the context.

func (*Error) Int added in v0.2.0

func (e *Error) Int(name string, value int) *Error

Int adds a named integer value (int) to the context.

func (*Error) Int8 added in v0.2.0

func (e *Error) Int8(name string, value int8) *Error

Int8 adds a named integer value (int8) to the context.

func (*Error) Int16 added in v0.2.0

func (e *Error) Int16(name string, value int16) *Error

Int16 adds a named integer value (int16) to the context.

func (*Error) Int32 added in v0.2.0

func (e *Error) Int32(name string, value int32) *Error

Int32 adds a named integer value (int32) to the context.

func (*Error) Int64 added in v0.2.0

func (e *Error) Int64(name string, value int64) *Error

Int64 adds a named integer value (int64) to the context.

func (*Error) Is added in v0.2.0

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

Is implements support for Is.

func (*Error) Pfx added in v0.3.0

func (e *Error) Pfx(prefix string) *Error

Pfx sets (or replaces) the prefix that will be prepended to subsequent context field names.

func (*Error) Stg added in v0.2.0

func (e *Error) Stg(name string, value fmt.Stringer) *Error

Stg adds a named value implementing fmt.Stringer to the context.

func (*Error) Str added in v0.2.0

func (e *Error) Str(name string, value string) *Error

Str adds a named string value to the context.

func (*Error) Strs added in v0.2.0

func (e *Error) Strs(name string, value []string) *Error

Strs adds a named slice of strings value to the context.

func (*Error) Type added in v0.4.0

func (e *Error) Type(name string, typ any) *Error

Type adds a type name to the context.

func (*Error) Uint added in v0.2.0

func (e *Error) Uint(name string, value uint) *Error

Uint adds a named unsigned integer value (uint) to the context.

func (*Error) Uint8 added in v0.2.0

func (e *Error) Uint8(name string, value uint8) *Error

Uint8 adds a named unsigned integer value (uint8) to the context.

func (*Error) Uint16 added in v0.2.0

func (e *Error) Uint16(name string, value uint16) *Error

Uint16 adds a named unsigned integer value (uint16) to the context.

func (*Error) Uint32 added in v0.2.0

func (e *Error) Uint32(name string, value uint32) *Error

Uint32 adds a named unsigned integer value (uint32) to the context.

func (*Error) Uint64 added in v0.2.0

func (e *Error) Uint64(name string, value uint64) *Error

Uint64 adds a named unsigned integer value (uint64) to the context.

func (*Error) Unwrap added in v0.2.0

func (e *Error) Unwrap() error

Unwrap method needed for errors.Is and errors.As to work.

func (*Error) WithCtx added in v1.0.0

func (e *Error) WithCtx(ctx *Context) *Error

WithCtx merges the given Context into the error. The current error's prefix is prepended to the names of the added fields.

type ErrorChainLinkContext added in v1.0.0

type ErrorChainLinkContext struct{}

ErrorChainLinkContext is given to links where only structured context was added via Just.

type ErrorChainLinkDescriptor added in v1.0.0

type ErrorChainLinkDescriptor interface {
	// contains filtered or unexported methods
}

ErrorChainLinkDescriptor describes a link in the processing chain. Implementations of this interface are used to describe the file:line locations in the error chain.

type ErrorChainLinkNew added in v1.0.0

type ErrorChainLinkNew string

ErrorChainLinkNew is given to links related to the creation of a new error via New/Newf.

type ErrorChainLinkWrap added in v1.0.0

type ErrorChainLinkWrap string

ErrorChainLinkWrap is given to chain links obtained via Wrap/Wrapf.

type ErrorContextConsumer added in v0.2.0

type ErrorContextConsumer interface {
	NextLink()
	Bool(name string, value bool)
	Int(name string, value int)
	Int8(name string, value int8)
	Int16(name string, value int16)
	Int32(name string, value int32)
	Int64(name string, value int64)
	Uint(name string, value uint)
	Uint8(name string, value uint8)
	Uint16(name string, value uint16)
	Uint32(name string, value uint32)
	Uint64(name string, value uint64)
	Flt32(name string, value float32)
	Flt64(name string, value float64)
	Str(name string, value string)
	Any(name string, value any)
	SetLinkInfo(loc token.Position, descr ErrorChainLinkDescriptor)
}

ErrorContextConsumer is the contract that must be implemented by the logging side to receive the structured values stored in the error.

type ErrorContextDeliverer added in v0.2.0

type ErrorContextDeliverer interface {
	Deliver(cons ErrorContextConsumer)
	Error() string
}

ErrorContextDeliverer is what is returned by the GetContextDeliverer function. Example of how to work with slog.

type slogConsumer struct{
   fields []any
}

func (c *slogConsumer) Int(name, value int) {
   c.fields = append(c.fields, slog.Int(name, value))
}

// And so on for the rest of the methods to implement errors.ErrorContextConsumer.

// Log logs at the Info level.
func Log(msg string, fields []slog.Attr) {
    var attrs []any
    for _, field := range fields {
        // Save all original fields.
        attrs = append(attrs, field)

        // Need to unwrap errors. For this, we look for fields that contain them.
        fv := field.Value.Any()
        e, ok := fv.(error)
        if !ok {
            continue
        }

        // v contains an error. Try to get context from it.
        dlr := errors.GetContextDeliverer(e)
        if dlr == nil {
            // This is not our error.
            continue
        }

        // Get the context and add the extracted fields.
        var errCtx slogConsumer{}
        dlr.Deliver(&errCtx)
        attrs = append(attrs, errCtx.fields...)
    }

    slog.Info(msg, attrs...)
}

A working example can be found in ./internal/example/main.go.

func GetContextDeliverer added in v0.2.0

func GetContextDeliverer(err error) ErrorContextDeliverer

GetContextDeliverer returns the structured-context deliverer for the given error.

Example
package main

import (
	"bytes"
	"fmt"
	"math"
	"strconv"

	"github.com/sirkon/errors"
)

func main() {
	// Handle the case of an error without structured context.
	if errors.GetContextDeliverer(errors.Const("error")) != nil {
		fmt.Println("must not be here")
	}

	// Now the main case where we need to show values from the context.
	// Here we add the prefix "error" – call Pfx("error") – and add
	// a bunch of values of various types.
	err := errors.New("error").Pfx("").Pfx("context").
		Bool("b", true).
		Int("i", -1).
		Int8("i8", math.MinInt8).
		Int16("i16", math.MinInt16).
		Int32("i32", math.MinInt32).
		Int64("i64", math.MinInt64).
		Uint("u", 1).
		Uint8("u8", math.MaxUint8).
		Uint16("u16", math.MaxUint16).
		Uint32("u32", math.MaxUint32).
		Uint64("u64", math.MaxUint64).
		Flt32("f32", math.MaxFloat32).
		Flt64("f64", math.MaxFloat64).
		Str("string", "str").
		Strs("strings", []string{"1", "2", "3"}).
		Stg("stringer", testStringer{}).
		Any("object", map[string]int{
			"key": 12,
		}).
		Bytes("bytes", []byte("123")).Bytes("bytes-raw", []byte{1, 2, 3}).
		Type("type-name", bytes.NewBuffer(nil))

	// Add a bit more context, this time without a prefix.
	err = errors.Wrap(err, "wrapping context").Str("wrapped", "value")
	// Print the error text.
	fmt.Println("error message:", strconv.Quote(err.Error()))

	// Get the context deliverer and feed it our ready implementation
	// of the context receiver, then output the accumulated data to STDOUT with a bit of formatting.
	cons := &testConsumer{}
	d := errors.GetContextDeliverer(err)
	d.Deliver(cons)
	for _, ctx := range cons.ctx {
		fmt.Println(" - "+ctx.name+":", ctx.value)
	}

}

type testStringer struct{}

func (testStringer) String() string {
	return "test stringer"
}

func init() {
	// Enable to slightly improve coverage.
	errors.InsertLocations()
}
Output:

error message: "wrapping context: error"
 - wrapped: value
 - context-b: true
 - context-i: -1
 - context-i8: -128
 - context-i16: -32768
 - context-i32: -2147483648
 - context-i64: -9223372036854775808
 - context-u: 1
 - context-u8: 255
 - context-u16: 65535
 - context-u32: 4294967295
 - context-u64: 18446744073709551615
 - context-f32: 3.4028235e+38
 - context-f64: 1.7976931348623157e+308
 - context-string: str
 - context-strings: [1 2 3]
 - context-stringer: test stringer
 - context-object: map[key:12]
 - context-bytes: 123
 - context-bytes-raw: [1 2 3]
 - context-type-name: *bytes.Buffer

Directories

Path Synopsis
internal
example command
Package main provides an example of configuration, usage, and results of working with the library.
Package main provides an example of configuration, usage, and results of working with the library.

Jump to

Keyboard shortcuts

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