sentry-ruby-core 4.4.0 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile +9 -5
  5. data/LICENSE.txt +1 -1
  6. data/README.md +29 -175
  7. data/bin/console +5 -1
  8. data/lib/sentry/background_worker.rb +33 -3
  9. data/lib/sentry/backtrace.rb +1 -3
  10. data/lib/sentry/breadcrumb/sentry_logger.rb +3 -1
  11. data/lib/sentry/breadcrumb.rb +28 -2
  12. data/lib/sentry/breadcrumb_buffer.rb +16 -0
  13. data/lib/sentry/client.rb +66 -7
  14. data/lib/sentry/configuration.rb +156 -112
  15. data/lib/sentry/core_ext/object/deep_dup.rb +4 -0
  16. data/lib/sentry/core_ext/object/duplicable.rb +2 -0
  17. data/lib/sentry/dsn.rb +6 -1
  18. data/lib/sentry/envelope.rb +49 -0
  19. data/lib/sentry/event.rb +65 -23
  20. data/lib/sentry/exceptions.rb +2 -0
  21. data/lib/sentry/hub.rb +37 -6
  22. data/lib/sentry/integrable.rb +2 -0
  23. data/lib/sentry/interface.rb +3 -10
  24. data/lib/sentry/interfaces/exception.rb +13 -3
  25. data/lib/sentry/interfaces/request.rb +52 -21
  26. data/lib/sentry/interfaces/single_exception.rb +31 -0
  27. data/lib/sentry/interfaces/stacktrace.rb +14 -0
  28. data/lib/sentry/interfaces/stacktrace_builder.rb +39 -10
  29. data/lib/sentry/interfaces/threads.rb +12 -2
  30. data/lib/sentry/linecache.rb +3 -0
  31. data/lib/sentry/net/http.rb +79 -51
  32. data/lib/sentry/rack/capture_exceptions.rb +2 -0
  33. data/lib/sentry/rack.rb +2 -1
  34. data/lib/sentry/rake.rb +33 -9
  35. data/lib/sentry/redis.rb +88 -0
  36. data/lib/sentry/release_detector.rb +39 -0
  37. data/lib/sentry/scope.rb +76 -6
  38. data/lib/sentry/span.rb +84 -8
  39. data/lib/sentry/transaction.rb +50 -13
  40. data/lib/sentry/transaction_event.rb +19 -6
  41. data/lib/sentry/transport/configuration.rb +4 -2
  42. data/lib/sentry/transport/dummy_transport.rb +2 -0
  43. data/lib/sentry/transport/http_transport.rb +55 -42
  44. data/lib/sentry/transport.rb +101 -32
  45. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  46. data/lib/sentry/utils/custom_inspection.rb +14 -0
  47. data/lib/sentry/utils/exception_cause_chain.rb +10 -10
  48. data/lib/sentry/utils/logging_helper.rb +6 -4
  49. data/lib/sentry/utils/real_ip.rb +9 -1
  50. data/lib/sentry/utils/request_id.rb +2 -0
  51. data/lib/sentry/version.rb +3 -1
  52. data/lib/sentry-ruby.rb +247 -47
  53. data/sentry-ruby-core.gemspec +2 -3
  54. data/sentry-ruby.gemspec +2 -3
  55. metadata +10 -22
  56. data/.craft.yml +0 -29
  57. data/lib/sentry/benchmarks/benchmark_transport.rb +0 -14
  58. data/lib/sentry/rack/deprecations.rb +0 -19
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class ThreadsInterface
5
+ # @param crashed [Boolean]
6
+ # @param stacktrace [Array]
3
7
  def initialize(crashed: false, stacktrace: nil)
4
8
  @id = Thread.current.object_id
5
9
  @name = Thread.current.name
@@ -8,6 +12,7 @@ module Sentry
8
12
  @stacktrace = stacktrace
9
13
  end
10
14
 
15
+ # @return [Hash]
11
16
  def to_hash
