derp

package module
v0.35.0 Latest Latest
Warning

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

Go to latest
Published: Jan 2, 2026 License: Apache-2.0 Imports: 7 Imported by: 105

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.NotFound("App.InnerFunc", "Error doing the thing", err.Error(), arg1)
    }

    return nil
}

func OuterFunc(arg1 string, arg2 string) error {

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

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

	return nil
}

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 derp erro is defined with a specific error code, corresponding to the standard HTTP status codes. These are created with helper functions such as InternalError and NotFoundError.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.

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 plugins, then the default setting is to report errors to the system console.

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.Internal("location", "description", 0, nil).Report()
}

4. Error Classification

Derp uses HTTP status codes to classify error states, and includes several functions to determine "categories" of errors:

derp.IsBadRequest(err)
derp.IsClientError(err)
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

Overview

Package derp provides a standardized way to create and manage errors in Go applications.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Details added in v0.32.3

func Details(err error) []any

Details retrieves the best-fit error details for any type of error

func ErrorCode

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 IsBadRequest added in v0.32.2

func IsBadRequest(err error) bool

IsBadRequest returns TRUE if this is a 400 (Bad Request) error.

func IsClientError

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 IsForbidden added in v0.32.2

func IsForbidden(err error) bool

IsForbidden returns TRUE if this is a 403 (Forbidden) error.

func IsGone added in v0.34.0

func IsGone(err error) bool

IsGone returns TRUE if this is a 410 (Gone) error.

func IsInformational

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 IsInternalServerError added in v0.32.2

func IsInternalServerError(err error) bool

IsInternalServerError returns TRUE if this is a 500 (Internal Server Error) error.

func IsMisdirectedRequest added in v0.32.2

func IsMisdirectedRequest(err error) bool

IsMisdirectedRequest returns TRUE if this is a 421 (Misdirected Request) error.

func IsNil added in v0.32.2

func IsNil(err error) bool

IsNil performs a robust nil check on an error interface Shout out to: https://medium.com/@mangatmodi/go-check-nil-interface-the-right-way-d142776edef1

func IsNotFound added in v0.32.1

func IsNotFound(err error) bool

IsNotFound returns TRUE if this is a 404 (Not Found) error.

func IsNotFoundOrGone added in v0.34.0

func IsNotFoundOrGone(err error) bool

IsNotFoundOrGone returns TRUE if this is a 404 (Not Found) or 410 (Gone) error.

func IsNotImplemented added in v0.32.2

func IsNotImplemented(err error) bool

IsNotImplemented returns TRUE if this is a 501 (Not Implemented) error.

func IsRedirection

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

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

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 IsTeapot added in v0.32.2

func IsTeapot(err error) bool

IsTeapot returns TRUE if this is a 418 (I'm a Teapot) error.

func IsTooManyRequests added in v0.34.2

func IsTooManyRequests(err error) (bool, time.Duration)

IsTooManyRequests returns TRUE if this is a 429 (Too Many Requests) error. If TRUE, it tries to find the recommended retry duration from the returned error. If no duration is found, then a default 1 hour retry duration is used.

func IsUnauthorized added in v0.32.2

func IsUnauthorized(err error) bool

IsUnauthorized returns TRUE if this is a 401 (Unauthorized) error.

func IsValidationError added in v0.32.2

func IsValidationError(err error) bool

IsValidationError returns TRUE if this is a 422 (Validation) error.

func Location added in v0.32.3

func Location(err error) string

Location retrieves the best-fit error location for any type of error

func Message

func Message(err error) string

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

func NotNil added in v0.32.2

func NotNil(err error) bool

NotNil returns TRUE if the error is NOT nil.

func Report

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

func ReportAndReturn(err error) error

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

func ReportFunc added in v0.32.7

func ReportFunc(fn func() error)

ReportFunc executes the provided function and reports any error that occurs. This is useful with `defer` statements, preventing the underlying function from being executed before the deferred call.

func RetryAfter added in v0.35.0

func RetryAfter(err error) time.Duration

RetryAfter retrieves the best-fit retry-after duration (in seconds) for any type of error

func RootCause

func RootCause(err error) error

RootCause digs into the error stack and returns the original error that caused the DERP. This is an alias for the Unwrap() function.

func RootLocation added in v0.32.5

func RootLocation(err error) string

RootLocation returns the deepest location defined within a chain of wrapped errors.

func RootMessage added in v0.32.5

func RootMessage(err error) string

RootMessage returns the deepest message available within a chain of wrapped errors.

func Serialize added in v0.32.6

func Serialize(err error) string

Serialize converts any error into its JSON string representation.

func URL added in v0.32.3

func URL(err error) string

URL retrieves the best-fit error URL for any type of error

func Unwrap added in v0.34.2

func Unwrap(err error) error

Unwrap 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, and is guaranteed to return a "Not Nil" value. This function ALWAYS returns a non-nil error value.

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

innerErr := NotFound("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)
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)
}

