sentry-ruby 5.16.1 → 5.17.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +1 -1
  4. data/lib/sentry/background_worker.rb +1 -1
  5. data/lib/sentry/backtrace.rb +7 -3
  6. data/lib/sentry/check_in_event.rb +1 -1
  7. data/lib/sentry/client.rb +42 -9
  8. data/lib/sentry/configuration.rb +19 -11
  9. data/lib/sentry/cron/monitor_schedule.rb +1 -1
  10. data/lib/sentry/dsn.rb +1 -1
  11. data/lib/sentry/envelope.rb +18 -1
  12. data/lib/sentry/error_event.rb +2 -2
  13. data/lib/sentry/event.rb +8 -8
  14. data/lib/sentry/hub.rb +1 -1
  15. data/lib/sentry/integrable.rb +4 -0
  16. data/lib/sentry/interface.rb +1 -0
  17. data/lib/sentry/interfaces/exception.rb +5 -3
  18. data/lib/sentry/interfaces/mechanism.rb +20 -0
  19. data/lib/sentry/interfaces/request.rb +2 -2
  20. data/lib/sentry/interfaces/single_exception.rb +6 -4
  21. data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
  22. data/lib/sentry/metrics/aggregator.rb +276 -0
  23. data/lib/sentry/metrics/configuration.rb +47 -0
  24. data/lib/sentry/metrics/counter_metric.rb +25 -0
  25. data/lib/sentry/metrics/distribution_metric.rb +25 -0
  26. data/lib/sentry/metrics/gauge_metric.rb +35 -0
  27. data/lib/sentry/metrics/local_aggregator.rb +53 -0
  28. data/lib/sentry/metrics/metric.rb +19 -0
  29. data/lib/sentry/metrics/set_metric.rb +28 -0
  30. data/lib/sentry/metrics/timing.rb +43 -0
  31. data/lib/sentry/metrics.rb +55 -0
  32. data/lib/sentry/propagation_context.rb +9 -8
  33. data/lib/sentry/puma.rb +1 -1
  34. data/lib/sentry/rack/capture_exceptions.rb +6 -1
  35. data/lib/sentry/rake.rb +3 -1
  36. data/lib/sentry/scope.rb +7 -2
  37. data/lib/sentry/session.rb +2 -2
  38. data/lib/sentry/session_flusher.rb +1 -6
  39. data/lib/sentry/span.rb +16 -2
  40. data/lib/sentry/transaction.rb +15 -14
  41. data/lib/sentry/transaction_event.rb +5 -0
  42. data/lib/sentry/transport/configuration.rb +0 -1
  43. data/lib/sentry/transport.rb +7 -21
  44. data/lib/sentry/utils/argument_checking_helper.rb +6 -0
  45. data/lib/sentry/utils/real_ip.rb +1 -1
  46. data/lib/sentry/utils/request_id.rb +1 -1
  47. data/lib/sentry/version.rb +1 -1
  48. data/lib/sentry-ruby.rb +15 -3
  49. data/sentry-ruby.gemspec +1 -0
  50. metadata +27 -2
data/lib/sentry/scope.rb CHANGED
@@ -252,6 +252,12 @@ module Sentry
252
252
  @transaction_sources.last
253
253
  end
254
254
 
255
+ # These are high cardinality and thus bad.
256
+ # @return [Boolean]
257
+ def transaction_source_low_quality?
258
+ transaction_source == :url
259
+ end
260
+
255
261
  # Returns the associated Transaction object.
256
262
  # @return [Transaction, nil]
257
263
  def get_transaction
@@ -295,7 +301,7 @@ module Sentry
295
301
  private
296
302
 
297
303
  def set_default_value
298
- @contexts = { :os => self.class.os_context, :runtime => self.class.runtime_context }
304
+ @contexts = { os: self.class.os_context, runtime: self.class.runtime_context }
299
305
  @extra = {}
300
306
  @tags = {}
301
307
  @user = {}
@@ -355,6 +361,5 @@ module Sentry
355
361
  global_event_processors << block
356
362
  end
357
363
  end
358
-
359
364
  end
360
365
  end
@@ -5,8 +5,8 @@ module Sentry
5
5
  attr_reader :started, :status, :aggregation_key
6
6
 
7
7
  # TODO-neel add :crashed after adding handled mechanism
8
- STATUSES = %i(ok errored exited)
9
- AGGREGATE_STATUSES = %i(errored exited)
8
+ STATUSES = %i[ok errored exited]
9
+ AGGREGATE_STATUSES = %i[errored exited]
10
10
 
