scope.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. package sentry
  2. import (
  3. "reflect"
  4. "sync"
  5. "time"
  6. )
  7. // Scope holds contextual data for the current scope.
  8. //
  9. // The scope is an object that can cloned efficiently and stores data that
  10. // is locally relevant to an event. For instance the scope will hold recorded
  11. // breadcrumbs and similar information.
  12. //
  13. // The scope can be interacted with in two ways:
  14. //
  15. // 1. the scope is routinely updated with information by functions such as
  16. // `AddBreadcrumb` which will modify the currently top-most scope.
  17. // 2. the topmost scope can also be configured through the `ConfigureScope`
  18. // method.
  19. //
  20. // Note that the scope can only be modified but not inspected.
  21. // Only the client can use the scope to extract information currently.
  22. type Scope struct {
  23. sync.RWMutex
  24. breadcrumbs []*Breadcrumb
  25. user User
  26. tags map[string]string
  27. contexts map[string]interface{}
  28. extra map[string]interface{}
  29. fingerprint []string
  30. level Level
  31. transaction string
  32. request Request
  33. eventProcessors []EventProcessor
  34. }
  35. func NewScope() *Scope {
  36. scope := Scope{
  37. breadcrumbs: make([]*Breadcrumb, 0),
  38. tags: make(map[string]string),
  39. contexts: make(map[string]interface{}),
  40. extra: make(map[string]interface{}),
  41. fingerprint: make([]string, 0),
  42. }
  43. return &scope
  44. }
  45. // AddBreadcrumb adds new breadcrumb to the current scope
  46. // and optionaly throws the old one if limit is reached.
  47. func (scope *Scope) AddBreadcrumb(breadcrumb *Breadcrumb, limit int) {
  48. if breadcrumb.Timestamp == 0 {
  49. breadcrumb.Timestamp = time.Now().Unix()
  50. }
  51. scope.Lock()
  52. defer scope.Unlock()
  53. breadcrumbs := append(scope.breadcrumbs, breadcrumb)
  54. if len(breadcrumbs) > limit {
  55. scope.breadcrumbs = breadcrumbs[1 : limit+1]
  56. } else {
  57. scope.breadcrumbs = breadcrumbs
  58. }
  59. }
  60. // ClearBreadcrumbs clears all breadcrumbs from the current scope.
  61. func (scope *Scope) ClearBreadcrumbs() {
  62. scope.breadcrumbs = []*Breadcrumb{}
  63. }
  64. // SetUser sets new user for the current scope.
  65. func (scope *Scope) SetUser(user User) {
  66. scope.user = user
  67. }
  68. // SetRequest sets new user for the current scope.
  69. func (scope *Scope) SetRequest(request Request) {
  70. scope.request = request
  71. }
  72. // SetTag adds a tag to the current scope.
  73. func (scope *Scope) SetTag(key, value string) {
  74. scope.Lock()
  75. defer scope.Unlock()
  76. scope.tags[key] = value
  77. }
  78. // SetTags assigns multiple tags to the current scope.
  79. func (scope *Scope) SetTags(tags map[string]string) {
  80. scope.Lock()
  81. defer scope.Unlock()
  82. for k, v := range tags {
  83. scope.tags[k] = v
  84. }
  85. }
  86. // RemoveTag removes a tag from the current scope.
  87. func (scope *Scope) RemoveTag(key string) {
  88. scope.Lock()
  89. defer scope.Unlock()
  90. delete(scope.tags, key)
  91. }
  92. // SetContext adds a context to the current scope.
  93. func (scope *Scope) SetContext(key string, value interface{}) {
  94. scope.Lock()
  95. defer scope.Unlock()
  96. scope.contexts[key] = value
  97. }
  98. // SetContexts assigns multiple contexts to the current scope.
  99. func (scope *Scope) SetContexts(contexts map[string]interface{}) {
  100. scope.Lock()
  101. defer scope.Unlock()
  102. for k, v := range contexts {
  103. scope.contexts[k] = v
  104. }
  105. }
  106. // RemoveContext removes a context from the current scope.
  107. func (scope *Scope) RemoveContext(key string) {
  108. scope.Lock()
  109. defer scope.Unlock()
  110. delete(scope.contexts, key)
  111. }
  112. // SetExtra adds an extra to the current scope.
  113. func (scope *Scope) SetExtra(key string, value interface{}) {
  114. scope.Lock()
  115. defer scope.Unlock()
  116. scope.extra[key] = value
  117. }
  118. // SetExtras assigns multiple extras to the current scope.
  119. func (scope *Scope) SetExtras(extra map[string]interface{}) {
  120. scope.Lock()
  121. defer scope.Unlock()
  122. for k, v := range extra {
  123. scope.extra[k] = v
  124. }
  125. }
  126. // RemoveExtra removes a extra from the current scope.
  127. func (scope *Scope) RemoveExtra(key string) {
  128. scope.Lock()
  129. defer scope.Unlock()
  130. delete(scope.extra, key)
  131. }
  132. // SetFingerprint sets new fingerprint for the current scope.
  133. func (scope *Scope) SetFingerprint(fingerprint []string) {
  134. scope.fingerprint = fingerprint
  135. }
  136. // SetLevel sets new level for the current scope.
  137. func (scope *Scope) SetLevel(level Level) {
  138. scope.level = level
  139. }
  140. // SetTransaction sets new transaction name for the current transaction.
  141. func (scope *Scope) SetTransaction(transactionName string) {
  142. scope.transaction = transactionName
  143. }
  144. // Clone returns a copy of the current scope with all data copied over.
  145. func (scope *Scope) Clone() *Scope {
  146. scope.RLock()
  147. defer scope.RUnlock()
  148. clone := NewScope()
  149. clone.user = scope.user
  150. clone.breadcrumbs = make([]*Breadcrumb, len(scope.breadcrumbs))
  151. copy(clone.breadcrumbs, scope.breadcrumbs)
  152. for key, value := range scope.tags {
  153. clone.tags[key] = value
  154. }
  155. for key, value := range scope.contexts {
  156. clone.contexts[key] = value
  157. }
  158. for key, value := range scope.extra {
  159. clone.extra[key] = value
  160. }
  161. clone.fingerprint = make([]string, len(scope.fingerprint))
  162. copy(clone.fingerprint, scope.fingerprint)
  163. clone.level = scope.level
  164. clone.transaction = scope.transaction
  165. clone.request = scope.request
  166. return clone
  167. }
  168. // Clear removed the data from the current scope.
  169. func (scope *Scope) Clear() {
  170. *scope = *NewScope()
  171. }
  172. // AddEventProcessor adds an event processor to the current scope.
  173. func (scope *Scope) AddEventProcessor(processor EventProcessor) {
  174. scope.Lock()
  175. defer scope.Unlock()
  176. scope.eventProcessors = append(scope.eventProcessors, processor)
  177. }
  178. // ApplyToEvent takes the data from the current scope and attaches it to the event.
  179. func (scope *Scope) ApplyToEvent(event *Event, hint *EventHint) *Event {
  180. scope.RLock()
  181. defer scope.RUnlock()
  182. if len(scope.breadcrumbs) > 0 {
  183. if event.Breadcrumbs == nil {
  184. event.Breadcrumbs = []*Breadcrumb{}
  185. }
  186. event.Breadcrumbs = append(event.Breadcrumbs, scope.breadcrumbs...)
  187. }
  188. if len(scope.tags) > 0 {
  189. if event.Tags == nil {
  190. event.Tags = make(map[string]string)
  191. }
  192. for key, value := range scope.tags {
  193. event.Tags[key] = value
  194. }
  195. }
  196. if len(scope.contexts) > 0 {
  197. if event.Contexts == nil {
  198. event.Contexts = make(map[string]interface{})
  199. }
  200. for key, value := range scope.contexts {
  201. event.Contexts[key] = value
  202. }
  203. }
  204. if len(scope.extra) > 0 {
  205. if event.Extra == nil {
  206. event.Extra = make(map[string]interface{})
  207. }
  208. for key, value := range scope.extra {
  209. event.Extra[key] = value
  210. }
  211. }
  212. if (reflect.DeepEqual(event.User, User{})) {
  213. event.User = scope.user
  214. }
  215. if (event.Fingerprint == nil || len(event.Fingerprint) == 0) &&
  216. len(scope.fingerprint) > 0 {
  217. event.Fingerprint = make([]string, len(scope.fingerprint))
  218. copy(event.Fingerprint, scope.fingerprint)
  219. }
  220. if scope.level != "" {
  221. event.Level = scope.level
  222. }
  223. if scope.transaction != "" {
  224. event.Transaction = scope.transaction
  225. }
  226. if (reflect.DeepEqual(event.Request, Request{})) {
  227. event.Request = scope.request
  228. }
  229. for _, processor := range scope.eventProcessors {
  230. id := event.EventID
  231. event = processor(event, hint)
  232. if event == nil {
  233. Logger.Printf("Event dropped by one of the Scope EventProcessors: %s\n", id)
  234. return nil
  235. }
  236. }
  237. return event
  238. }