func WrapIF added in v0.33.0

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

WrapIF returns a wrapped error if the inner error is not nil. If the inner error is nil, then this function returns nil.

Types

type DetailsGetter added in v0.32.3

type DetailsGetter interface {
	// Details returns a list of details about the error.
	GetDetails() []any
}

DetailsGetter interface wraps the GetDetails method, which returns a list of details about the error

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
	URL          string `json:"url,omitempty"`        // URL to a web page with more information about this error
	Details      []any  `json:"details,omitempty"`    // Additional information related to this error message, such as parameters to the function that caused the error.
	TimeStamp    int64  `json:"timestamp"`            // Unix Epoch timestamp of the date/time when this error was created
	WrappedValue error  `json:"innerError,omitempty"` // An underlying error object used to identify the root cause of this error.
}

Error represents a runtime error. It includes

func AsError added in v0.34.3

func AsError(err error) Error

AsError converts a generic error into a derp.Error type

func BadRequest added in v0.33.0

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

BadRequest returns a (400) Bad Request error which indicates that the request is not properly formatted. https://www.rfc-editor.org/rfc/rfc9110.html#name-400-bad-request

func BadRequestError added in v0.32.1

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

deprecated: use BadRequest() instead

func Forbidden added in v0.33.0

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

Forbidden returns a (403) Forbidden error which indicates that the current user does not have permissions to access the requested resource. https://www.rfc-editor.org/rfc/rfc9110.html#name-403-forbidden

func ForbiddenError added in v0.32.1

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

deprecated: use Forbidden() instead

func Gone added in v0.34.0

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

Gone returns a (410) Gone error which indicates that the resource requested is no longer available and will not be available again. https://www.rfc-editor.org/rfc/rfc9110.html#name-410-gone

func Internal added in v0.33.0

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

Internal returns a (500) Internal Server Error which 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

func InternalError added in v0.32.1

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

deprecated: use Internal() instead

func MisdirectedRequest added in v0.33.0

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

MisdirectedRequest returns a (421) Misdirected Request error. which indicates that the request was made to the wrong server; that server is not able to produce a response. https://www.rfc-editor.org/rfc/rfc9110.html#name-421-misdirected-request

func MisdirectedRequestError added in v0.32.1

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

deprecated: use MisdirectedRequest() instead

func NotFound

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

NotFound returns a (404) Not Found error which indicates that the requested resource does not exist, such as when database query returns "not found" https://www.rfc-editor.org/rfc/rfc9110.html#name-404-not-found

func NotFoundError added in v0.32.1

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

deprecated: use NotFound() instead

func NotImplemented added in v0.33.0

func NotImplemented(location string, details ...any) Error

NotImplemented returns a (501) Not Implemented error which indicates that the server does not support the functionality required to fulfill the request. https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented

func NotImplementedError added in v0.32.1

func NotImplementedError(location string, details ...any) Error

deprecated: use NotImplemented() instead

func Teapot added in v0.33.0

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

Teapot returns a (418) I'm a Teapot error which indicates that the server is a teapot that cannot serve HTTP requests. https://www.rfc-editor.org/rfc/rfc7168.html#name-418-im-a-teapot https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#418

func TeapotError added in v0.32.1

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

deprecated: use Teapot() instead

func Timeout added in v0.33.0

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

Timeout returns a (524) Timeout error which indicates that the request took longer than an internal timeout threshold https://http.dev/524

func TimeoutError added in v0.32.4

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

deprecated: use Timeout() instead

func Unauthorized added in v0.33.0

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

Unauthorized returns a (401) Unauthorized error which indicates that the request requires user authentication. https://www.rfc-editor.org/rfc/rfc9110.html#name-401-unauthorized

func UnauthorizedError added in v0.32.1

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

deprecated: use Unauthorized() instead

func Validation added in v0.33.0

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

Validation returns a (422) Validation error which indicates that the request contains invalid data. https://www.rfc-editor.org/rfc/rfc9110.html#name-422-unprocessable-content

func ValidationError added in v0.16.0

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

deprecated: use Validation() instead

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) GetDetails added in v0.32.3

func (err Error) GetDetails() []any

GetDetails returns the error Details embedded in this Error.

func (Error) GetErrorCode

func (err Error) GetErrorCode() int

GetErrorCode returns the error Code embedded in this Error.

func (Error) GetLocation added in v0.32.3

func (err Error) GetLocation() string

GetLocation returns the error Location embedded in this Error.

func (Error) GetMessage

func (err Error) GetMessage() string

GetMessage returns the error Message embedded in this Error.

func (Error) GetRetryAfter added in v0.35.0

func (err Error) GetRetryAfter() time.Duration

GetRetryAfter returns the retry-after duration (in seconds) provided by the WrappedValue. If the WrappedValue is nil, or does not implement the RetryAfterGetter interface, this method returns 0

