sentry-ruby-core 4.4.2 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +2 -0
  4. data/Gemfile +8 -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 +65 -7
  14. data/lib/sentry/configuration.rb +155 -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 +26 -0
  19. data/lib/sentry/event.rb +65 -23
  20. data/lib/sentry/exceptions.rb +2 -0
  21. data/lib/sentry/hub.rb +31 -5
  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 +49 -19
  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 +71 -47
  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/release_detector.rb +39 -0
  36. data/lib/sentry/scope.rb +76 -6
  37. data/lib/sentry/span.rb +84 -8
  38. data/lib/sentry/transaction.rb +48 -10
  39. data/lib/sentry/transaction_event.rb +19 -6
  40. data/lib/sentry/transport/configuration.rb +4 -2
  41. data/lib/sentry/transport/dummy_transport.rb +2 -0
  42. data/lib/sentry/transport/http_transport.rb +57 -38
  43. data/lib/sentry/transport.rb +80 -19
  44. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  45. data/lib/sentry/utils/custom_inspection.rb +14 -0
  46. data/lib/sentry/utils/exception_cause_chain.rb +10 -10
  47. data/lib/sentry/utils/logging_helper.rb +6 -4
  48. data/lib/sentry/utils/real_ip.rb +9 -1
  49. data/lib/sentry/utils/request_id.rb +2 -0
  50. data/lib/sentry/version.rb +3 -1
  51. data/lib/sentry-ruby.rb +184 -49
  52. data/sentry-ruby-core.gemspec +2 -3
  53. data/sentry-ruby.gemspec +2 -3
  54. metadata +9 -22
  55. data/.craft.yml +0 -28
  56. data/lib/sentry/benchmarks/benchmark_transport.rb +0 -14
  57. data/lib/sentry/rack/deprecations.rb +0 -19
@@ -1,73 +1,89 @@
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
9
  OP_NAME = "net.http"
7
10
 
11
+ # To explain how the entire thing works, we need to know how the original Net::HTTP#request works
12
+ # Here's part of its definition. As you can see, it usually calls itself inside a #start block
13
+ #
14
+ # ```
15
+ # def request(req, body = nil, &block)
16
+ # unless started?
17
+ # start {
18
+ # req['connection'] ||= 'close'
19
+ # return request(req, body, &block) # <- request will be called for the second time from the first call
20
+ # }
21
+ # end
22
+ # # .....
23
+ # end
24
+ # ```
25
+ #
26
+ # So we're only instrumenting request when `Net::HTTP` is already started
8
27
  def request(req, body = nil, &block)
28
+ return super unless started?
29
+
30
+ sentry_span = start_sentry_span
31
+ set_sentry_trace_header(req, sentry_span)
32
+
9
33
  super.tap do |res|
10
34
  record_sentry_breadcrumb(req, res)
11
- record_sentry_span(req, res)
35
+ record_sentry_span(req, res, sentry_span)
12
36
  end
13
37
  end
14
38
 
15
- def do_start
16
- super.tap do
17
- start_sentry_span
18
- end
19
- end
39
+ private
20
40
 
21
- def do_finish
22
- super.tap do
23
- finish_sentry_span
24
- end
25
- end
41
+ def set_sentry_trace_header(req, sentry_span)
42
+ return unless sentry_span
26
43
 
27
- private
44
+ trace = Sentry.get_current_client.generate_sentry_trace(sentry_span)
45
+ req[SENTRY_TRACE_HEADER_NAME] = trace if trace
46
+ end
28
47
 
29
48
  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
49
+ return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
50
+ return if from_sentry_sdk?
51
+
52
+ request_info = extract_request_info(req)
53
+
54
+ crumb = Sentry::Breadcrumb.new(
55
+ level: :info,
56
+ category: OP_NAME,
57
+ type: :info,
58
+ data: {
59
+ status: res.code.to_i,
60
+ **request_info
61
+ }
62
+ )
63
+ Sentry.add_breadcrumb(crumb)
46
64
  end
