errorreport.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package errorreport
  2. import (
  3. "context"
  4. "net/http"
  5. "github.com/imgproxy/imgproxy/v3/errorreport/airbrake"
  6. "github.com/imgproxy/imgproxy/v3/errorreport/bugsnag"
  7. "github.com/imgproxy/imgproxy/v3/errorreport/honeybadger"
  8. "github.com/imgproxy/imgproxy/v3/errorreport/sentry"
  9. )
  10. // reporter is an interface that all error reporters must implement.
  11. // most of our reporters are singletons, so in most cases close is noop.
  12. type reporter interface {
  13. Report(err error, req *http.Request, meta map[string]any)
  14. Close()
  15. }
  16. // metaCtxKey is the context.Context key for request metadata
  17. type metaCtxKey struct{}
  18. // initialized reporters
  19. var reporters []reporter
  20. // Init initializes all configured error reporters and returns a Reporter instance.
  21. func Init(config *Config) error {
  22. if err := config.Validate(); err != nil {
  23. return err
  24. }
  25. reporters = make([]reporter, 0)
  26. if r, err := bugsnag.New(&config.Bugsnag); err != nil {
  27. return err
  28. } else if r != nil {
  29. reporters = append(reporters, r)
  30. }
  31. if r, err := honeybadger.New(&config.Honeybadger); err != nil {
  32. return err
  33. } else if r != nil {
  34. reporters = append(reporters, r)
  35. }
  36. if r, err := sentry.New(&config.Sentry); err != nil {
  37. return err
  38. } else if r != nil {
  39. reporters = append(reporters, r)
  40. }
  41. if r, err := airbrake.New(&config.Airbrake); err != nil {
  42. return err
  43. } else if r != nil {
  44. reporters = append(reporters, r)
  45. }
  46. return nil
  47. }
  48. // StartRequest initializes metadata storage in the request context.
  49. func StartRequest(req *http.Request) context.Context {
  50. meta := make(map[string]any)
  51. return context.WithValue(req.Context(), metaCtxKey{}, meta)
  52. }
  53. // SetMetadata sets a metadata key-value pair in the request context.
  54. func SetMetadata(req *http.Request, key string, value any) {
  55. meta, ok := req.Context().Value(metaCtxKey{}).(map[string]any)
  56. if !ok || meta == nil {
  57. return
  58. }
  59. meta[key] = value
  60. }
  61. // Report reports an error to all configured reporters with the request and its metadata.
  62. func Report(err error, req *http.Request) {
  63. meta, ok := req.Context().Value(metaCtxKey{}).(map[string]any)
  64. if !ok {
  65. meta = nil
  66. }
  67. for _, reporter := range reporters {
  68. reporter.Report(err, req, meta)
  69. }
  70. }
  71. // Close closes all reporters
  72. func Close() {
  73. for _, reporter := range reporters {
  74. reporter.Close()
  75. }
  76. }