func (Error) GetTimeStamp added in v0.32.3

func (err Error) GetTimeStamp() int64

GetTimeStamp returns the error TimeStamp embedded in this Error.

func (Error) GetURL added in v0.32.3

func (err Error) GetURL() string

GetURL returns the help URL embedded in this Error.

func (Error) IsZero added in v0.34.3

func (err Error) IsZero() bool

IsZero returns true if this Error is empty / uninitialized

func (Error) Unwrap

func (err Error) Unwrap() error

Unwrap supports Go 1.13+ error unwrapping

type ErrorCodeGetter

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 wraps the GetErrorCode method, which returns a numeric, application-specific code that references this error

type HTTPError added in v0.34.2

type HTTPError struct {
	Request  HTTPRequestReport  `json:"request"`
	Response HTTPResponseReport `json:"response"`

	WrappedValue error `json:"innerError,omitempty"` // An underlying error object used to identify the root cause of this error.
}

HTTPError wraps a standard derp.Error, including additional data about a failed HTTP transaction

func NewHTTPError added in v0.34.2

func NewHTTPError(request *http.Request, response *http.Response) HTTPError

NewHTTPError creates a new HTTPError object from the given request and response

func UnwrapHTTPError added in v0.34.2

func UnwrapHTTPError(err error) *HTTPError

UnwrapHTTPError unwraps the provided error, returning the first HTTPError found in the chain. If no HTTPError is found, this function returns nil.

func WrapHTTPError added in v0.34.2

func WrapHTTPError(err error, request *http.Request, response *http.Response) HTTPError

WrapHTTPError creates a new HTTPError object from the given request/response ands wraps an existing error

func (HTTPError) Error added in v0.34.2

func (err HTTPError) Error() string

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

func (HTTPError) GetErrorCode added in v0.34.2

func (err HTTPError) GetErrorCode() int

GetErrorCode returns the error Code embedded in this Error.

func (HTTPError) GetRetryAfter added in v0.35.0

func (err HTTPError) GetRetryAfter() time.Duration

RetryAfter returns the number of seconds to wait until retrying the transaction. It is derived from one of several possible headers in the HTTP response, including `Retry-After`, `X-Ratelimit-Reset`, and `X-Rate-Limit-Reset`.

If no such header is found, this method returns a default of 3600 seconds (1 hour). https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/429

func (HTTPError) Unwrap added in v0.34.2

func (err HTTPError) Unwrap() error

Unwrap returns the inner error wrapped by this HTTPError.

type HTTPRequestReport added in v0.34.2

type HTTPRequestReport struct {
	URL    string      `json:"url"`
	Method string      `json:"method"`
	Header http.Header `json:"header"`
}

HTTPRequestReport includes details of a failed HTTP request

type HTTPResponseReport added in v0.34.2

type HTTPResponseReport struct {
	StatusCode int         `json:"statusCode"`
	Status     string      `json:"status"`
	Header     http.Header `json:"header"`
}

HTTPResponseReport includes response details of a failed HTTP request

type LocationGetter added in v0.32.3

type LocationGetter interface {
	// Location returns the location of the error in the source code.
	GetLocation() string
}

LocationGetter interface wraps the GetLocation method, which returns the location of the error

type MessageGetter

type MessageGetter interface {

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

MessageGetter interface wraps the GetMessage method, which returns a human-friendly string representation of the error

type Option

type Option func(*Error)

Option defines a function that modifies a derp.Error

func WithBadRequest

func WithBadRequest() Option

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

func WithCode

func WithCode(code int) Option

WithCode returns an option that sets the derp.Error code

func WithForbidden

func WithForbidden() Option

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

func WithInternalError

func WithInternalError() Option

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

func WithLocation

func WithLocation(location string) Option

WithLocation returns an option that sets the derp.Error location

func WithMessage

func WithMessage(message string) Option

WithMessage returns an option that sets the derp.Error message

func WithNotFound

func WithNotFound() Option

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

func WithUnauthorized added in v0.34.1

func WithUnauthorized() Option

WithUnauthorized returns an option that sets the derp.Error code to 401 (Unauthorized)

func WithWrappedValue

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 = make([]Plugin, 0)

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 RetryAfterGetter added in v0.35.0

type RetryAfterGetter interface {
	// RetryAfter returns the number of seconds to wait before retrying the operation that caused this error.
	GetRetryAfter() time.Duration
}

RetryAfterGetter interface wraps the GetRetryAfter method, which returns the number of seconds to wait before retrying the operation that caused this error

type URLGetter added in v0.32.3

type URLGetter interface {
	// URL returns a URL to a web page with more information about this error.
	GetURL() string
}

URLGetter interface wraps the GetURL method, which returns a URL to a web page with more information about this error

type Unwrapper

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
Package plugins provides a number of reporting plugins for derp.
Package plugins provides a number of reporting plugins for derp.

Jump to

Keyboard shortcuts

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