errorreport

package
v0.0.11 Latest Latest
Warning

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

Go to latest
Published: Jan 13, 2024 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package errorreport enables you to configure Sentry for error reporting. A general ReportError function is provided for ad-hoc reporting, as well as several options for middleware. These middleware detect and report errors automatically.

See the executable examples below and on individual functions for more details on usage.

You configure and initialise errorreport using Init():

err := errorreport.Init(
         errorreport.WithDSN(os.Getenv("SENTRY_DSN")),
         errorreport.WithRelease(os.Getenv("APP"), os.Getenv("APP_VERSION")),
         errorreport.WithEnvironment(os.Getenv("AWS_ENVIRONMENT_NAME")))
if err != nil {
  // handle initialisation error
}

Ad-hoc errors can be reported using ReportError():

errorreport.ReportError(ctx, errors.New("We hit a snag!"))

For application without middleware, Panic can be captured and reported to sentry in main before the program exits in main

defer func() {
  if err := recover(); err != nil {
    errorreport.GracefullyShutdown(err, timeout)
}()

For application with middleware, HTTP middleware can be used. Passing in nil uses the default panic handler. See the OnRequestPanicHandler type if you wish to supply your own.

mw := middleware.NewHTTPMiddleware(nil)
mw(myHTTPHandler)

Goa middleware can be used, allowing errors to be reported automatically from Goa applications:

mw := errorreport.NewGoaMiddleware()
mw(myGoaEndpoint)

This is recommended when using Goa, as it offers reporting of all errors returned from the generated logic types.

This package also supports middleware for Lambda functions:

mw := errorreport.NewLambdaMiddleware(errorreport.LambdaErrorOptions{})
Example (Fargate)
package main

import (
	"context"
	"os"
	"time"

	"github.com/cultureamp/ca-go/x/log"
	"github.com/cultureamp/ca-go/x/sentry/errorreport"
)

var (
	app         string
	appVersion  string
	buildNumber string
	branch      string
	commit      string
)

type Settings struct {
	SentryDSN string
	Farm      string
	AppEnv    string
}

func getSettings() *Settings {
	return &Settings{
		SentryDSN: os.Getenv("SENTRY_DSN"),
		Farm:      os.Getenv("FARM"),
		AppEnv:    os.Getenv("APP_ENV"),
	}
}

func main() {
	// This is an example of how to use the errorreport package in a Main
	// function. The following is an example `main` function.

	ctx := context.Background()
	logger := log.NewFromCtx(ctx)

	settings := getSettings()

	// configure error reporting settings
	err := errorreport.Init(
		errorreport.WithDSN(settings.SentryDSN),
		errorreport.WithRelease(app, appVersion),
		errorreport.WithEnvironment(settings.AppEnv),
		errorreport.WithBuildDetails(settings.Farm, buildNumber, branch, commit),
		errorreport.WithTag("application_name", app),
		// optionally add a tag to every error report
		errorreport.WithTag("animal", "gopher"),

		// or add multiple tags at once to be added to every error report
		errorreport.WithTags(map[string]string{
			"genus":   "phoenicoparrus",
			"species": "jamesi",
		}),
		errorreport.WithBeforeFilter(errorreport.RootCauseAsTitle),
	)
	if err != nil {
		logger.Fatal().Err(err).Msg("sentry init")
	}

	// handle core business logic here
	handleBusinessLogic(ctx)

	// capture panic and report to sentry before the program exits
	defer func() {
		if err := recover(); err != nil {
			errorreport.GracefullyShutdown(err, time.Second*5)
		}
	}()
}

func handleBusinessLogic(ctx context.Context) {
	if _, err := doSomething(); err != nil {

		errorreport.ReportError(ctx, err)
	}
}

func doSomething() (string, error) {
	return "", nil
}
Output:

Example (Lambda)
package main

import (
	"context"
	"os"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"

	"github.com/cultureamp/ca-go/x/sentry/errorreport"
)

var (
	app         string
	appVersion  string
	buildNumber string
	branch      string
	commit      string
)

type Settings struct {
	SentryDSN string
	Farm      string
	AppEnv    string
}

func getSettings() *Settings {
	return &Settings{
		SentryDSN: os.Getenv("SENTRY_DSN"),
		Farm:      os.Getenv("FARM"),
		AppEnv:    os.Getenv("APP_ENV"),
	}
}

func main() {
	// This is an example of how to use the errorreport package in a Lambda
	// function. The following is an example `main` function.

	ctx := context.Background()

	// in a real application, use something like "github.com/kelseyhightower/envconfig"
	settings := getSettings()

	// configure error reporting settings
	err := errorreport.Init(
		errorreport.WithDSN(settings.SentryDSN),
		errorreport.WithRelease(app, appVersion),
		errorreport.WithEnvironment(settings.AppEnv),
		errorreport.WithBuildDetails(settings.Farm, buildNumber, branch, commit),
		errorreport.WithServerlessTransport(),

		// optionally add a tag to every error report
		errorreport.WithTag("animal", "gopher"),

		// or add multiple tags at once to be added to every error report
		errorreport.WithTags(map[string]string{
			"genus":   "phoenicoparrus",
			"species": "jamesi",
		}),

		// optionally customise error title with the root cause message
		errorreport.WithBeforeFilter(errorreport.RootCauseAsTitle),
	)
	if err != nil {
		// FIX: write error to log
		os.Exit(1)
	}

	// wrap the lambda handler function with error reporting
	handler := errorreport.LambdaMiddleware(Handler)

	// start the lambda function
	lambda.StartWithOptions(handler, lambda.WithContext(ctx))
}

// Handler is the lambda handler function with the logic to be executed. In this
// case, it's a Kinesis event handler, but this could be a handler for any
// Lambda event.
func Handler(ctx context.Context, event events.KinesisEvent) error {
	for _, record := range event.Records {
		if err := processRecord(ctx, record); err != nil {
			return err
		}
	}

	return nil
}

func processRecord(ctx context.Context, record events.KinesisEventRecord) error {

	defer errorreport.Decorate(map[string]string{
		"event_id":        record.EventID,
		"partition_key":   record.Kinesis.PartitionKey,
		"sequence_number": record.Kinesis.SequenceNumber,
	})()

	return nil
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Decorate

func Decorate(tags map[string]string) func()

Decorate creates a new Sentry scope and adds the supplied tags. This allows for any errors that are generated in this scope to have additional information added to them. For example, this is useful when processing multiple event records in a batch. The return value is a function that should be passed to `defer` so the created scope is automatically popped.

Example
package main

import (
	"github.com/cultureamp/ca-go/x/sentry/errorreport"
)

func main() {
	defer errorreport.Decorate(map[string]string{
		"key":    "123",
		"animal": "flamingo",
	})()

	// Since this API is designed around "defer", don't use it in a loop.
	// Instead, create a function and call that function in a loop.

}
Output:

func GracefullyShutdown

func GracefullyShutdown(err interface{}, timeout time.Duration)

GracefullyShutdown flushes the Sentry client buffered events with blocking for at most the given timeout.

func Init

func Init(opts ...Option) error

Init initialises the Sentry client with the given options. It returns an error if mandatory options are not supplied.

func LambdaMiddleware

func LambdaMiddleware[TIn any](nextHandler lambdafunction.HandlerOf[TIn], config ...LambdaOption) lambdafunction.HandlerOf[TIn]

LambdaMiddleware[TIn] provides error-handling middleware for a Lambda function that has a payload type of TIn. This suits Lambda functions like event processors, where the return has no payload.

func LambdaWithOutputMiddleware

func LambdaWithOutputMiddleware[TIn any, TOut any](nextHandler lambdafunction.HandlerWithOutputOf[TIn, TOut], config ...LambdaOption) lambdafunction.HandlerWithOutputOf[TIn, TOut]

LambdaWithOutputMiddleware[TIn, TOut] provides error-handling middleware for a Lambda function that has a payload type of TIn and returns the tuple TOut,error.

func NewGoaEndpointMiddleware

func NewGoaEndpointMiddleware() func(goa.Endpoint) goa.Endpoint

NewGoaEndpointMiddleware returns Goa middleware to detect and report errors to Sentry.

func NewHTTPMiddleware

func NewHTTPMiddleware(onRequestPanic OnRequestPanicHandler) func(http.Handler) http.Handler

NewHTTPMiddleware returns an http.Handler that reports panics to Sentry, recovers from the panic, and calls the OnRequestPanicHandler if provided. If a handler is not provided, returns a JSON:API structured body with status 500.

func ReportError

func ReportError(ctx context.Context, err error)

ReportError reports an error to Sentry. It will attempt to extract request IDs and the authenticated user from the context.

func RootCauseAsTitle

func RootCauseAsTitle(event *sentry.Event, hint *sentry.EventHint) *sentry.Event

RootCauseAsTitle uses error message as custom exception type. The general errors like *erros.errorString can end up grouping errors and makes it harder for us to find the latest error in Sentry issues dashboard.

Types

type LambdaOption

type LambdaOption func(o *lambdaOptions)

LambdaOption is a function type that can be supplied to alter the behaviour of the LambdaMiddleware functions.

func WithRepanic

func WithRepanic(repanic bool) LambdaOption

WithRepanic configures whether to panic again after reporting an error to Sentry. This setting defaults to true, as typically the function invocation should be allowed to fail by the standard Lambda mechanisms once a panic occurs.

type OnRequestPanicHandler

type OnRequestPanicHandler func(context.Context, http.ResponseWriter, error)

OnRequestPanicHandler is a function that can be supplied to HTTP middleware to perform further processing of an HTTP request after a panic has occurred.

type Option

type Option func(c *config)

Option is a function type that can be provided to Configure to modify the behaviour of Sentry.

func WithBeforeFilter

func WithBeforeFilter(filter SentryBeforeFilter) Option

WithBeforeFilter configures a function that will be called before an error is reported. This can be used to filter out certain errors from being reported.

func WithBuildDetails

func WithBuildDetails(farm, buildNumber, branch, commit string) Option

WithBuildDetails configures Sentry to send build details along with error reports.

func WithDSN

func WithDSN(dsn string) Option

WithDSN configures Sentry with the given DSN. This is a mandatory option.

func WithDebug

func WithDebug() Option

WithDebug configures Sentry to log debug information.

func WithEnvironment

func WithEnvironment(env string) Option

WithEnvironment configures Sentry for the given environment, e.g. production-us. This is the name of the AWS account to which the application is deployed, and should be supplied to the application from the infrastructure via an environment variable. Environment names are defined in the Culture Amp CDK Constructs. This is a mandatory option.

func WithRelease

func WithRelease(appName, appVersion string) Option

WithRelease formats the Sentry release with the given app name and version. This is a mandatory option.

func WithServerlessTransport

func WithServerlessTransport() Option

WithServerlessTransport configures Sentry with the correct transport for serverless applications.

func WithTag

func WithTag(name string, value string) Option

WithTag adds the specified name/value pair as a tag on every error report. Tags are used for grouping and searching error reports.

func WithTags

func WithTags(tags map[string]string) Option

WithTag adds multiple name/value pairs as tags on every error report. Tags are used for grouping and searching error reports.

func WithTransport

func WithTransport(transport sentry.Transport) Option

WithTransport configures an alternate transport for sending reports to Sentry.

type SentryBeforeFilter

type SentryBeforeFilter func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event

SentryBeforeFilter is executed before a Sentry event is sent. It allows attributes of the event to be modified. The event can be discarded by returning nil.

Jump to

Keyboard shortcuts

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