11
11
  def initialize
12
12
  @started = Sentry.utc_now
@@ -20,12 +20,8 @@ module Sentry
20
20
 
21
21
  def flush
22
22
  return if @pending_aggregates.empty?
23
- envelope = pending_envelope
24
-
25
- Sentry.background_worker.perform do
26
- @client.transport.send_envelope(envelope)
27
- end
28
23
 
24
+ @client.capture_envelope(pending_envelope)
29
25
  @pending_aggregates = {}
30
26
  end
31
27
 
@@ -85,6 +81,5 @@ module Sentry
85
81
  end
86
82
  end
87
83
  end
88
-
89
84
  end
90
85
  end
data/lib/sentry/span.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "securerandom"
4
+ require "sentry/metrics/local_aggregator"
4
5
 
5
6
  module Sentry
6
7
  class Span
7
-
8
8
  # We will try to be consistent with OpenTelemetry on this front going forward.
9
9
  # https://develop.sentry.dev/sdk/performance/span-data-conventions/
10
10
  module DataConventions
@@ -150,7 +150,7 @@ module Sentry
150
150
 
151
151
  # @return [Hash]
152
152
  def to_hash
153
- {
153
+ hash = {
154
154
  trace_id: @trace_id,
155
155
  span_id: @span_id,
156
156
  parent_span_id: @parent_span_id,
@@ -162,6 +162,11 @@ module Sentry
162
162
  tags: @tags,
163
163
  data: @data
164
164
  }
165
+
166
+ summary = metrics_summary
167
+ hash[:_metrics_summary] = summary if summary
168
+
169
+ hash
165
170
  end
166
171
 
167
172
  # Returns the span's context that can be used to embed in an Event.
@@ -269,5 +274,14 @@ module Sentry
269
274
  def set_tag(key, value)
270
275
  @tags[key] = value
271
276
  end
277
+
278
+ # Collects gauge metrics on the span for metric summaries.
279
+ def metrics_local_aggregator
280
+ @metrics_local_aggregator ||= Sentry::Metrics::LocalAggregator.new
281
+ end
282
+
283
+ def metrics_summary
284
+ @metrics_local_aggregator&.to_hash
285
+ end
272
286
  end
273
287
  end
@@ -13,7 +13,7 @@ module Sentry
13
13
  MESSAGE_PREFIX = "[Tracing]"
14
14
 
15
15
  # https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
16
- SOURCES = %i(custom url route view component task)
16
+ SOURCES = %i[custom url route view component task]
17
17
 
18
18
  include LoggingHelper
19
19
 
@@ -110,14 +110,15 @@ module Sentry
110
110
 
111
111
  trace_id, parent_span_id, parent_sampled = sentry_trace_data
112
112
 
113
- baggage = if baggage && !baggage.empty?
114
- Baggage.from_incoming_header(baggage)
115
- else
116
- # If there's an incoming sentry-trace but no incoming baggage header,
117
- # for instance in traces coming from older SDKs,
118
- # baggage will be empty and frozen and won't be populated as head SDK.
119
- Baggage.new({})
120
- end
113
+ baggage =
114
+ if baggage && !baggage.empty?
115
+ Baggage.from_incoming_header(baggage)
116
+ else
117
+ # If there's an incoming sentry-trace but no incoming baggage header,
118
+ # for instance in traces coming from older SDKs,
119
+ # baggage will be empty and frozen and won't be populated as head SDK.
120
+ Baggage.new({})
121
+ end
121
122
 
122
123
  baggage.freeze!
123
124
 
@@ -301,6 +302,11 @@ module Sentry
301
302
  profiler.start
302
303
  end
303
304
 
305
+ # These are high cardinality and thus bad
306
+ def source_low_quality?
307
+ source == :url
308
+ end
309
+
304
310
  protected
305
311
 
306
312
  def init_span_recorder(limit = 1000)
@@ -336,11 +342,6 @@ module Sentry
336
342
  @baggage = Baggage.new(items, mutable: false)
337
343
  end
338
344
 
339
- # These are high cardinality and thus bad
340
- def source_low_quality?
341
- source == :url
342
- end
343
-
344
345
  class SpanRecorder
345
346
  attr_reader :max_length, :spans
346
347
 
@@ -17,6 +17,9 @@ module Sentry
17
17
  # @return [Hash, nil]
18
18
  attr_accessor :profile
19
19
 
20
+ # @return [Hash, nil]
21
+ attr_accessor :metrics_summary
22
+
20
23
  def initialize(transaction:, **options)
21
24
  super(**options)
22
25
 
@@ -29,6 +32,7 @@ module Sentry
29
32
  self.tags = transaction.tags
30
33
  self.dynamic_sampling_context = transaction.get_baggage.dynamic_sampling_context
31
34
  self.measurements = transaction.measurements
35
+ self.metrics_summary = transaction.metrics_summary
32
36
 
33
37
  finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
34
38
  self.spans = finished_spans.map(&:to_hash)
@@ -49,6 +53,7 @@ module Sentry
49
53
  data[:spans] = @spans.map(&:to_hash) if @spans
50
54
  data[:start_timestamp] = @start_timestamp
51
55
  data[:measurements] = @measurements
56
+ data[:_metrics_summary] = @metrics_summary if @metrics_summary
52
57
  data
53
58
  end
54
59
 
@@ -3,7 +3,6 @@
3
3
  module Sentry
4
4
  class Transport
5
5
  class Configuration
6
-
7
6
  # The timeout in seconds to open a connection to Sentry, in seconds.
8
7
  # Default value is 2.
9
8
  #
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
- require "base64"
5
4
  require "sentry/envelope"
6
5
 
7
6
  module Sentry
@@ -89,18 +88,9 @@ module Sentry
89
88
  [data, serialized_items]
90
89
  end
91
90
 
92
- def is_rate_limited?(item_type)
91
+ def is_rate_limited?(data_category)
93
92
  # check category-specific limit
94
- category_delay =
95
- case item_type
96
- when "transaction"
97
- @rate_limits["transaction"]
98
- when "sessions"
99
- @rate_limits["session"]
100
- else
101
- @rate_limits["error"]
102
- end
103
-
93
+ category_delay = @rate_limits[data_category]
104
94
  # check universal limit if not category limit
105
95
  universal_delay = @rate_limits[nil]
106
96
 
@@ -161,11 +151,11 @@ module Sentry
161
151
  envelope
162
152
  end
163
153
 
164
- def record_lost_event(reason, item_type)
154
+ def record_lost_event(reason, data_category)
165
155
  return unless @send_client_reports
166
156
  return unless CLIENT_REPORT_REASONS.include?(reason)
167
157
 
168
- @discarded_events[[reason, item_type]] += 1
158
+ @discarded_events[[reason, data_category]] += 1
169
159
  end
170
160
 
171
161
  def flush
@@ -185,11 +175,7 @@ module Sentry
185
175
  return nil if @discarded_events.empty?
186
176
 
187
177
  discarded_events_hash = @discarded_events.map do |key, val|
188
- reason, type = key
189
-
190
- # 'event' has to be mapped to 'error'
191
- category = type == 'event' ? 'error' : type
192
-
178
+ reason, category = key
193
179
  { reason: reason, category: category, quantity: val }
194
180
  end
195
181
 
@@ -207,9 +193,9 @@ module Sentry
207
193
 
208
194
  def reject_rate_limited_items(envelope)
209
195
  envelope.items.reject! do |item|
210
- if is_rate_limited?(item.type)
196
+ if is_rate_limited?(item.data_category)
211
197
  log_debug("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
212
- record_lost_event(:ratelimit_backoff, item.type)
198
+ record_lost_event(:ratelimit_backoff, item.data_category)
213
199
 
214
200
  true
215
201
  else
@@ -15,5 +15,11 @@ module Sentry
15
15
  raise ArgumentError, "expect the argument to be one of #{values.map(&:inspect).join(' or ')}, got #{argument.inspect}"
16
16
  end
17
17
  end
18
+
19
+ def check_callable!(name, value)
20
+ unless value == nil || value.respond_to?(:call)
21
+ raise ArgumentError, "#{name} must be callable (or nil to disable)"
22
+ end
23
+ end
18
24
  end
19
25
  end
@@ -15,7 +15,7 @@ module Sentry
15
15
  "fc00::/7", # private IPv6 range fc00::/7
16
16
  "10.0.0.0/8", # private IPv4 range 10.x.x.x
17
17
  "172.16.0.0/12", # private IPv4 range 172.16.0.0 .. 172.31.255.255
18
- "192.168.0.0/16", # private IPv4 range 192.168.x.x
18
+ "192.168.0.0/16" # private IPv4 range 192.168.x.x
19
19
  ]
20
20
 
21
21
  attr_reader :ip
@@ -3,7 +3,7 @@
3
3
  module Sentry
4
4
  module Utils
5
5
  module RequestId
6
- REQUEST_ID_HEADERS = %w(action_dispatch.request_id HTTP_X_REQUEST_ID).freeze
6
+ REQUEST_ID_HEADERS = %w[action_dispatch.request_id HTTP_X_REQUEST_ID].freeze
7
7
 
8
8
  # Request ID based on ActionDispatch::RequestId
9
9
  def self.read_from(env)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.16.1"
4
+ VERSION = "5.17.3"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -23,10 +23,11 @@ require "sentry/background_worker"
23
23
  require "sentry/session_flusher"
24
24
  require "sentry/backpressure_monitor"
25
25
  require "sentry/cron/monitor_check_ins"
26
+ require "sentry/metrics"
26
27
 
27
28
  [
28
29
  "sentry/rake",
29
- "sentry/rack",
30
+ "sentry/rack"
30
31
  ].each do |lib|
31
32
  begin
32
33
  require lib
@@ -77,6 +78,10 @@ module Sentry
77
78
  # @return [BackpressureMonitor, nil]
78
79
  attr_reader :backpressure_monitor
79
80
 
81
+ # @!attribute [r] metrics_aggregator
82
+ # @return [Metrics::Aggregator, nil]
83
+ attr_reader :metrics_aggregator
84
+
80
85
  ##### Patch Registration #####
81
86
 
82
87
  # @!visibility private
@@ -222,8 +227,9 @@ module Sentry
222
227
  Thread.current.thread_variable_set(THREAD_LOCAL, hub)
223
228
  @main_hub = hub
224
229
  @background_worker = Sentry::BackgroundWorker.new(config)
225
- @session_flusher = config.auto_session_tracking ? Sentry::SessionFlusher.new(config, client) : nil
230
+ @session_flusher = config.session_tracking? ? Sentry::SessionFlusher.new(config, client) : nil
226
231
  @backpressure_monitor = config.enable_backpressure_handling ? Sentry::BackpressureMonitor.new(config, client) : nil
232
+ @metrics_aggregator = config.metrics.enabled ? Sentry::Metrics::Aggregator.new(config, client) : nil
227
233
  exception_locals_tp.enable if config.include_local_variables
228
234
  at_exit { close }
229
235
  end
@@ -244,8 +250,14 @@ module Sentry
244
250
  @backpressure_monitor = nil
245
251
  end
246
252
 
253
+ if @metrics_aggregator
254
+ @metrics_aggregator.flush(force: true)
255
+ @metrics_aggregator.kill
256
+ @metrics_aggregator = nil
257
+ end
258
+
247
259
  if client = get_current_client
248
- client.transport.flush
260
+ client.flush
249
261
 
250
262
  if client.configuration.include_local_variables
251
263
  exception_locals_tp.disable
data/sentry-ruby.gemspec CHANGED
@@ -21,4 +21,5 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
 
23
23
  spec.add_dependency "concurrent-ruby", '~> 1.0', '>= 1.0.2'
24
+ spec.add_dependency "bigdecimal"
24
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.16.1
4
+ version: 5.17.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-09 00:00:00.000000000 Z
11
+ date: 2024-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 1.0.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: bigdecimal
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
33
47
  description: A gem that provides a client interface for the Sentry error logger
34
48
  email: accounts@sentry.io
35
49
  executables: []
@@ -75,6 +89,7 @@ files:
75
89
  - lib/sentry/integrable.rb
76
90
  - lib/sentry/interface.rb
77
91
  - lib/sentry/interfaces/exception.rb
92
+ - lib/sentry/interfaces/mechanism.rb
78
93
  - lib/sentry/interfaces/request.rb
79
94
  - lib/sentry/interfaces/single_exception.rb
80
95
  - lib/sentry/interfaces/stacktrace.rb
@@ -82,6 +97,16 @@ files:
82
97
  - lib/sentry/interfaces/threads.rb
83
98
  - lib/sentry/linecache.rb
84
99
  - lib/sentry/logger.rb
100
+ - lib/sentry/metrics.rb
101
+ - lib/sentry/metrics/aggregator.rb
102
+ - lib/sentry/metrics/configuration.rb
103
+ - lib/sentry/metrics/counter_metric.rb
104
+ - lib/sentry/metrics/distribution_metric.rb
105
+ - lib/sentry/metrics/gauge_metric.rb
106
+ - lib/sentry/metrics/local_aggregator.rb
107
+ - lib/sentry/metrics/metric.rb
108
+ - lib/sentry/metrics/set_metric.rb
109
+ - lib/sentry/metrics/timing.rb
85
110
  - lib/sentry/net/http.rb
86
111
  - lib/sentry/profiler.rb
87
112
  - lib/sentry/propagation_context.rb