errorist

package module
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2021 License: MIT Imports: 12 Imported by: 3

README

errorist

Godoc Reference MIT License Badge

Package errorist provides useful error handling utilities inspired by Thanos Coding Style Guide and Uber go style guide.

Closing Resources

errorist provides hassle-free functions closing io.Closer with defer.

With Error Capture

The most recommended way is using error capture. An error caused by Close will be captured on the given error pointer unless it already has an error as the value.

func printFile(path string) (err error) {
    f, err := os.OpenFile(path)
    if err != nil {
        return errors.Wrapf(err, "open %s", path)
    }
    defer errorist.CloseWithErrCapture(f, &err)
    ...
}

With Error Channel

An error also can be captured and sent to an error channel (chan error). It is a good fit with resources in goroutines.

errChan := make(chan error)
go func() {
    f, err := os.OpenFile(path)
    defer errorist.CloseWithErrChan(f, errChan)
}()

With Error Log

Otherwise, why don't we just log and ignore it? Default logger is log.Println but you are able to customize it with options.

defer errorist.CloseWithLogOnErr(f)

// with logrus
defer errorist.CloseWithLogOnErr(f, errorist.LogWithLogrus(logger.Warn))

Adding Contexts with Error Wrapping

If you're familiar with errors.Wrap or fmt.Errorf, you may want to do the same error handling with errorist. errorist provides the option wrapping errors with context.

func printFile(path string) (err error) {
    f, err := os.OpenFile(path)
    if err != nil {
        return errors.Wrapf(err, "open %s", path)
    }
    defer errorist.CloseWithErrCapture(f, &err, errorist.Wrapf("close %s", path))
    ...
}

Note that errorist.Wrapf is just an option specifier for errorist; it cannot be used solely. If you want to just wrap errors, you can use pkg/errors or fmt.Errorf with %w pattern added in Go 1.13.

Recovering from Panics

errorist provides panic recovery functions that can be used with defer.

wg, ctx := errgroup.WithContext(context.Background())
wg.Go(func() (err error) {
    defer errorist.RecoverWithErrCapture(&err)
    ...
})

Stacktrace is prettified, and calls from non-project source will be filtered by default. You can customize stacktrace format with options. For details, please refer options.go.

fmt.Println("%+v", err)
panic: assignment to entry in nil map
    github.com/therne/errorist.panicStation (panic_test.go:67)
    github.com/therne/errorist.TestWrapPanicWith.func1.1.1 (panic_test.go:19)
    github.com/therne/errorist.TestWrapPanicWith.func1.1 (panic_test.go:13)
    github.com/therne/errorist.TestWrapPanicWith.func1 (panic_test.go:12)
    github.com/therne/errorist.TestWrapPanicWith (panic_test.go:11)

Prettifying Stacktraces on Errors

pkg/errors is the most popular and powerful tool for handling and wrapping errors. errorist provides extracting and prettifying a stacktrace from errors created or wrapped by pkg/errors.

errorist.Stacktrace(err) ==
    []string{
        "github.com/some/app/api/Server.Handle (api.go:84)",
        "github.com/some/app/controller/Controller.Get (controller.go:11)",
    }

The below example shows how to use it in API responses for debugging purposes.

func handleGinError(c *gin.Context) {
    c.Next()
    if len(c.Errors) > 0 {
        err := c.Errors.Last().Err
        c.JSON(500, gin.H{
            "error":       err.Error(),
            "stacktraces": errorist.Stacktrace(err)
        })
    }
}

Options

You can use global options, package-wide, or with call arguments. Options set on a smaller scope can override options set on a wider scope.

errorist.SetGlobalOptions(
    errorist.IncludeNonProjectFiles(),
    errorist.WithDetailedTrace(),
)

// package-local options can override global options
errorist.SetPackageLevelOptions(
    errorist.IncludedPackages("github.com/my/pkg"),
    errorist.LogWithLogrus(pkgLogger),
)

// call options can override options above
errorist.CloseWithErrCapture(f, &err, errorist.Wrapf("close %s", path))

For detailed options, please refer Godoc or options.go.

License: MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultOptions = Options{
	Logger: func(err string) { log.Println(err) },

	DetailedStacktrace:  false,
	SkipNonProjectFiles: true,
}

Functions

func CloseWithErrCapture

func CloseWithErrCapture(c io.Closer, capture *error, opts ...Option)

CloseWithErrCapture is used if you want to close and fail the function or method on a `io.Closer.Close()` error (make sure the `error` return argument is named as `err`). If the error is already present, `CloseWithErrCapture` will append the error caused by `Close` if any.

func CloseWithErrChan

func CloseWithErrChan(c io.Closer, errChan chan<- error, opts ...Option)

CloseWithErrChan is used if you want to close and fail the function or method on a `io.Closer.Close()` error (make sure the `error` return argument is named as `err`). If the error is already present, `CloseWithErrChan` will send the error to the given channel caused by `Close` if any.

func CloseWithLogOnErr added in v0.1.1

func CloseWithLogOnErr(c io.Closer, opts ...Option)

CloseWithLogOnErr is used if you want to close and fail the function or method on a `io.Closer.Close()` error (make sure the `error` return argument is named as `err`). If the error is already present, `CloseWithLogOnErr` will log the error caused by `Close` if any.

