errorcontext

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2022 License: MIT Imports: 3 Imported by: 1

README

go-errorcontext
build-status go report MIT License coverage docs

go-errorcontext

A trivial go package providing an error implementation that wraps any other error, capturing the context. The errorcontext.With() function is provided to simplify this:

    if err := db.QueryContext(ctx, sql, args); err != nil {
        return errorcontext.Wrap(ctx, err, "database query")
    }

The error returned by Wrap() has an idiomatic string representation of a wrapped error, equivalent to:

    "database query: %v", err

In addition to wrapping errors, errorcontext can also be used to create new errors that do not wrap any other error:

    if fooParam == "" {
        return errorcontext.New(ctx, "required fooParam not specified")
    }

Whether wrapping an error or creating a new one, the captured context is ultiamtely retrieved (if required) when handling a returned error by unwrapping the ErrorWithContext and calling the Context() function on that error to obtain the "most wrapped" context wrapped within the error.

The errorcontext.FromError() function provides a convenient way to do this, also accepting a default context (usually the current context) to use if no context is captured by the error:

    if err := SomeFooService(ctx, fooId); err != nil {
        ctx := errorcontext.FromError(ctx, err)
        log := logger.FromContext(ctx)
        log.Error(err)
        return
    }

Intended Use

The intended use of ErrorWithContext is for reducing "chatter" when logging errors, particularly when using a context logger to enrich structured logs.


The Problem

  1. A context enriched by a call hierarchy is most enriched at the deepest level of that call hierarchy.
  2. A hierarchy of errors wrapped by a call hierarchy is most wrapped at the shallowest level of that call hierarchy.

Errors logged only at the deepest level of a call hierarchy can be enriched with the most context information, but lack any information about the call hierarchy resulting in that error.

Errors logged at (or close to) the root of a call hierarchy can provide the most information about the call hierarchy leading to the error, but lack any of the context enrichment provided by that call hierarchy.

What often then happens is that errors are logged at every level in the call hierarchy, resulting in multiple error logs for a single error, one of which contains the call hierarchy information and another the greatest context enrichment. Every other log entry for that error contains an incomplete representation of both context and call hierarchy.


ErrorWithContext addresses this dilemma by providing a mechanism for returning the context at each level back up the call hierarchy.

A simple convention then ensures that the error is logged only once and with the greatest possible amount of context enrichment.

The convention has two parts:

  1. If an error is returned, it is not logged but returned, wrapped by an ErrorWithContext
  2. If an error is not returned (usually at the effective root of the call hierarchy), it is logged, using a context extracted from the error and a logger initialised from that context

Informational and warning logs may of course continue to be emitted at every level in the call hierarachy.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FromError

func FromError(ctx context.Context, err error) context.Context

FromError accepts a current context and an error and returns the context from the 'most wrapped' ErrorWithContext, or the supplied `context` if no ErrorWithContext is wrapped by the supplied `err`.

func New

func New(ctx context.Context, text string) error

New creates a new ErrorWithContext, capturing the specified context and a string for the error.

The error returned has a string representation of: "<text>"

func Newf

func Newf(ctx context.Context, text string, args ...any) error

Newf creates a new ErrorWithContext, capturing the specified context, a string and args to be substituted for any format specifiers in the string.

The error returned has a string representation of: "<text>"

func Wrap

func Wrap(ctx context.Context, err error, text string) error

Wrap wraps a specified error, capturing the specified context and a string to use when representing the wrapped error.

The error returned has a string representation of: "<text>: <err>"

func Wrapf

func Wrapf(ctx context.Context, err error, text string, args ...any) error

Wrapf wraps a specified error, capturing the specified context a string to use when representing the wrapped error and args to be substituted for any format specifiers in the string.

The error returned has a string representation of: "<text>: <err>"

Types

type ErrorWithContext

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

ErrorWithContext wraps an error, capturing a context and a string used to wrap the wrapped error in the string representation of the error.

func (ErrorWithContext) Context

func (err ErrorWithContext) Context() context.Context

Context returns the innermost context accessible from this error or any wrapped ErrorWithContext.

func (ErrorWithContext) Error

func (err ErrorWithContext) Error() string

Error implements the error interface.

func (ErrorWithContext) Unwrap

func (err ErrorWithContext) Unwrap() error

Unwrap implements unwrapping to return the wrapped error.

Jump to

Keyboard shortcuts

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