derp

package module
v0.31.0 Latest Latest
Warning

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

Go to latest
Published: Feb 28, 2024 License: Apache-2.0 Imports: 3 Imported by: 67

README

DERP 🤪

GoDoc Version Build Status Go Report Card Codecov

Better Error Reporting for Go

Derp is a drop-in replacement for the default error objects, and can be used anywhere that expects or requires an error value. It enhances Go's default with additional tracking codes, error nesting, and plug-ins for reporting errors to external sources.

1. More Informative Errors

Derp encapulates all of the data you can collect to troubleshoot the root cause of runtime errors. Here's a quick look at each argument.

  • Location The location where the error took place, typically the name of the package and function
  • Message A human readable description of the error
  • Code A custom error code for tracking exactly what error occurred.
  • Error Nested error that lets you see down the call stack
  • Details Variadic of additional parameters that may be helpful in debugging this error.

func InnerFunc(arg1 string) error {

    if err := doTheThing(); err != nil {
        // Derp create errors with more troubleshooting info than standard errors.
        return derp.NewNotFoundError("App.InnerFunc", "Error doing the thing", err.Error(), arg1)
    }

    return nil
}

func OuterFunc(arg1 string, arg2 string) {

    // Call InnerFunc with required arguments.
    if err := InnerFunction(arg1); err != nil {

        // Wraps errors with additional details and nested stack trace, then report to Ops.
        derp.Wrap(err, "App.OuterFunc", "Error calling InnerFunction", arg1, arg2).Report()
    }
}

2. Nested Errors

Derp lets you include information about your entire call stack, so that you can pinpoint exactly what's going on, and how you got there. You can embed any object that supports the Error interface.

Error Codes

Every error in derp includes a numeric error code. We suggest using standard HTTP status codes, but you can return any number that works for you. To help you dig to the original cause of the error, nested error codes will "bubble up" from the original root cause, unless you specifically override them.

To set an error code, just pass a non-zero code number to the derp.New function. To let underlying codes bubble up, just pass a zero.

3. Reporting Plug-Ins

The derp package uses plugins to report errors to an external source. Plugins can send the error to the error console, to a database, an external service, or anywhere else you desire.

Plugins should be configured once, on a system-wide basis, when your application starts up. If you don't set up any

import "github.com/benpate/derp/plugins/mongodb"

func init() {

    // By default, derp uses the ConsolePlugin{}.  You can remove
    // this default behavior by calling derp.Plugins.Clear()

    // Add a database plugin to insert error reports into your database.
    derp.Plugins.Add(mongodb.New(connectionString, collectionName))
}

func SomewhereInYourCode() {
    // Report passes the error to each of the configured
    // plugins, to deliver the error to its destination.
    derp.New(code, "location", "description", 0, nil).Report()
}
Plug-Ins

The package includes a default reporter, and you can add to this list easily using derp.Plugins.Add() to add any object that implements the Plugin interface at startup.

  • Console write a human-friendly error report to the console (this package)
  • derp-mongo writes error reports to a MongoDB database
  • derp-zerolog writes error reports to the zerolog logging package

Pull Requests Welcome

Original versions of this library have been used in production on commercial applications for years, and the extra data collection has been a tremendous help for everyone involved.

I'm now open sourcing this library, and others, with hopes that you'll also benefit from a more robust error package.

Please use GitHub to make suggestions, pull requests, and enhancements. We're all in this together! 🤪

Documentation

Index

Examples

Constants

View Source
const (

	// CodeBadRequestError indicates that the request is not properly formatted.
	// https://www.rfc-editor.org/rfc/rfc9110.html#name-400-bad-request
	CodeBadRequestError = 400

	// CodeUnauthorizedError indicates that the request requires user authentication.
	// https://www.rfc-editor.org/rfc/rfc9110.html#name-401-unauthorized
	CodeUnauthorizedError = 401

	// CodeForbiddenError means that the current user does not have the required permissions to access the requested resource.
	// https://www.rfc-editor.org/rfc/rfc9110.html#name-403-forbidden
	CodeForbiddenError = 403

	// CodeNotFoundError represents a request for a resource that does not exist, such as a database query that returns "not found"
	// https://www.rfc-editor.org/rfc/rfc9110.html#name-404-not-found
	CodeNotFoundError = 404

	// CodeValidationError retpresents a request that contains invalid data.
	// https://www.rfc-editor.org/rfc/rfc9110.html#name-422-unprocessable-content
	CodeValidationError = 422

	// CodeInternalError represents a generic error message, given when an unexpected condition was encountered and no more specific message is suitable.
	// https://www.rfc-editor.org/rfc/rfc9110.html#name-500-internal-server-error
	CodeInternalError = 500
)

