1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-12-23 22:11:10 +02:00
Files
imgproxy/errorreport/errorreport.go
Sergei Aleksandrovich e33254005d Refactored errors (#1578)
* Refactored errors

* Make monitoring and errorreport accept `errctx.Error` instead of `error`

* Add server.Error; Remove category from errctx; Make HTTP handlers respond with *server.Error

* Remove stackSkip from errctx.Wrap; Add errctx.WrapWithStackSkip
2025-11-20 01:26:21 +06:00

100 lines
2.4 KiB
Go

package errorreport
import (
"context"
"net/http"
"github.com/imgproxy/imgproxy/v3/errctx"
"github.com/imgproxy/imgproxy/v3/errorreport/airbrake"
"github.com/imgproxy/imgproxy/v3/errorreport/bugsnag"
"github.com/imgproxy/imgproxy/v3/errorreport/honeybadger"
"github.com/imgproxy/imgproxy/v3/errorreport/sentry"
)
// reporter is an interface that all error reporters must implement.
// most of our reporters are singletons, so in most cases close is noop.
type reporter interface {
Report(err errctx.Error, req *http.Request, meta map[string]any)
Close()
}
// metaCtxKey is the context.Context key for request metadata
type metaCtxKey struct{}
type Reporter struct {
// initialized reporters
reporters []reporter
}
// Init initializes all configured error reporters and returns a Reporter instance.
func New(config *Config) (*Reporter, error) {
if err := config.Validate(); err != nil {
return nil, err
}
reporters := make([]reporter, 0)
if r, err := bugsnag.New(&config.Bugsnag); err != nil {
return nil, err
} else if r != nil {
reporters = append(reporters, r)
}
if r, err := honeybadger.New(&config.Honeybadger); err != nil {
return nil, err
} else if r != nil {
reporters = append(reporters, r)
}
if r, err := sentry.New(&config.Sentry); err != nil {
return nil, err
} else if r != nil {
reporters = append(reporters, r)
}
if r, err := airbrake.New(&config.Airbrake); err != nil {
return nil, err
} else if r != nil {
reporters = append(reporters, r)
}
return &Reporter{
reporters: reporters,
}, nil
}
// StartRequest initializes metadata storage in the request context.
func StartRequest(req *http.Request) context.Context {
meta := make(map[string]any)
return context.WithValue(req.Context(), metaCtxKey{}, meta)
}
// SetMetadata sets a metadata key-value pair in the request context.
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
}
// Report reports an error to all configured reporters with the request and its metadata.
func (r *Reporter) Report(err errctx.Error, req *http.Request) {
meta, ok := req.Context().Value(metaCtxKey{}).(map[string]any)
if !ok {
meta = nil
}
for _, reporter := range r.reporters {
reporter.Report(err, req, meta)
}
}
// Close closes all reporters
func (r *Reporter) Close() {
for _, reporter := range r.reporters {
reporter.Close()
}
}