47
65
 
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
66
+ def record_sentry_span(req, res, sentry_span)
67
+ return unless Sentry.initialized? && sentry_span
68
+
69
+ request_info = extract_request_info(req)
70
+ sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
71
+ sentry_span.set_data(:status, res.code.to_i)
72
+ finish_sentry_span(sentry_span)
54
73
  end
55
74
 
56
75
  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
76
+ return unless Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
77
+ return if from_sentry_sdk?
78
+ return if transaction.sampled == false
60
79
 
61
- child_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
62
- @sentry_span = child_span
63
- end
80
+ transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
64
81
  end
65
82
 
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
83
+ def finish_sentry_span(sentry_span)
84
+ return unless Sentry.initialized? && sentry_span
85
+
86
+ sentry_span.set_timestamp(Sentry.utc_now.to_f)
71
87
  end
72
88
 
73
89
  def from_sentry_sdk?
@@ -76,9 +92,17 @@ module Sentry
76
92
  end
77
93
 
78
94
  def extract_request_info(req)
79
- uri = req.uri
95
+ uri = req.uri || URI.parse("#{use_ssl? ? 'https' : 'http'}://#{address}#{req.path}")
80
96
  url = "#{uri.scheme}://#{uri.host}#{uri.path}" rescue uri.to_s
81
- { method: req.method, url: url }
97
+
98
+ result = { method: req.method, url: url }
99
+
100
+ if Sentry.configuration.send_default_pii
101
+ result[:url] = result[:url] + "?#{uri.query}"
102
+ result[:body] = req.body
103
+ end
104
+
105
+ result
82
106
  end
83
107
  end
84
108
  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,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
+ new.merge(old)
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"],
data/lib/sentry/span.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "securerandom"
3
4
 
4
5
  module Sentry
@@ -17,9 +18,49 @@ module Sentry
17
18
  504 => "deadline_exceeded"
18
19
  }
19
20
 
20
-
21
- attr_reader :trace_id, :span_id, :parent_span_id, :sampled, :start_timestamp, :timestamp, :description, :op, :status, :tags, :data
22
- attr_accessor :span_recorder, :transaction
21
+ # An uuid that can be used to identify a trace.
22
+ # @return [String]
23
+ attr_reader :trace_id
24
+ # An uuid that can be used to identify the span.
25
+ # @return [String]
26
+ attr_reader :span_id
27
+ # Span parent's span_id.
28
+ # @return [String]
29
+ attr_reader :parent_span_id
30
+ # Sampling result of the span.
31
+ # @return [Boolean, nil]
32
+ attr_reader :sampled
33
+ # Starting timestamp of the span.
34
+ # @return [Float]
35
+ attr_reader :start_timestamp
36
+ # Finishing timestamp of the span.
37
+ # @return [Float]
38
+ attr_reader :timestamp
39
+ # Span description
40
+ # @return [String]
41
+ attr_reader :description
42
+ # Span operation
43
+ # @return [String]
44
+ attr_reader :op
45
+ # Span status
46
+ # @return [String]
47
+ attr_reader :status
48
+ # Span tags
49
+ # @return [Hash]
50
+ attr_reader :tags
51
+ # Span data
52
+ # @return [Hash]
53
+ attr_reader :data
54
+
55
+ # The SpanRecorder the current span belongs to.
56
+ # SpanRecorder holds all spans under the same Transaction object (including the Transaction itself).
57
+ # @return [SpanRecorder]
58
+ attr_accessor :span_recorder
59
+
60
+ # The Transaction object the Span belongs to.
61
+ # Every span needs to be attached to a Transaction and their child spans will also inherit the same transaction.
62
+ # @return [Transaction]
63
+ attr_accessor :transaction
23
64
 
