notifier.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package bugsnag
  2. import (
  3. "fmt"
  4. "github.com/bugsnag/bugsnag-go/errors"
  5. )
  6. // Notifier sends errors to Bugsnag.
  7. type Notifier struct {
  8. Config *Configuration
  9. RawData []interface{}
  10. }
  11. // New creates a new notifier.
  12. // You can pass an instance of bugsnag.Configuration in rawData to change the configuration.
  13. // Other values of rawData will be passed to Notify.
  14. func New(rawData ...interface{}) *Notifier {
  15. config := Config.clone()
  16. for i, datum := range rawData {
  17. if c, ok := datum.(Configuration); ok {
  18. config.update(&c)
  19. rawData[i] = nil
  20. }
  21. }
  22. return &Notifier{
  23. Config: config,
  24. RawData: rawData,
  25. }
  26. }
  27. // Notify sends an error to Bugsnag. Any rawData you pass here will be sent to
  28. // Bugsnag after being converted to JSON. e.g. bugsnag.SeverityError, bugsnag.Context,
  29. // or bugsnag.MetaData.
  30. func (notifier *Notifier) Notify(err error, rawData ...interface{}) (e error) {
  31. config := notifier.Config
  32. return notifier.NotifySync(err, config.Synchronous, rawData...)
  33. }
  34. // NotifySync sends an error to Bugsnag. The synchronous parameter specifies
  35. // whether to send the report in the current context. Any rawData you pass here
  36. // will be sent to Bugsnag after being converted to JSON. e.g.
  37. // bugsnag.SeverityError, bugsnag.Context, or bugsnag.MetaData.
  38. func (notifier *Notifier) NotifySync(err error, synchronous bool, rawData ...interface{}) (e error) {
  39. event, config := newEvent(errors.New(err, 1), rawData, notifier)
  40. // Never block, start throwing away errors if we have too many.
  41. e = middleware.Run(event, config, func() error {
  42. config.logf("notifying bugsnag: %s", event.Message)
  43. if config.notifyInReleaseStage() {
  44. if synchronous {
  45. return (&payload{event, config}).deliver()
  46. }
  47. // Ensure that any errors are logged if they occur in a goroutine.
  48. go func(event *Event, config *Configuration) {
  49. err := (&payload{event, config}).deliver()
  50. if err != nil {
  51. config.logf("bugsnag.Notify: %v", err)
  52. }
  53. }(event, config)
  54. return nil
  55. }
  56. return fmt.Errorf("not notifying in %s", config.ReleaseStage)
  57. })
  58. if e != nil {
  59. config.logf("bugsnag.Notify: %v", e)
  60. }
  61. return e
  62. }
  63. // AutoNotify notifies Bugsnag of any panics, then repanics.
  64. // It sends along any rawData that gets passed in.
  65. // Usage:
  66. // go func() {
  67. // defer AutoNotify()
  68. // // (possibly crashy code)
  69. // }()
  70. func (notifier *Notifier) AutoNotify(rawData ...interface{}) {
  71. if err := recover(); err != nil {
  72. severity := notifier.getDefaultSeverity(rawData, SeverityError)
  73. state := HandledState{SeverityReasonHandledPanic, severity, true, ""}
  74. notifier.appendStateIfNeeded(rawData, state)
  75. notifier.Notify(errors.New(err, 2), rawData...)
  76. panic(err)
  77. }
  78. }
  79. // Recover logs any panics, then recovers.
  80. // It sends along any rawData that gets passed in.
  81. // Usage: defer Recover()
  82. func (notifier *Notifier) Recover(rawData ...interface{}) {
  83. if err := recover(); err != nil {
  84. severity := notifier.getDefaultSeverity(rawData, SeverityWarning)
  85. state := HandledState{SeverityReasonHandledPanic, severity, false, ""}
  86. notifier.appendStateIfNeeded(rawData, state)
  87. notifier.Notify(errors.New(err, 2), rawData...)
  88. }
  89. }
  90. func (notifier *Notifier) dontPanic() {
  91. if err := recover(); err != nil {
  92. notifier.Config.logf("bugsnag/notifier.Notify: panic! %s", err)
  93. }
  94. }
  95. // Get defined severity from raw data or a fallback value
  96. func (notifier *Notifier) getDefaultSeverity(rawData []interface{}, s severity) severity {
  97. allData := append(notifier.RawData, rawData...)
  98. for _, datum := range allData {
  99. if _, ok := datum.(severity); ok {
  100. return datum.(severity)
  101. }
  102. }
  103. for _, datum := range allData {
  104. if _, ok := datum.(HandledState); ok {
  105. return datum.(HandledState).OriginalSeverity
  106. }
  107. }
  108. return s
  109. }
  110. func (notifier *Notifier) appendStateIfNeeded(rawData []interface{}, h HandledState) []interface{} {
  111. for _, datum := range append(notifier.RawData, rawData...) {
  112. if _, ok := datum.(HandledState); ok {
  113. return rawData
  114. }
  115. }
  116. return append(rawData, h)
  117. }