12
17
  {
13
18
  values: [
@@ -22,8 +27,13 @@ module Sentry
22
27
  }
23
28
  end
24
29
 
25
- # patch this method if you want to change a threads interface's stacktrace frames
26
- # also see `StacktraceBuilder.build`.
30
+ # Builds the ThreadsInterface with given backtrace and stacktrace_builder.
31
+ # Patch this method if you want to change a threads interface's stacktrace frames.
32
+ # @see StacktraceBuilder.build
33
+ # @param backtrace [Array]
34
+ # @param stacktrace_builder [StacktraceBuilder]
35
+ # @param crashed [Hash]
36
+ # @return [ThreadsInterface]
27
37
  def self.build(backtrace:, stacktrace_builder:, **options)
28
38
  stacktrace = stacktrace_builder.build(backtrace: backtrace) if backtrace
29
39
  new(**options, stacktrace: stacktrace)
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
4
+ # @api private
2
5
  class LineCache
3
6
  def initialize
4
7
  @cache = {}
@@ -1,87 +1,115 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "net/http"
2
4
 
3
5
  module Sentry
6
+ # @api private
4
7
  module Net
5
8
  module HTTP
6
- OP_NAME = "net.http"
9
+ OP_NAME = "http.client"
10
+ BREADCRUMB_CATEGORY = "net.http"
7
11
 
12
+ # To explain how the entire thing works, we need to know how the original Net::HTTP#request works
13
+ # Here's part of its definition. As you can see, it usually calls itself inside a #start block
14
+ #
15
+ # ```
16
+ # def request(req, body = nil, &block)
17
+ # unless started?
18
+ # start {
19
+ # req['connection'] ||= 'close'
20
+ # return request(req, body, &block) # <- request will be called for the second time from the first call
21
+ # }
22
+ # end
23
+ # # .....
24
+ # end
25
+ # ```
26
+ #
27
+ # So we're only instrumenting request when `Net::HTTP` is already started
8
28
  def request(req, body = nil, &block)
29
+ return super unless started?
30
+
31
+ sentry_span = start_sentry_span
32
+ set_sentry_trace_header(req, sentry_span)
33
+
9
34
  super.tap do |res|
10
35
  record_sentry_breadcrumb(req, res)
11
- record_sentry_span(req, res)
36
+ record_sentry_span(req, res, sentry_span)
12
37
  end
13
38
  end
14
39
 
15
- def do_start
16
- super.tap do
17
- start_sentry_span
18
- end
19
- end
40
+ private
20
41
 
21
- def do_finish
22
- super.tap do
23
- finish_sentry_span
24
- end
25
- end
42
+ def set_sentry_trace_header(req, sentry_span)
43
+ return unless sentry_span
26
44
 
27
- private
45
+ trace = Sentry.get_current_client.generate_sentry_trace(sentry_span)
46
+ req[SENTRY_TRACE_HEADER_NAME] = trace if trace
47
+ end
28
48
 
29
49
  def record_sentry_breadcrumb(req, res)
30
- if Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
31
- return if from_sentry_sdk?
32
-
33
- request_info = extract_request_info(req)
34
- crumb = Sentry::Breadcrumb.new(
35
- level: :info,
36
- category: OP_NAME,
37
- type: :info,
38
- data: {
39
- method: request_info[:method],
40
- url: request_info[:url],
41
- status: res.code.to_i
42
- }
43
- )
44
- Sentry.add_breadcrumb(crumb)
45
- end
50
+ return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
51
+ return if from_sentry_sdk?
52
+
53
+ request_info = extract_request_info(req)
54
+
55
+ crumb = Sentry::Breadcrumb.new(
56
+ level: :info,
57
+ category: BREADCRUMB_CATEGORY,
58
+ type: :info,
59
+ data: {
60
+ status: res.code.to_i,
61
+ **request_info
62
+ }
63
+ )
64
+ Sentry.add_breadcrumb(crumb)
46
65
  end
47
66
 
48
- def record_sentry_span(req, res)
49
- if Sentry.initialized? && @sentry_span
50
- request_info = extract_request_info(req)
51
- @sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
52
- @sentry_span.set_data(:status, res.code.to_i)
53
- end
67
+ def record_sentry_span(req, res, sentry_span)
68
+ return unless Sentry.initialized? && sentry_span
69
+
70
+ request_info = extract_request_info(req)
71
+ sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
72
+ sentry_span.set_data(:status, res.code.to_i)
73
+ finish_sentry_span(sentry_span)
54
74
  end
55
75
 
56
76
  def start_sentry_span
57
- if Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
58
- return if from_sentry_sdk?
59
- return if transaction.sampled == false
77
+ return unless Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
78
+ return if from_sentry_sdk?
79
+ return if transaction.sampled == false
60
80
 
61
- child_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
62
- @sentry_span = child_span
63
- end
81
+ transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
64
82
  end
65
83
 
66
- def finish_sentry_span
67
- if Sentry.initialized? && @sentry_span
68
- @sentry_span.set_timestamp(Sentry.utc_now.to_f)
69
- @sentry_span = nil
70
- end
84
+ def finish_sentry_span(sentry_span)
85
+ return unless Sentry.initialized? && sentry_span
86
+
87
+ sentry_span.set_timestamp(Sentry.utc_now.to_f)
71
88
  end
72
89
 
73
90
  def from_sentry_sdk?
74
- dsn_host = Sentry.configuration.dsn.host
75
- dsn_host == self.address
91
+ dsn = Sentry.configuration.dsn
92
+ dsn && dsn.host == self.address
76
93
  end
77
94
 
78
95
  def extract_request_info(req)
79
- uri = req.uri
96
+ uri = req.uri || URI.parse("#{use_ssl? ? 'https' : 'http'}://#{address}#{req.path}")
80
97
  url = "#{uri.scheme}://#{uri.host}#{uri.path}" rescue uri.to_s
81
- { method: req.method, url: url }
98
+
99
+ result = { method: req.method, url: url }
100
+
101
+ if Sentry.configuration.send_default_pii
102
+ result[:url] = result[:url] + "?#{uri.query}"
103
+ result[:body] = req.body
104
+ end
105
+
106
+ result
82
107
  end
83
108
  end
84
109
  end
85
110
  end
86
111
 
87
- Net::HTTP.send(:prepend, Sentry::Net::HTTP)
112
+ Sentry.register_patch do
113
+ patch = Sentry::Net::HTTP
114
+ Net::HTTP.send(:prepend, patch) unless Net::HTTP.ancestors.include?(patch)
115
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Rack
3
5
  class CaptureExceptions
data/lib/sentry/rack.rb CHANGED
@@ -1,4 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack'
2
4
 
3
5
  require 'sentry/rack/capture_exceptions'
4
- require 'sentry/rack/deprecations'
data/lib/sentry/rake.rb CHANGED
@@ -1,17 +1,41 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rake"
2
4
  require "rake/task"
3
5
 
6
+ module Sentry
7
+ module Rake
8
+ module Application
9
+ # @api private
10
+ def display_error_message(ex)
11
+ Sentry.capture_exception(ex) do |scope|
12
+ task_name = top_level_tasks.join(' ')
13
+ scope.set_transaction_name(task_name)
14
+ scope.set_tag("rake_task", task_name)
15
+ end if Sentry.initialized? && !Sentry.configuration.skip_rake_integration
16
+
17
+ super
18
+ end
19
+ end
20
+
21
+ module Task
22
+ # @api private
23
+ def execute(args=nil)
24
+ return super unless Sentry.initialized? && Sentry.get_current_hub
25
+
26
+ super
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ # @api private
4
33
  module Rake
5
34
  class Application
6
- alias orig_display_error_messsage display_error_message
7
- def display_error_message(ex)
8
- Sentry.capture_exception(ex, hint: { background: false }) do |scope|
9
- task_name = top_level_tasks.join(' ')
10
- scope.set_transaction_name(task_name)
11
- scope.set_tag("rake_task", task_name)
12
- end if Sentry.initialized?
35
+ prepend(Sentry::Rake::Application)
36
+ end
13
37
 
14
- orig_display_error_messsage(ex)
15
- end
38
+ class Task
39
+ prepend(Sentry::Rake::Task)
16
40
  end
17
41
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # @api private
5
+ class Redis
6
+ OP_NAME ||= "db.redis.command"
7
+ LOGGER_NAME ||= :redis_logger
8
+
9
+ def initialize(commands, host, port, db)
10
+ @commands, @host, @port, @db = commands, host, port, db
11
+ end
12
+
13
+ def instrument
14
+ return yield unless Sentry.initialized?
15
+
16
+ record_span do
17
+ yield.tap do
18
+ record_breadcrumb
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :commands, :host, :port, :db
26
+
27
+ def record_span
28
+ return yield unless (transaction = Sentry.get_current_scope.get_transaction) && transaction.sampled
29
+
30
+ sentry_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
31
+
32
+ yield.tap do
33
+ sentry_span.set_description(commands_description)
34
+ sentry_span.set_data(:server, server_description)
35
+ sentry_span.set_timestamp(Sentry.utc_now.to_f)
36
+ end
37
+ end
38
+
39
+ def record_breadcrumb
40
+ return unless Sentry.configuration.breadcrumbs_logger.include?(LOGGER_NAME)
41
+
42
+ Sentry.add_breadcrumb(
43
+ Sentry::Breadcrumb.new(
44
+ level: :info,
45
+ category: OP_NAME,
46
+ type: :info,
47
+ data: {
48
+ commands: parsed_commands,
49
+ server: server_description
50
+ }
51
+ )
52
+ )
53
+ end
54
+
55
+ def commands_description
56
+ parsed_commands.map do |statement|
57
+ statement.values.join(" ").strip
58
+ end.join(", ")
59
+ end
60
+
61
+ def parsed_commands
62
+ commands.map do |statement|
63
+ command, key, *_values = statement
64
+
65
+ { command: command.to_s.upcase, key: key }
66
+ end
67
+ end
68
+
69
+ def server_description
70
+ "#{host}:#{port}/#{db}"
71
+ end
72
+
73
+ module Client
74
+ def logging(commands, &block)
75
+ Sentry::Redis.new(commands, host, port, db).instrument do
76
+ super
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ if defined?(::Redis::Client)
84
+ Sentry.register_patch do
85
+ patch = Sentry::Redis::Client
86
+ Redis::Client.prepend(patch) unless Redis::Client.ancestors.include?(patch)
87
+ end
88
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # @api private
5
+ class ReleaseDetector
6
+ class << self
7
+ def detect_release(project_root:, running_on_heroku:)
8
+ detect_release_from_env ||
9
+ detect_release_from_git ||
10
+ detect_release_from_capistrano(project_root) ||
11
+ detect_release_from_heroku(running_on_heroku)
12
+ end
13
+
14
+ def detect_release_from_heroku(running_on_heroku)
15
+ return unless running_on_heroku
16
+ ENV['HEROKU_SLUG_COMMIT']
17
+ end
18
+
19
+ def detect_release_from_capistrano(project_root)
20
+ revision_file = File.join(project_root, 'REVISION')
21
+ revision_log = File.join(project_root, '..', 'revisions.log')
22
+
23
+ if File.exist?(revision_file)
24
+ File.read(revision_file).strip
25
+ elsif File.exist?(revision_log)
26
+ File.open(revision_log).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
27
+ end
28
+ end
29
+
30
+ def detect_release_from_git
31
+ Sentry.sys_command("git rev-parse --short HEAD") if File.directory?(".git")
32
+ end
33
+
34
+ def detect_release_from_env
35
+ ENV['SENTRY_RELEASE']
36
+ end
37
+ end
38
+ end
39
+ end
data/lib/sentry/scope.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "sentry/breadcrumb_buffer"
2
4
  require "etc"
3
5
 
@@ -9,20 +11,28 @@ module Sentry
9
11
 
10
12
  attr_reader(*ATTRIBUTES)
11
13
 
14
+ # @param max_breadcrumbs [Integer] the maximum number of breadcrumbs to be stored in the scope.
12
15
  def initialize(max_breadcrumbs: nil)
13
16
  @max_breadcrumbs = max_breadcrumbs
14
17
  set_default_value
15
18
  end
16
19
 
20
+ # Resets the scope's attributes to defaults.
21
+ # @return [void]
17
22
  def clear
18
23
  set_default_value
19
24
  end
20
25
 
26
+ # Applies stored attributes and event processors to the given event.
27
+ # @param event [Event]
28
+ # @param hint [Hash] the hint data that'll be passed to event processors.
29
+ # @return [Event]
21
30
  def apply_to_event(event, hint = nil)
22
31
  event.tags = tags.merge(event.tags)
23
32
  event.user = user.merge(event.user)
24
33
  event.extra = extra.merge(event.extra)
25
34
  event.contexts = contexts.merge(event.contexts)
35
+ event.transaction = transaction_name if transaction_name
26
36
 
27
37
  if span
28
38
  event.contexts[:trace] = span.get_trace_context
@@ -30,7 +40,6 @@ module Sentry
30
40
 
31
41
  event.fingerprint = fingerprint
32
42
  event.level = level
33
- event.transaction = transaction_names.last
34
43
  event.breadcrumbs = breadcrumbs
35
44
  event.rack_env = rack_env if rack_env
36
45
 
@@ -43,14 +52,20 @@ module Sentry
43
52
  event
44
53
  end
45
54
 
55
+ # Adds the breadcrumb to the scope's breadcrumbs buffer.
56
+ # @param breadcrumb [Breadcrumb]
57
+ # @return [void]
46
58
  def add_breadcrumb(breadcrumb)
47
59
  breadcrumbs.record(breadcrumb)
48
60
  end
49
61
 
62
+ # Clears the scope's breadcrumbs buffer
63
+ # @return [void]
50
64
  def clear_breadcrumbs
51
65
  set_new_breadcrumb_buffer
52
66
  end
53
67
 
68
+ # @return [Scope]
54
69
  def dup
55
70
  copy = super
56
71
  copy.breadcrumbs = breadcrumbs.dup
@@ -64,6 +79,9 @@ module Sentry
64
79
  copy
65
80
  end
66
81
 
82
+ # Updates the scope's data from a given scope.
83
+ # @param scope [Scope]
84
+ # @return [void]
67
85
  def update_from_scope(scope)
68
86
  self.breadcrumbs = scope.breadcrumbs
69
87
  self.contexts = scope.contexts
@@ -75,6 +93,14 @@ module Sentry
75
93
  self.span = scope.span
76
94
  end
77
95
 
96
+ # Updates the scope's data from the given options.
97
+ # @param contexts [Hash]
98
+ # @param extras [Hash]
99
+ # @param tags [Hash]
100
+ # @param user [Hash]
101
+ # @param level [String, Symbol]
102
+ # @param fingerprint [Array]
103
+ # @return [void]
78
104
  def update_from_options(
79
105
  contexts: nil,
80
106
  extra: nil,
@@ -91,75 +117,118 @@ module Sentry
91
117
  self.fingerprint = fingerprint if fingerprint
92
118
  end
93
119
 
120
+ # Sets the scope's rack_env attribute.
121
+ # @param env [Hash]
122
+ # @return [Hash]
94
123
  def set_rack_env(env)
95
124
  env = env || {}
96
125
  @rack_env = env
97
126
  end
98
127
 
128
+ # Sets the scope's span attribute.
129
+ # @param span [Span]
130
+ # @return [Span]
99
131
  def set_span(span)
100
132
  check_argument_type!(span, Span)
101
133
  @span = span
102
134
  end
103
135
 
136
+ # @!macro set_user
104
137
  def set_user(user_hash)
105
138
  check_argument_type!(user_hash, Hash)
106
139
  @user = user_hash
107
140
  end
108
141
 
142
+ # @!macro set_extras
109
143
  def set_extras(extras_hash)
110
144
  check_argument_type!(extras_hash, Hash)
111
145
  @extra.merge!(extras_hash)
112
146
  end
113
147
 
148
+ # Adds a new key-value pair to current extras.
149
+ # @param key [String, Symbol]
150
+ # @param value [Object]
151
+ # @return [Hash]
114
152
  def set_extra(key, value)
115
- @extra.merge!(key => value)
153
+ set_extras(key => value)
116
154
  end
117
155
 
156
+ # @!macro set_tags
118
157
  def set_tags(tags_hash)
119
158
  check_argument_type!(tags_hash, Hash)
120
159
  @tags.merge!(tags_hash)
121
160
  end
122
161
 
162
+ # Adds a new key-value pair to current tags.
163
+ # @param key [String, Symbol]
164
+ # @param value [Object]
165
+ # @return [Hash]
123
166
  def set_tag(key, value)
124
- @tags.merge!(key => value)
167
+ set_tags(key => value)
125
168
  end
126
169
 
170
+ # Updates the scope's contexts attribute by merging with the old value.
171
+ # @param contexts [Hash]
172
+ # @return [Hash]
127
173
  def set_contexts(contexts_hash)
128
174
  check_argument_type!(contexts_hash, Hash)
129
- @contexts.merge!(contexts_hash)
175
+ @contexts.merge!(contexts_hash) do |key, old, new|
176
+ old.merge(new)
177
+ end
130
178
  end
131
179
 
180
+ # @!macro set_context
132
181
  def set_context(key, value)
133
182
  check_argument_type!(value, Hash)
134
- @contexts.merge!(key => value)
183
+ set_contexts(key => value)
135
184
  end
136
185
 
186
+ # Sets the scope's level attribute.
187
+ # @param level [String, Symbol]
188
+ # @return [void]
137
189
  def set_level(level)
138
190
  @level = level
139
191
  end
140
192
 
193
+ # Appends a new transaction name to the scope.
194
+ # The "transaction" here does not refer to `Transaction` objects.
195
+ # @param transaction_name [String]
196
+ # @return [void]
141
197
  def set_transaction_name(transaction_name)
142
198
  @transaction_names << transaction_name
143
199
  end
144
200
 
201
+ # Returns current transaction name.
202
+ # The "transaction" here does not refer to `Transaction` objects.
203
+ # @return [String, nil]
145
204
  def transaction_name
146
205
  @transaction_names.last
147
206
  end
148
207
 
208
+ # Returns the associated Transaction object.
209
+ # @return [Transaction, nil]
149
210
  def get_transaction
150
211
  span.transaction if span
151
212
  end
152
213
 
214
+ # Returns the associated Span object.
215
+ # @return [Span, nil]
153
216
  def get_span
154
217
  span
155
218
  end
156
219
 
220
+ # Sets the scope's fingerprint attribute.
221
+ # @param fingerprint [Array]
222
+ # @return [Array]
157
223
  def set_fingerprint(fingerprint)
158
224
  check_argument_type!(fingerprint, Array)
159
225
 
160
226
  @fingerprint = fingerprint
161
227
  end
162
228
 
229
+ # Adds a new event processor [Proc] to the scope.
230
+ # @param block [Proc]
231
+ # @return [void]
163
232
  def add_event_processor(&block)
164
233
  @event_processors << block
165
234
  end
@@ -189,8 +258,8 @@ module Sentry
189
258
  @breadcrumbs = BreadcrumbBuffer.new(@max_breadcrumbs)
190
259
  end
191
260
 
192
-
193
261
  class << self
262
+ # @return [Hash]
194
263
  def os_context
195
264
  @os_context ||=
196
265
  begin
@@ -204,6 +273,7 @@ module Sentry
204
273
  end
205
274
  end
206
275
 
276
+ # @return [Hash]
207
277
  def runtime_context
208
278
  @runtime_context ||= {
209
279
  name: RbConfig::CONFIG["ruby_install_name"],