errornotifier

package
v0.0.0-...-81c75b8 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2024 License: MIT Imports: 14 Imported by: 0

README

Error Notification

This package provides an interface for pushing panics and arbitrary errors into error logging systems:

type Notifier interface {
	Notify(interface{}, *http.Request) error
}

The second parameter *http.Request is optional, and will allow the notifier to provide added context/metadata from the request in a notification.

There are 4 implementations of the interface:

  • Push to Airbrake
  • Print to appkit logger
  • Buffering notifier (for testing)
  • Failing notifier (for testing)

Implementations/Configuration

Airbrake Notifier Usage

The package provides AirbrakeConfig:

type AirbrakeConfig struct {
	ProjectID   int64
	Token       string
	Environment string `default:"dev"`
}

Include a field of type errornotifier.AirbrakeConfig in your app config:

type AppConfig struct {
	// ...

	Airbrake errnotifier.AirbrakeConfig
}

And set appropriate values for this struct as part of your application configuration.

Add filters to appConfig.Airbrake:

appConfig.Airbrake.Filters = []interface{}{
    regexp.MustCompile("secret"),
    "context canceled",
}

Or use os.Setenv("AIRBRAKE_FILTERS", "['operation was canceled', 'context canceled']")

Create an Airbrake error notifier:

if notifier, err := errornotifier.NewAirbrakeNotifier(appConfig.Airbrake); err != nil {
	// handle the error
}

Then use the returned Notifier as described below.

Logging Notifier Usage

Use NewLogNotifier to construct your logging notifier:

notifier := errornotifier.NewLogNotifier(logger)

Then use the returned Notifier as described below.

Buffering Notifier Usage

Create an errornotifier/utils.BufferNotifier

notifier := utils.BufferNotifier{}

Any calls to errornotifier.Notifier.Notify will be stored in notifier.Notices. Use it as a Notifier as described below.

Failing Notifier Usage

Inside a Go test, create a errornotifier/utils.TestNotifier with the received *testing.T:

func TestStuff(t *testing.T) {
    notifier := utils.TestNotifier{t}
}

Any calls to notifier.Notify will trigger a test failure via testing.T.Fatal. Use it as a Notifier as described below.

Usage

Send error notifications via errornotifier.Notifier.Notify:

func handler(w http.ResponseWriter, r *http.Request) {
	var notifier errornotifier.Notifier = // ...

	err := doWork()
	if err != nil {
		notifier.Notify(err, r)
	}
}

Middleware/Contextual usage

The package provides a middleware that sends any panics in downstream HTTP handlers to the notifier. Wrap your existing handler using the middleware:

var notifier errornotifier.Notifier = // ...

notifierMiddleware := errornotifier.Recover(notifier)

return notifierMiddleware(handler)

This middleware will also make the notifier available to the HTTP handler via the request's context, using errornotifier.ForceContext:

func handler(w http.ResponseWriter, r *http.Request) {
	notifier := errornotifier.ForceContext(r.Context())

    notifier.Notify(..., r)
}

This will always return a valid notifier:

  1. Return notifier from request context, if any.
  2. If there is no notifier in the context, return a logging notifier using log.ForceContext. This means that the logging notifier will use the requests logger, if present. Otherwise falling back to log.Default().

NotifyOnPanic

errornotifier.NotifyOnPanic is used to make using goroutines in HTTP handlers a bit safer. It:

  1. Executes the passed function.
  2. Recovers a panic if necessary.
  3. Notifies the passed notifier if a panic occurred.
  4. Returns nil on no panic, or the error from recover.

Goroutines by default are not recovered, so for example this will crash a HTTP server (meaning program exit, not just aborting the handler for a specific request), as the panic reaches to the top level of the goroutine's stack without being handled.

func handler(w http.ResponseWriter, r *http.Request) {
    go func() {
        panic(errors.New("error"))
    }
}

to avoid this, and spawn goroutines without fear that an unhandled panic brings down the whole webserver, wrap the goroutine:

func handler(w http.ResponseWriter, r *http.Request) {
    go errornotifier.NotifyOnPanic(
        errornotifier.ForceContext(r.Context()),
        r,
        func() {
            panic(errors.New("error"))
        },
    )
}

Documentation

Overview

Package errornotifier is a notifier "provider" that provides a way to report runtime error. It uses gobrake notifier by default.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Context

func Context(c context.Context, n Notifier) context.Context

Context installs a given Error Notifier in the returned context

func NotifyOnPanic

func NotifyOnPanic(n Notifier, req *http.Request, f func()) (err error)

NotifyOnPanic will notify Airbrake if function f panics, and will return the error that caused the panic (if any)

This is for wrapping Goroutines to prevent panics from bringing down the whole application.

Example
package main

import (
	"fmt"

	"github.com/theplant/appkit/errornotifier"
	au "github.com/theplant/appkit/errornotifier/utils"
)

func main() {
	bufferNotifier := &au.BufferNotifier{}

	// return nil => Do nothing
	err := errornotifier.NotifyOnPanic(bufferNotifier, nil, func() {
		fmt.Println("do nothing")
	})
	fmt.Printf("%v %d\n", err, len(bufferNotifier.Notices))

	// panic in func => return panic error
	err = errornotifier.NotifyOnPanic(bufferNotifier, nil, func() {
		panicErr := "panic"
		fmt.Println(panicErr)
		panic(panicErr)
	})
	fmt.Printf("%v %d\n", err, len(bufferNotifier.Notices))

}
Output:

do nothing
<nil> 0
panic
panic 1

func Recover

func Recover(n Notifier) func(h http.Handler) http.Handler

Recover wraps an http.Handler to report all `panic`s to Airbrake.

Types

type AirbrakeConfig

type AirbrakeConfig struct {
	ProjectID   int64
	Token       string
	Environment string `default:"dev"`

	KeysBlocklist []interface{}
	Filters       []interface{}
}

AirbrakeConfig is struct to embed into application config to allow configuration of Airbrake notifier from environment or other external source

type Notifier

type Notifier interface {
	Notify(err interface{}, r *http.Request, context map[string]interface{})
}

Notifier defines an interface for reporting error

func ForceContext

func ForceContext(c context.Context) Notifier

ForceContext extracts a notifier from the request context, falling back to a LogNotifier using the context's logger.

func NewAirbrakeNotifier

func NewAirbrakeNotifier(c AirbrakeConfig) (Notifier, io.Closer, error)

NewAirbrakeNotifier constructs Airbrake notifier from given config

Returns error if no Airbrake configuration or airbrake configuration is invalid

Notify is async, call close to wait send data to Airbrake.

func NewLogNotifier

func NewLogNotifier(logger log.Logger) Notifier

NewLogNotifier constructs notifier that logs error notification messages to given logger

Directories

Path Synopsis
Package utils provides notifiers that implement the errornotifier.Notifier interface for use in testing.
Package utils provides notifiers that implement the errornotifier.Notifier interface for use in testing.

Jump to

Keyboard shortcuts

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