func RecoverWithErrCapture

func RecoverWithErrCapture(capture *error, opts ...Option)

func RecoverWithErrChan

func RecoverWithErrChan(errChan chan<- error, opts ...Option)

func SetGlobalOptions

func SetGlobalOptions(opts ...Option)

SetGlobalOptions sets options applied in current package scope. It can override global options.

func SetPackageLevelOptions

func SetPackageLevelOptions(opts ...Option)

SetPackageLevelOptions sets options applied in current package scope. It can override global options.

func Stacktrace

func Stacktrace(err error, _ ...Option) (traceEntries []string)

Stacktrace returns pretty-formatted stack trace of an error created or wrapped by `github.com/pkg/errors` package. Runtime stack traces are skipped for simplicity.

func StopWithErrCapture

func StopWithErrCapture(c Stopper, capture *error, opts ...Option)

StopWithErrCapture is used if you want to Stop and fail the function or method on a `Stop()` error (make sure the `error` return argument is named as `err`). If the error is already present, `StopWithErrCapture` will append the error caused by `Stop` if any.

func StopWithErrChan

func StopWithErrChan(c Stopper, errChan chan<- error, opts ...Option)

StopWithErrChan is used if you want to Stop and fail the function or method on a `Stop()` error (make sure the `error` return argument is named as `err`). If the error is already present, `StopWithErrChan` will send the error to the given channel caused by `Stop` if any.

func StopWithErrLog

func StopWithErrLog(c Stopper, opts ...Option)

StopWithErrLog is used if you want to Stop and fail the function or method on a `Stop()` error (make sure the `error` return argument is named as `err`). If the error is already present, `StopWithErrLog` will log the error caused by `Stop` if any.

Types

type LogrusLikeLoggingFunc

type LogrusLikeLoggingFunc func(...interface{})

LogrusLikeLoggingFunc includes leveled logging functions on Logrus. https://github.com/sirupsen/logrus#level-logging Other loggers sharing same function signature can be also used.

type Option

type Option func(o *Options)

func IncludeNonProjectFiles

func IncludeNonProjectFiles() Option

IncludeNonProjectFiles is an option for including non-project files to stacktrace. It is not recommended to use this option for production because it refers GOPATH from environment variable for the decision. IncludedPackages is recommended.

func IncludedPackages

func IncludedPackages(pkgs ...string) Option

IncludedPackages is an option specifying allowed list of package names in stacktrace. If set, only packages starting with given names will be included.

func LogWithLogrus

func LogWithLogrus(lf LogrusLikeLoggingFunc) Option

LogWithLogrus is an option for using logrus on functions end with "WithErrorLog".

func LogWithPrintfFamily

func LogWithPrintfFamily(lf PrintfFamily) Option

LogWithPrintfFamily is an option for using printf-like loggers on functions end with "WithErrorLog".

func WithDetailedTrace

func WithDetailedTrace() Option

WithDetailedTrace is an option for dumping running goroutine and its traces will be dumped.

func WithLogHandler

func WithLogHandler(handler func(err string)) Option

WithLogHandler is an option for specifying custom logger on functions end with "WithErrorLog".

func WrapWithFmtErrorf

func WrapWithFmtErrorf() Option

WrapWithFmtErrorf is an option for using fmt.Errorf on error wrapping.

func Wrapf

func Wrapf(format string, args ...interface{}) Option

Wrapf is an option for adding context info to the error by wrapping it.

type Options

type Options struct {
	// Logger specifies logging function used on functions end with "WithErrLog".
	// It uses `log.Println` by default.
	Logger func(err string)

	// DetailedStacktrace specifies verbosity of stacktrace.
	// If it's true, running goroutine and its traces will be dumped.
	// Otherwise, it only dumps package and function name with source lines, similar to Java's.
	DetailedStacktrace bool

	// SkipNonProjectFiles specifies whether to skip stacktrace from non-project sources.
	// true by default.
	//
	// It is not recommended to use this option for production because it refers
	// GOPATH from environment variable for the decision. IncludedPackages is recommended.
	SkipNonProjectFiles bool

	// IncludedPackages specifies allowed list of package names in stacktrace.
	// If set, only packages starting with given names will be included.
	IncludedPackages []string

	// WrapArguments specifies additional context info added on error.
	// If first argument is string, it is used to format message with rest of the arguments and
	// will be passed to errors.Wrapf (by default) or fmt.Errorf (optional).
	WrapArguments []interface{}

	// WrapWithFmtErrorf specifies whether to use fmt.Errorf on error wrapping. false by default.
	WrapWithFmtErrorf bool
}

type PanicError

type PanicError struct {
	Reason  string
	Stack   []string
	Options Options
}

func WrapPanic

func WrapPanic(recovered interface{}, opt ...Option) *PanicError

func (PanicError) Error

func (pe PanicError) Error() string

func (PanicError) Pretty

func (pe PanicError) Pretty() (desc string)

type PrintfFamily

type PrintfFamily func(string, ...interface{})

type Stopper

type Stopper interface {
	Stop() error
}

Jump to

Keyboard shortcuts

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