metaerr

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2023 License: MIT Imports: 5 Imported by: 0

README

MetaErr

Metaerr is a golang package to create or wrap errors with custom metadata and location.

Why

I was using github.com/pkg/errors before and the stacktraces were huge and not really useful. Then I found the Fault library which was amazing, but the usage I wanted to do was at odd with some of the opinions built into the library.

This is why I decided to write this simple library. It uses the same "stacktrace" models as Fault, in the sense that the stack you will see if the locations of the errors (and wrapped errors) creation, and not the stacktrace that led to the creation of the error.

And the next feature it provides is the ability to add any number of key/pair metadata entries to each error (and wrapped errors). This is useful if you want to attach metadata at error create and then leverage that metadata at resolution. A common use case is to have a generic http error handler for an API that would leverage the metadata to determine the http status or build an error payload to be sent to the user. Another use case would be logging and alerting. If you convert the metadata into fields in a JSON logger, you could have different alerting rules for logged ERRORS based on the metadata, for example, errors with the metadata tag containing "security" could raise a immediate alert.

Usage

Metaerr can be used with golang standard errors package. They are also compatible with error wrapping introduced in Go 1.13.

To create an new MetaErr from a string, use

err := metaerr.New("failure")

To create a new MetaErr by wrapping an existing error, use

err := metaerr.Wrap(err, "failure")

The next step once you have a Metaerr is to add metadata to it. The first step is to create a function matching the metaerr.ErrorMetadata signature. For your convenience, you can use metaerr.StringMeta, but you can also create your own. Ultimately, all metadata entries are stored as string.

//Create an metadata called ErrorCode
var ErrorCode = metaerr.StringMeta("error_code")

func main() {
	rootCause := metaerr.New("failure")
	err := metaerr.Wrap(rootCause, "cannot fetch content").Meta(ErrorCode("x01"))
	fmt.Printf("%+v", err)
}

will print (... will be your project location)

cannot fetch content [error_code=x01]
        at .../quantumcycle/metaerr/cmd/main.go:13
failure
        at .../quantumcycle/metaerr/cmd/main.go:12
Getting the err message, location, and metadata

In the example above, we use the Printf formatting to display the error, metadata and location all in one gulp. You can however use the provided helper function to get the individual parts

err := metaerr.New("failure")
err.Error() //returns failure
err.Location() //returns .../mysource/mypackage/file.go:22

// will print error_code:x01
meta := metaerr.GetMeta(err, false)
for k, values := range meta {
  for _, val := range values {
    fmt.Println(k + ":" + val)
  }
}

Options

You can provide options to alter the errors on creation. At the moment there is a single option, WithLocationSkip. By default when creating an error, Metaerr will skip 2 call stack to determine the error creation location. This works well if you call metaerr directly at the place where the error is created. However there is a use case where you want to create an error factory for some common use case, to initialize the error with some common metadata. In this case, if you use the standard metaerr.New, the reported location will be the line where metaerr.New is called, which will be in your error factory method. This is probably not what you want. In this case, you can use the metaerr.WithLocationSkip option to add additional call stack skip to determine the location. Here is an example:

package main

import (
	"fmt"

	"github.com/quantumcycle/metaerr"
)

var Tag = metaerr.StringMeta("tag")

func CreateDatabaseError(reason string) error {
	return metaerr.New(reason, metaerr.WithLocationSkip(1)).Meta(Tag("database"))
}

func main() {
	dbErr := CreateDatabaseError("no such table [User]")
	fmt.Printf("%+v", dbErr)
}

which will output

no such table [User] [tag=database]
        at /home/matdurand/sources/github/quantumcycle/metaerr/cmd/main.go:16

Without the WithLocationSkip option, the reported location would be line 12, inside the CreateDatabaseError function. having all our errors pointing to this specific line would ne useless.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetMeta

func GetMeta(err error, nested bool) map[string][]string

func StringMeta

func StringMeta(name string) func(val string) ErrorMetadata

Types

type Error

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

func New

func New(reason string, opt ...Option) Error

func Wrap

func Wrap(err error, msg string) *Error

func (Error) Error

func (e Error) Error() string

func (Error) Format

func (e Error) Format(s fmt.State, verb rune)

func (Error) Location

func (e Error) Location() string

func (Error) Meta

func (e Error) Meta(metas ...ErrorMetadata) Error

func (Error) Unwrap

func (e Error) Unwrap() error

type ErrorMetadata

type ErrorMetadata = func(err Error) []MetaValue

type MetaValue

type MetaValue struct {
	Name   string
	Values []string
}

type Option

type Option func(*Error)

func WithLocationSkip

func WithLocationSkip(additionalCallerSkip int) Option

Jump to

Keyboard shortcuts

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