Variables

This section is empty.

Functions

func ErrorCode added in v0.16.0

func ErrorCode(err error) int

ErrorCode returns an error code for any error. It tries to read the error code from objects matching the ErrorCodeGetter interface. If the provided error does not match this interface, then it assigns a generic "Internal Server Error" code 500.

func IsClientError added in v0.31.0

func IsClientError(err error) bool

IsClientError returns TRUE if the error `Code` is a 4xx / Client Error error. https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors

func IsInformational added in v0.31.0

func IsInformational(err error) bool

IsInformational returns TRUE if the error `Code` is a 1xx / Informational error. https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_informational_response

func IsRedirection added in v0.31.0

func IsRedirection(err error) bool

IsRedirection returns TRUE if the error `Code` is a 3xx / Redirection error. https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection

func IsServerError added in v0.31.0

func IsServerError(err error) bool

IsServerError returns TRUE if the error `Code` is a 5xx / Server Error error. https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors

func IsSuccess added in v0.31.0

func IsSuccess(err error) bool

IsSuccess returns TRUE if the error `Code` is a 2xx / Success error. https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success

func Message added in v0.19.1

func Message(err error) string

Message retrieves the best-fit error message for any type of error

func NilOrNotFound added in v0.29.0

func NilOrNotFound(err error) bool

NilOrNotFound returns TRUE if the error is nil or a 404 / Not Found error. All other errors return FALSE

func NotFound added in v0.16.0

func NotFound(err error) bool

NotFound returns TRUE if the error `Code` is a 404 / Not Found error.

func Report added in v0.12.0

func Report(err error)

Report takes ANY error (hopefully a derp error) and attempts to report it via all configured error reporting mechanisms.

func ReportAndReturn added in v0.28.1

func ReportAndReturn(err error) error

ReportAndReturn reports an error to the logger and also returns it to the caller.

func RootCause added in v0.13.0

func RootCause(err error) error

RootCause digs into the error stack and returns the original error that caused the DERP

func Wrap

func Wrap(inner error, location string, message string, details ...any) error

Wrap encapsulates an existing derp.Error

Example
// Derp errors can be nested, containing detailed information
// about the entire call stack, with specifics about what went
// wrong at every level

innerErr := NewNotFoundError("Inner Function", "Original Error")

middleErr := Wrap(innerErr, "Middleware Function", "Error calling 'innerErr'", "parameter", "list", "here")

outerErr := Wrap(middleErr, "Error in Main Function", "Error calling 'middleErr'", "suspected", "cause", "of", "the", "error")

Report(outerErr)
Output:

Example (StandardErrors)
// Wrap also works with standard library errors
// so you can add information to errors that are
// exported by other packages that don't use derp.
thisBreaks := func() error {
	return errors.New("Something failed")
}

// Try something that fails
if err := thisBreaks(); err != nil {

	// Populate a derp.Error with everything you know about the error
	result := Wrap(err, "Example", "Something broke in `thisBreaks`", WithCode(404), "additional details go here")

	// Call .Report() to send an error to Ops. This is a system-wide
	// configuration that's set up during initialization.
	Report(result)
}
Output:

Types

type Error

type Error struct {
	Code         int    `json:"code"`       // Numeric error code (such as an HTTP status code) to report to the client.
	Location     string `json:"location"`   // Function name (or other location description) of where the error occurred
	Message      string `json:"message"`    // Primary (top-level) error message for this error
	TimeStamp    int64  `json:"timestamp"`  // Unix Epoch timestamp of the date/time when this error was created
	Details      []any  `json:"details"`    // Additional information related to this error message, such as parameters to the function that caused the error.
	WrappedValue error  `json:"innerError"` // An underlying error object used to identify the root cause of this error.
}

Error represents a runtime error. It includes

func New

func New(code int, location string, message string, details ...any) Error

New returns a new Error object

