event.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package bugsnag
  2. import (
  3. "strings"
  4. "github.com/bugsnag/bugsnag-go/errors"
  5. )
  6. // Context is the context of the error in Bugsnag.
  7. // This can be passed to Notify, Recover or AutoNotify as rawData.
  8. type Context struct {
  9. String string
  10. }
  11. // User represents the searchable user-data on Bugsnag. The Id is also used
  12. // to determine the number of users affected by a bug. This can be
  13. // passed to Notify, Recover or AutoNotify as rawData.
  14. type User struct {
  15. Id string `json:"id,omitempty"`
  16. Name string `json:"name,omitempty"`
  17. Email string `json:"email,omitempty"`
  18. }
  19. // ErrorClass overrides the error class in Bugsnag.
  20. // This struct enables you to group errors as you like.
  21. type ErrorClass struct {
  22. Name string
  23. }
  24. // Sets the severity of the error on Bugsnag. These values can be
  25. // passed to Notify, Recover or AutoNotify as rawData.
  26. var (
  27. SeverityError = severity{"error"}
  28. SeverityWarning = severity{"warning"}
  29. SeverityInfo = severity{"info"}
  30. )
  31. // The severity tag type, private so that people can only use Error,Warning,Info
  32. type severity struct {
  33. String string
  34. }
  35. // The form of stacktrace that Bugsnag expects
  36. type stackFrame struct {
  37. Method string `json:"method"`
  38. File string `json:"file"`
  39. LineNumber int `json:"lineNumber"`
  40. InProject bool `json:"inProject,omitempty"`
  41. }
  42. type SeverityReason string
  43. const (
  44. SeverityReasonCallbackSpecified SeverityReason = "userCallbackSetSeverity"
  45. SeverityReasonHandledError = "handledError"
  46. SeverityReasonHandledPanic = "handledPanic"
  47. SeverityReasonUnhandledError = "unhandledError"
  48. SeverityReasonUnhandledMiddlewareError = "unhandledErrorMiddleware"
  49. SeverityReasonUnhandledPanic = "unhandledPanic"
  50. SeverityReasonUserSpecified = "userSpecifiedSeverity"
  51. )
  52. type HandledState struct {
  53. SeverityReason SeverityReason
  54. OriginalSeverity severity
  55. Unhandled bool
  56. Framework string
  57. }
  58. // Event represents a payload of data that gets sent to Bugsnag.
  59. // This is passed to each OnBeforeNotify hook.
  60. type Event struct {
  61. // The original error that caused this event, not sent to Bugsnag.
  62. Error *errors.Error
  63. // The rawData affecting this error, not sent to Bugsnag.
  64. RawData []interface{}
  65. // The error class to be sent to Bugsnag. This defaults to the type name of the Error, for
  66. // example *error.String
  67. ErrorClass string
  68. // The error message to be sent to Bugsnag. This defaults to the return value of Error.Error()
  69. Message string
  70. // The stacktrrace of the error to be sent to Bugsnag.
  71. Stacktrace []stackFrame
  72. // The context to be sent to Bugsnag. This should be set to the part of the app that was running,
  73. // e.g. for http requests, set it to the path.
  74. Context string
  75. // The severity of the error. Can be SeverityError, SeverityWarning or SeverityInfo.
  76. Severity severity
  77. // The grouping hash is used to override Bugsnag's grouping. Set this if you'd like all errors with
  78. // the same grouping hash to group together in the dashboard.
  79. GroupingHash string
  80. // User data to send to Bugsnag. This is searchable on the dashboard.
  81. User *User
  82. // Other MetaData to send to Bugsnag. Appears as a set of tabbed tables in the dashboard.
  83. MetaData MetaData
  84. // The reason for the severity and original value
  85. handledState HandledState
  86. }
  87. func newEvent(err *errors.Error, rawData []interface{}, notifier *Notifier) (*Event, *Configuration) {
  88. config := notifier.Config
  89. event := &Event{
  90. Error: err,
  91. RawData: append(notifier.RawData, rawData...),
  92. ErrorClass: err.TypeName(),
  93. Message: err.Error(),
  94. Stacktrace: make([]stackFrame, len(err.StackFrames())),
  95. Severity: SeverityWarning,
  96. MetaData: make(MetaData),
  97. handledState: HandledState{
  98. SeverityReasonHandledError,
  99. SeverityWarning,
  100. false,
  101. "",
  102. },
  103. }
  104. for _, datum := range event.RawData {
  105. switch datum := datum.(type) {
  106. case severity:
  107. event.Severity = datum
  108. event.handledState.OriginalSeverity = datum
  109. event.handledState.SeverityReason = SeverityReasonUserSpecified
  110. case Context:
  111. event.Context = datum.String
  112. case Configuration:
  113. config = config.merge(&datum)
  114. case MetaData:
  115. event.MetaData.Update(datum)
  116. case User:
  117. event.User = &datum
  118. case ErrorClass:
  119. event.ErrorClass = datum.Name
  120. case HandledState:
  121. event.handledState = datum
  122. event.Severity = datum.OriginalSeverity
  123. }
  124. }
  125. for i, frame := range err.StackFrames() {
  126. file := frame.File
  127. inProject := config.isProjectPackage(frame.Package)
  128. // remove $GOROOT and $GOHOME from other frames
  129. if idx := strings.Index(file, frame.Package); idx > -1 {
  130. file = file[idx:]
  131. }
  132. if inProject {
  133. file = config.stripProjectPackages(file)
  134. }
  135. event.Stacktrace[i] = stackFrame{
  136. Method: frame.Name,
  137. File: file,
  138. LineNumber: frame.LineNumber,
  139. InProject: inProject,
  140. }
  141. }
  142. return event, config
  143. }