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 ¶
- func Decorate(tags map[string]string) func()
- func GracefullyShutdown(err interface{}, timeout time.Duration)
- func Init(opts ...Option) error
- func LambdaMiddleware[TIn any](nextHandler lambdafunction.HandlerOf[TIn], config ...LambdaOption) lambdafunction.HandlerOf[TIn]
- func LambdaWithOutputMiddleware[TIn any, TOut any](nextHandler lambdafunction.HandlerWithOutputOf[TIn, TOut], ...) lambdafunction.HandlerWithOutputOf[TIn, TOut]
- func NewGoaEndpointMiddleware() func(goa.Endpoint) goa.Endpoint
- func NewHTTPMiddleware(onRequestPanic OnRequestPanicHandler) func(http.Handler) http.Handler
- func ReportError(ctx context.Context, err error)
- func RootCauseAsTitle(event *sentry.Event, hint *sentry.EventHint) *sentry.Event
- type LambdaOption
- type OnRequestPanicHandler
- type Option
- func WithBeforeFilter(filter SentryBeforeFilter) Option
- func WithBuildDetails(farm, buildNumber, branch, commit string) Option
- func WithDSN(dsn string) Option
- func WithDebug() Option
- func WithEnvironment(env string) Option
- func WithRelease(appName, appVersion string) Option
- func WithServerlessTransport() Option
- func WithTag(name string, value string) Option
- func WithTags(tags map[string]string) Option
- func WithTransport(transport sentry.Transport) Option
- type SentryBeforeFilter
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Decorate ¶
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 ¶
GracefullyShutdown flushes the Sentry client buffered events with blocking for at most the given timeout.
func Init ¶
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 ¶
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 ¶
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 ¶
WithBuildDetails configures Sentry to send build details along with error reports.
func WithEnvironment ¶
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 ¶
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 ¶
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 ¶
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.