Example
// Derp errors work anywhere that you use normal errors.
// They just contain more information about what actually happened.
// Here's how to create a new error to report back to a caller
err := NewNotFoundError("Code Location", "Error Message", "additional details here", 12345, map[string]any{})

// Pluggable error reporting interface can dump errors to the console
// or anywhere else that you want to send them.
Report(err)
Output:

func NewBadRequestError added in v0.22.1

func NewBadRequestError(location string, message string, details ...any) Error

func NewForbiddenError added in v0.22.1

func NewForbiddenError(location string, message string, details ...any) Error

func NewInternalError added in v0.22.1

func NewInternalError(location string, message string, details ...any) Error

func NewNotFoundError added in v0.22.1

func NewNotFoundError(location string, message string, details ...any) Error

func NewUnauthorizedError added in v0.25.0

func NewUnauthorizedError(location string, message string, details ...any) Error

func NewValidationError added in v0.26.0

func NewValidationError(message string, details ...any) Error

func (Error) Error

func (err Error) Error() string

Error implements the Error interface, which allows derp.Error objects to be used anywhere a standard error is used.

func (Error) GetErrorCode added in v0.31.0

func (err Error) GetErrorCode() int

ErrorCode returns the error Code embedded in this Error.

func (Error) GetMessage added in v0.31.0

func (err Error) GetMessage() string

ErrorMessage returns the error Message embedded in this Error.

func (Error) Unwrap added in v0.10.0

func (err Error) Unwrap() error

Unwrap supports Go 1.13+ error unwrapping

type ErrorCodeGetter added in v0.16.0

type ErrorCodeGetter interface {

	// ErrorCode returns a numeric, application-specific code that references this error.
	// HTTP status codes are recommended, but not required
	GetErrorCode() int
}

ErrorCodeGetter interface describes any error that can also "get" an error code value

type MessageGetter added in v0.20.0

type MessageGetter interface {

	// Message returns a human-friendly string representation of the error.
	GetMessage() string
}

MessageGetter interface describes any error that can also report a "Message"

type Option added in v0.29.0

type Option func(*Error)

Option defines a function that modifies a derp.Error

func WithBadRequest added in v0.29.0

func WithBadRequest() Option

WithBadRequest returns an option that sets the derp.Error code to 400 (Bad Request)

func WithCode added in v0.29.0

func WithCode(code int) Option

func WithForbidden added in v0.29.0

func WithForbidden() Option

WithForbidden returns an option that sets the derp.Error code to 403 (Forbidden)

func WithInternalError added in v0.29.0

func WithInternalError() Option

WithInternalError returns an option that sets the derp.Error code to 500 (Internal Server Error)

func WithLocation added in v0.29.0

func WithLocation(location string) Option

WithLocation returns an option that sets the derp.Error location

func WithMessage added in v0.31.0

func WithMessage(message string) Option

WithMessage returns an option that sets the derp.Error message

func WithNotFound added in v0.29.0

func WithNotFound() Option

WithNotFound returns an option that sets the derp.Error code to 404 (Not Found)

func WithWrappedValue added in v0.29.0

func WithWrappedValue(inner error) Option

WithWrappedValue returns an option that sets the derp.Error wrapped value

type Plugin

type Plugin interface {
	Report(error)
}

Plugin wraps the "Report" method, which reports a derp error to an external source. Reporters are responsible for handling and swallowing any errors they generate.

type PluginList

type PluginList []Plugin

PluginList represents an array of plugins, which will be called in succession whenever the Error.Report() function is called.

var Plugins PluginList

Plugins is the array of objects that are able to report a derp when err.Report() is called.

func (PluginList) Add

func (list PluginList) Add(plugin Plugin) PluginList

Add registers a new plugin to the system-wide configuration. This lets the developer configure and append additional plugins during initialization. It should be called during system startup only.

func (PluginList) Clear

func (list PluginList) Clear() PluginList

Clear removes all plugins from the system-wide configuration. It is useful for removing the library default Console() from the list of plugins, in the event that you don't want to report errors to the console.

type Unwrapper added in v0.13.0

type Unwrapper interface {

	// Unwrap returns the inner error bundled inside of an outer error.
	Unwrap() error
}

Unwrapper interface describes any error that can be "unwrapped". It supports the Unwrap method added in Go 1.13+

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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