24
65
  def initialize(
25
66
  description: nil,
@@ -44,6 +85,8 @@ module Sentry
44
85
  @tags = {}
45
86
  end
46
87
 
88
+ # Finishes the span by adding a timestamp.
89
+ # @return [self]
47
90
  def finish
48
91
  # already finished
49
92
  return if @timestamp
@@ -52,6 +95,8 @@ module Sentry
52
95
  self
53
96
  end
54
97
 
98
+ # Generates a trace string that can be used to connect other transactions.
99
+ # @return [String]
55
100
  def to_sentry_trace
56
101
  sampled_flag = ""
57
102
  sampled_flag = @sampled ? 1 : 0 unless @sampled.nil?
@@ -59,6 +104,7 @@ module Sentry
59
104
  "#{@trace_id}-#{@span_id}-#{sampled_flag}"
60
105
  end
61
106
 
107
+ # @return [Hash]
62
108
  def to_hash
63
109
  {
64
110
  trace_id: @trace_id,
@@ -74,6 +120,8 @@ module Sentry
74
120
  }
75
121
  end
76
122
 
123
+ # Returns the span's context that can be used to embed in an Event.
124
+ # @return [Hash]
77
125
  def get_trace_context
78
126
  {
79
127
  trace_id: @trace_id,
@@ -85,9 +133,11 @@ module Sentry
85
133
  }
86
134
  end
87
135
 
88
- def start_child(**options)
89
- options = options.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
90
- new_span = Span.new(**options)
136
+ # Starts a child span with given attributes.
137
+ # @param attributes [Hash] the attributes for the child span.
138
+ def start_child(**attributes)
139
+ attributes = attributes.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
140
+ new_span = Span.new(**attributes)
91
141
  new_span.transaction = transaction
92
142
  new_span.span_recorder = span_recorder
93
143
 
@@ -98,8 +148,17 @@ module Sentry
98
148
  new_span
99
149
  end
100
150
 
101
- def with_child_span(**options, &block)
102
- child_span = start_child(**options)
151
+ # Starts a child span, yield it to the given block, and then finish the span after the block is executed.
152
+ # @example
153
+ # span.with_child_span do |child_span|
154
+ # # things happen here will be recorded in a child span
155
+ # end
156
+ #
157
+ # @param attributes [Hash] the attributes for the child span.
158
+ # @param block [Proc] the action to be recorded in the child span.
159
+ # @yieldparam child_span [Span]
160
+ def with_child_span(**attributes, &block)
161
+ child_span = start_child(**attributes)
103
162
 
104
163
  yield(child_span)
105
164
 
@@ -110,22 +169,33 @@ module Sentry
110
169
  dup
111
170
  end
112
171
 
172
+ # Sets the span's operation.
173
+ # @param op [String] operation of the span.
113
174
  def set_op(op)
114
175
  @op = op
115
176
  end
116
177
 
178
+ # Sets the span's description.
179
+ # @param description [String] description of the span.
117
180
  def set_description(description)
118
181
  @description = description
119
182
  end
120
183
 
184
+
185
+ # Sets the span's status.
186
+ # @param satus [String] status of the span.
121
187
  def set_status(status)
122
188
  @status = status
123
189
  end
124
190
 
191
+ # Sets the span's finish timestamp.
192
+ # @param timestamp [Float] finished time in float format (most precise).
125
193
  def set_timestamp(timestamp)
126
194
  @timestamp = timestamp
127
195
  end
128
196
 
197
+ # Sets the span's status with given http status code.
198
+ # @param status_code [String] example: "500".
129
199
  def set_http_status(status_code)
130
200
  status_code = status_code.to_i
131
201
  set_data("status_code", status_code)
@@ -139,10 +209,16 @@ module Sentry
139
209
  set_status(status)
140
210
  end
141
211
 
212
+ # Inserts a key-value pair to the span's data payload.
213
+ # @param key [String, Symbol]
214
+ # @param value [Object]
142
215
  def set_data(key, value)
143
216
  @data[key] = value
144
217
  end
145
218
 
219
+ # Sets a tag to the span.
220
+ # @param key [String, Symbol]
221
+ # @param value [String]
146
222
  def set_tag(key, value)
147
223
  @tags[key] = value
148
224
  end