From 71aea9b5077285c0ce0ea9e8a950de029a18b4de Mon Sep 17 00:00:00 2001 From: DarthSim Date: Sun, 10 Mar 2024 20:44:45 +0300 Subject: [PATCH] Add processing options and source image URL to error reports --- CHANGELOG.md | 3 +++ errorreport/airbrake/airbrake.go | 23 ++++++++++++++++---- errorreport/bugsnag/bugsnag.go | 14 +++++++++--- errorreport/errorreport.go | 30 ++++++++++++++++++++++---- errorreport/honeybadger/honeybadger.go | 30 ++++++++++++++++---------- errorreport/sentry/sentry.go | 26 ++++++++++++++-------- processing_handler.go | 3 +++ server.go | 3 +++ 8 files changed, 101 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbf10b45..cd5b0e8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog ## [Unreleased] +### Add +- Add processing/info options and source image URL to error reports. + ### Change - Support configuring OpenTelemetry with standard [general](https://opentelemetry.io/docs/languages/sdk-configuration/general/) and [OTLP Exporter](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/) environment variables. - `IMGPROXY_MAX_SRC_RESOLUTION` default value is increased to 50. diff --git a/errorreport/airbrake/airbrake.go b/errorreport/airbrake/airbrake.go index 899f51db..c13478b5 100644 --- a/errorreport/airbrake/airbrake.go +++ b/errorreport/airbrake/airbrake.go @@ -2,12 +2,18 @@ package airbrake import ( "net/http" + "strings" "github.com/airbrake/gobrake/v5" + "github.com/imgproxy/imgproxy/v3/config" ) -var notifier *gobrake.Notifier +var ( + notifier *gobrake.Notifier + + metaReplacer = strings.NewReplacer(" ", "-") +) func Init() { if len(config.AirbrakeProjecKey) > 0 { @@ -19,10 +25,19 @@ func Init() { } } -func Report(err error, req *http.Request) { - if notifier != nil { - notifier.Notify(err, req) +func Report(err error, req *http.Request, meta map[string]any) { + if notifier == nil { + return } + + notice := notifier.Notice(err, req, 2) + + for k, v := range meta { + key := metaReplacer.Replace(strings.ToLower(k)) + notice.Context[key] = v + } + + notifier.SendNoticeAsync(notice) } func Close() { diff --git a/errorreport/bugsnag/bugsnag.go b/errorreport/bugsnag/bugsnag.go index 1cda26fe..64a39294 100644 --- a/errorreport/bugsnag/bugsnag.go +++ b/errorreport/bugsnag/bugsnag.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/bugsnag/bugsnag-go/v2" + "github.com/imgproxy/imgproxy/v3/config" ) @@ -19,8 +20,15 @@ func Init() { } } -func Report(err error, req *http.Request) { - if enabled { - bugsnag.Notify(err, req) +func Report(err error, req *http.Request, meta map[string]any) { + if !enabled { + return } + + extra := make(bugsnag.MetaData) + for k, v := range meta { + extra.Add("Processing Context", k, v) + } + + bugsnag.Notify(err, req, extra) } diff --git a/errorreport/errorreport.go b/errorreport/errorreport.go index fa0bca32..97e745bb 100644 --- a/errorreport/errorreport.go +++ b/errorreport/errorreport.go @@ -1,6 +1,7 @@ package errorreport import ( + "context" "net/http" "github.com/imgproxy/imgproxy/v3/errorreport/airbrake" @@ -9,6 +10,8 @@ import ( "github.com/imgproxy/imgproxy/v3/errorreport/sentry" ) +type metaCtxKey struct{} + func Init() { bugsnag.Init() honeybadger.Init() @@ -16,11 +19,30 @@ func Init() { airbrake.Init() } +func StartRequest(req *http.Request) context.Context { + meta := make(map[string]any) + return context.WithValue(req.Context(), metaCtxKey{}, meta) +} + +func SetMetadata(req *http.Request, key string, value any) { + meta, ok := req.Context().Value(metaCtxKey{}).(map[string]any) + if !ok || meta == nil { + return + } + + meta[key] = value +} + func Report(err error, req *http.Request) { - bugsnag.Report(err, req) - honeybadger.Report(err, req) - sentry.Report(err, req) - airbrake.Report(err, req) + meta, ok := req.Context().Value(metaCtxKey{}).(map[string]any) + if !ok { + meta = nil + } + + bugsnag.Report(err, req, meta) + honeybadger.Report(err, req, meta) + sentry.Report(err, req, meta) + airbrake.Report(err, req, meta) } func Close() { diff --git a/errorreport/honeybadger/honeybadger.go b/errorreport/honeybadger/honeybadger.go index 963bf74b..8bd65b1c 100644 --- a/errorreport/honeybadger/honeybadger.go +++ b/errorreport/honeybadger/honeybadger.go @@ -5,13 +5,14 @@ import ( "strings" "github.com/honeybadger-io/honeybadger-go" + "github.com/imgproxy/imgproxy/v3/config" ) var ( enabled bool - headersReplacer = strings.NewReplacer("-", "_") + metaReplacer = strings.NewReplacer("-", "_", " ", "_") ) func Init() { @@ -24,15 +25,22 @@ func Init() { } } -func Report(err error, req *http.Request) { - if enabled { - headers := make(honeybadger.CGIData) - - for k, v := range req.Header { - key := "HTTP_" + headersReplacer.Replace(strings.ToUpper(k)) - headers[key] = v[0] - } - - honeybadger.Notify(err, req.URL, headers) +func Report(err error, req *http.Request, meta map[string]any) { + if !enabled { + return } + + extra := make(honeybadger.CGIData, len(req.Header)+len(meta)) + + for k, v := range req.Header { + key := "HTTP_" + metaReplacer.Replace(strings.ToUpper(k)) + extra[key] = v[0] + } + + for k, v := range meta { + key := metaReplacer.Replace(strings.ToUpper(k)) + extra[key] = v + } + + honeybadger.Notify(err, req.URL, extra) } diff --git a/errorreport/sentry/sentry.go b/errorreport/sentry/sentry.go index 3a16e2ef..6748740f 100644 --- a/errorreport/sentry/sentry.go +++ b/errorreport/sentry/sentry.go @@ -5,6 +5,7 @@ import ( "time" "github.com/getsentry/sentry-go" + "github.com/imgproxy/imgproxy/v3/config" ) @@ -26,14 +27,21 @@ func Init() { } } -func Report(err error, req *http.Request) { - if enabled { - hub := sentry.CurrentHub().Clone() - hub.Scope().SetRequest(req) - hub.Scope().SetLevel(sentry.LevelError) - eventID := hub.CaptureException(err) - if eventID != nil { - hub.Flush(timeout) - } +func Report(err error, req *http.Request, meta map[string]any) { + if !enabled { + return + } + + hub := sentry.CurrentHub().Clone() + hub.Scope().SetRequest(req) + hub.Scope().SetLevel(sentry.LevelError) + + if meta != nil { + hub.Scope().SetContext("Processing context", meta) + } + + eventID := hub.CaptureException(err) + if eventID != nil { + hub.Flush(timeout) } } diff --git a/processing_handler.go b/processing_handler.go index 07007e9d..410fbaad 100644 --- a/processing_handler.go +++ b/processing_handler.go @@ -241,6 +241,9 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) { po, imageURL, err := options.ParsePath(path, r.Header) checkErr(ctx, "path_parsing", err) + errorreport.SetMetadata(r, "Source Image URL", imageURL) + errorreport.SetMetadata(r, "Processing Options", po) + err = security.VerifySourceURL(imageURL) checkErr(ctx, "security", err) diff --git a/server.go b/server.go index 976aa7b4..742a4339 100644 --- a/server.go +++ b/server.go @@ -132,6 +132,9 @@ func withSecret(h router.RouteHandler) router.RouteHandler { func withPanicHandler(h router.RouteHandler) router.RouteHandler { return func(reqID string, rw http.ResponseWriter, r *http.Request) { + ctx := errorreport.StartRequest(r) + r = r.WithContext(ctx) + defer func() { if rerr := recover(); rerr != nil { if rerr == http.ErrAbortHandler {