sentry-ruby 5.16.1 → 5.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +10 -10
  4. data/Rakefile +1 -1
  5. data/bin/console +1 -0
  6. data/lib/sentry/background_worker.rb +1 -1
  7. data/lib/sentry/backpressure_monitor.rb +2 -32
  8. data/lib/sentry/backtrace.rb +7 -3
  9. data/lib/sentry/check_in_event.rb +1 -1
  10. data/lib/sentry/client.rb +42 -9
  11. data/lib/sentry/configuration.rb +20 -12
  12. data/lib/sentry/cron/monitor_schedule.rb +1 -1
  13. data/lib/sentry/dsn.rb +1 -1
  14. data/lib/sentry/envelope.rb +18 -1
  15. data/lib/sentry/error_event.rb +2 -2
  16. data/lib/sentry/event.rb +8 -8
  17. data/lib/sentry/graphql.rb +9 -0
  18. data/lib/sentry/hub.rb +13 -2
  19. data/lib/sentry/integrable.rb +4 -0
  20. data/lib/sentry/interface.rb +1 -0
  21. data/lib/sentry/interfaces/exception.rb +5 -3
  22. data/lib/sentry/interfaces/mechanism.rb +20 -0
  23. data/lib/sentry/interfaces/request.rb +2 -2
  24. data/lib/sentry/interfaces/single_exception.rb +6 -4
  25. data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
  26. data/lib/sentry/metrics/aggregator.rb +248 -0
  27. data/lib/sentry/metrics/configuration.rb +47 -0
  28. data/lib/sentry/metrics/counter_metric.rb +25 -0
  29. data/lib/sentry/metrics/distribution_metric.rb +25 -0
  30. data/lib/sentry/metrics/gauge_metric.rb +35 -0
  31. data/lib/sentry/metrics/local_aggregator.rb +53 -0
  32. data/lib/sentry/metrics/metric.rb +19 -0
  33. data/lib/sentry/metrics/set_metric.rb +28 -0
  34. data/lib/sentry/metrics/timing.rb +43 -0
  35. data/lib/sentry/metrics.rb +56 -0
  36. data/lib/sentry/net/http.rb +2 -1
  37. data/lib/sentry/propagation_context.rb +9 -8
  38. data/lib/sentry/puma.rb +1 -1
  39. data/lib/sentry/rack/capture_exceptions.rb +14 -2
  40. data/lib/sentry/rake.rb +3 -1
  41. data/lib/sentry/redis.rb +2 -1
  42. data/lib/sentry/scope.rb +21 -26
  43. data/lib/sentry/session.rb +2 -2
  44. data/lib/sentry/session_flusher.rb +6 -38
  45. data/lib/sentry/span.rb +39 -5
  46. data/lib/sentry/test_helper.rb +1 -1
  47. data/lib/sentry/threaded_periodic_worker.rb +39 -0
  48. data/lib/sentry/transaction.rb +15 -14
  49. data/lib/sentry/transaction_event.rb +5 -0
  50. data/lib/sentry/transport/configuration.rb +0 -1
  51. data/lib/sentry/transport.rb +8 -22
  52. data/lib/sentry/utils/argument_checking_helper.rb +6 -0
  53. data/lib/sentry/utils/logging_helper.rb +0 -4
  54. data/lib/sentry/utils/real_ip.rb +1 -1
  55. data/lib/sentry/utils/request_id.rb +1 -1
  56. data/lib/sentry/version.rb +1 -1
  57. data/lib/sentry-ruby.rb +26 -3
  58. data/sentry-ruby.gemspec +1 -0
  59. metadata +29 -2
@@ -50,14 +50,15 @@ module Sentry
50
50
  if sentry_trace_data
51
51
  @trace_id, @parent_span_id, @parent_sampled = sentry_trace_data
52
52
 
53
- @baggage = if baggage_header && !baggage_header.empty?
54
- Baggage.from_incoming_header(baggage_header)
55
- else
56
- # If there's an incoming sentry-trace but no incoming baggage header,
57
- # for instance in traces coming from older SDKs,
58
- # baggage will be empty and frozen and won't be populated as head SDK.
59
- Baggage.new({})
60
- end
53
+ @baggage =
54
+ if baggage_header && !baggage_header.empty?
55
+ Baggage.from_incoming_header(baggage_header)
56
+ else
57
+ # If there's an incoming sentry-trace but no incoming baggage header,
58
+ # for instance in traces coming from older SDKs,
59
+ # baggage will be empty and frozen and won't be populated as head SDK.
60
+ Baggage.new({})
61
+ end
61
62
 
62
63
  @baggage.freeze!
63
64
  @incoming_trace = true
data/lib/sentry/puma.rb CHANGED
@@ -7,7 +7,7 @@ module Sentry
7
7
  module Server
8
8
  PUMA_4_AND_PRIOR = Gem::Version.new(::Puma::Const::PUMA_VERSION) < Gem::Version.new("5.0.0")
9
9
 
10
- def lowlevel_error(e, env, status=500)
10
+ def lowlevel_error(e, env, status = 500)
11
11
  result =
12
12
  if PUMA_4_AND_PRIOR
13
13
  super(e, env)
@@ -4,6 +4,8 @@ module Sentry
4
4
  module Rack
5
5
  class CaptureExceptions
6
6
  ERROR_EVENT_ID_KEY = "sentry.error_event_id"
7
+ MECHANISM_TYPE = "rack"
8
+ SPAN_ORIGIN = "auto.http.rack"
7
9
 
8
10
  def initialize(app)
9
11
  @app = app
@@ -56,13 +58,19 @@ module Sentry
56
58
  end
57
59
 
58
60
  def capture_exception(exception, env)
59
- Sentry.capture_exception(exception).tap do |event|
61
+ Sentry.capture_exception(exception, hint: { mechanism: mechanism }).tap do |event|
60
62
  env[ERROR_EVENT_ID_KEY] = event.event_id if event
61
63
  end
62
64
  end
63
65
 
64
66
  def start_transaction(env, scope)
65
- options = { name: scope.transaction_name, source: scope.transaction_source, op: transaction_op }
67
+ options = {
68
+ name: scope.transaction_name,
69
+ source: scope.transaction_source,
70
+ op: transaction_op,
71
+ origin: SPAN_ORIGIN
72
+ }
73
+
66
74
  transaction = Sentry.continue_trace(env, **options)
67
75
  Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
68
76
  end
@@ -74,6 +82,10 @@ module Sentry
74
82
  transaction.set_http_status(status_code)
75
83
  transaction.finish
76
84
  end
85
+
86
+ def mechanism
87
+ Sentry::Mechanism.new(type: MECHANISM_TYPE, handled: false)
88
+ end
77
89
  end
78
90
  end
79
91
  end
data/lib/sentry/rake.rb CHANGED
@@ -8,7 +8,9 @@ module Sentry
8
8
  module Application
9
9
  # @api private
10
10
  def display_error_message(ex)
11
- Sentry.capture_exception(ex) do |scope|
11
+ mechanism = Sentry::Mechanism.new(type: 'rake', handled: false)
12
+
13
+ Sentry.capture_exception(ex, hint: { mechanism: mechanism }) do |scope|
12
14
  task_name = top_level_tasks.join(' ')
13
15
  scope.set_transaction_name(task_name, source: :task)
14
16
  scope.set_tag("rake_task", task_name)
data/lib/sentry/redis.rb CHANGED
@@ -4,6 +4,7 @@ module Sentry
4
4
  # @api private
5
5
  class Redis
6
6
  OP_NAME = "db.redis"
7
+ SPAN_ORIGIN = "auto.db.redis"
7
8
  LOGGER_NAME = :redis_logger
8
9
 
9
10
  def initialize(commands, host, port, db)
@@ -13,7 +14,7 @@ module Sentry
13
14
  def instrument
14
15
  return yield unless Sentry.initialized?
15
16
 
16
- Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f) do |span|
17
+ Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN) do |span|
17
18
  yield.tap do
18
19
  record_breadcrumb
19
20
 
data/lib/sentry/scope.rb CHANGED
@@ -9,8 +9,8 @@ module Sentry
9
9
  include ArgumentCheckingHelper
10
10
 
11
11
  ATTRIBUTES = [
12
- :transaction_names,
13
- :transaction_sources,
12
+ :transaction_name,
13
+ :transaction_source,
14
14
  :contexts,
15
15
  :extra,
16
16
  :tags,
@@ -96,8 +96,8 @@ module Sentry
96
96
  copy.extra = extra.deep_dup
97
97
  copy.tags = tags.deep_dup
98
98
  copy.user = user.deep_dup
99
- copy.transaction_names = transaction_names.dup
100
- copy.transaction_sources = transaction_sources.dup
99
+ copy.transaction_name = transaction_name.dup
100
+ copy.transaction_source = transaction_source.dup
101
101
  copy.fingerprint = fingerprint.deep_dup
102
102
  copy.span = span.deep_dup
103
103
  copy.session = session.deep_dup
@@ -114,8 +114,8 @@ module Sentry
114
114
  self.extra = scope.extra
115
115
  self.tags = scope.tags
116
116
  self.user = scope.user
117
- self.transaction_names = scope.transaction_names
118
- self.transaction_sources = scope.transaction_sources
117
+ self.transaction_name = scope.transaction_name
118
+ self.transaction_source = scope.transaction_source
119
119
  self.fingerprint = scope.fingerprint
120
120
  self.span = scope.span
121
121
  self.propagation_context = scope.propagation_context
@@ -128,14 +128,15 @@ module Sentry
128
128
  # @param user [Hash]
129
129
  # @param level [String, Symbol]
130
130
  # @param fingerprint [Array]
131
- # @return [void]
131
+ # @return [Array]
132
132
  def update_from_options(
133
133
  contexts: nil,
134
134
  extra: nil,
135
135
  tags: nil,
136
136
  user: nil,
137
137
  level: nil,
138
- fingerprint: nil
138
+ fingerprint: nil,
139
+ **options
139
140
  )
140
141
  self.contexts.merge!(contexts) if contexts
141
142
  self.extra.merge!(extra) if extra
@@ -143,6 +144,9 @@ module Sentry
143
144
  self.user = user if user
144
145
  self.level = level if level
145
146
  self.fingerprint = fingerprint if fingerprint
147
+
148
+ # Returns unsupported option keys so we can notify users.
149
+ options.keys
146
150
  end
147
151
 
148
152
  # Sets the scope's rack_env attribute.
@@ -227,8 +231,8 @@ module Sentry
227
231
  # @param transaction_name [String]
228
232
  # @return [void]
229
233
  def set_transaction_name(transaction_name, source: :custom)
230
- @transaction_names << transaction_name
231
- @transaction_sources << source
234
+ @transaction_name = transaction_name
235
+ @transaction_source = source
232
236
  end
233
237
 
234
238
  # Sets the currently active session on the scope.
@@ -238,18 +242,10 @@ module Sentry
238
242
  @session = session
239
243
  end
240
244
 
241
- # Returns current transaction name.
242
- # The "transaction" here does not refer to `Transaction` objects.
243
- # @return [String, nil]
244
- def transaction_name
245
- @transaction_names.last
246
- end
247
-
248
- # Returns current transaction source.
249
- # The "transaction" here does not refer to `Transaction` objects.
250
- # @return [String, nil]
251
- def transaction_source
252
- @transaction_sources.last
245
+ # These are high cardinality and thus bad.
246
+ # @return [Boolean]
247
+ def transaction_source_low_quality?
248
+ transaction_source == :url
253
249
  end
254
250
 
255
251
  # Returns the associated Transaction object.
@@ -295,14 +291,14 @@ module Sentry
295
291
  private
296
292
 
297
293
  def set_default_value
298
- @contexts = { :os => self.class.os_context, :runtime => self.class.runtime_context }
294
+ @contexts = { os: self.class.os_context, runtime: self.class.runtime_context }
299
295
  @extra = {}
300
296
  @tags = {}
301
297
  @user = {}
302
298
  @level = :error
303
299
  @fingerprint = []
304
- @transaction_names = []
305
- @transaction_sources = []
300
+ @transaction_name = nil
301
+ @transaction_source = nil
306
302
  @event_processors = []
307
303
  @rack_env = {}
308
304
  @span = nil
@@ -355,6 +351,5 @@ module Sentry
355
351
  global_event_processors << block
356
352
  end
357
353
  end
358
-
359
354
  end
360
355
  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
@@ -1,58 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- class SessionFlusher
5
- include LoggingHelper
6
-
4
+ class SessionFlusher < ThreadedPeriodicWorker
7
5
  FLUSH_INTERVAL = 60
8
6
 
9
7
  def initialize(configuration, client)
10
- @thread = nil
11
- @exited = false
8
+ super(configuration.logger, FLUSH_INTERVAL)
12
9
  @client = client
13
10
  @pending_aggregates = {}
14
11
  @release = configuration.release
15
12
  @environment = configuration.environment
16
- @logger = configuration.logger
17
13
 
18
14
  log_debug("[Sessions] Sessions won't be captured without a valid release") unless @release
19
15
  end
20
16
 
21
17
  def flush
22
18
  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
19
 
20
+ @client.capture_envelope(pending_envelope)
29
21
  @pending_aggregates = {}
30
22
  end
31
23
 
24
+ alias_method :run, :flush
25
+
32
26
  def add_session(session)
33
- return if @exited
34
27
  return unless @release
35
28
 
36
- begin
37
- ensure_thread
38
- rescue ThreadError
39
- log_debug("Session flusher thread creation failed")
40
- @exited = true
41
- return
42
- end
29
+ return unless ensure_thread
43
30
 
44
31
  return unless Session::AGGREGATE_STATUSES.include?(session.status)
45
32
  @pending_aggregates[session.aggregation_key] ||= init_aggregates(session.aggregation_key)
46
33
  @pending_aggregates[session.aggregation_key][session.status] += 1
47
34
  end
48
35
 
49
- def kill
50
- log_debug("Killing session flusher")
51
-
52
- @exited = true
53
- @thread&.kill
54
- end
55
-
56
36
  private
57
37
 
58
38
  def init_aggregates(aggregation_key)
@@ -74,17 +54,5 @@ module Sentry
74
54
  def attrs
75
55
  { release: @release, environment: @environment }
76
56
  end
77
-
78
- def ensure_thread
79
- return if @thread&.alive?
80
-
81
- @thread = Thread.new do
82
- loop do
83
- sleep(FLUSH_INTERVAL)
84
- flush
85
- end
86
- end
87
- end
88
-
89
57
  end
90
58
  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
@@ -39,6 +39,11 @@ module Sentry
39
39
  # Recommended: If different than server.port.
40
40
  # Example: 16456
41
41
  SERVER_SOCKET_PORT = "server.socket.port"
42
+
43
+ FILEPATH = "code.filepath"
44
+ LINENO = "code.lineno"
45
+ FUNCTION = "code.function"
46
+ NAMESPACE = "code.namespace"
42
47
  end
43
48
 
44
49
  STATUS_MAP = {
@@ -55,6 +60,8 @@ module Sentry
55
60
  504 => "deadline_exceeded"
56
61
  }
57
62
 
63
+ DEFAULT_SPAN_ORIGIN = "manual"
64
+
58
65
  # An uuid that can be used to identify a trace.
59
66
  # @return [String]
60
67
  attr_reader :trace_id
@@ -88,6 +95,9 @@ module Sentry
88
95
  # Span data
89
96
  # @return [Hash]
90
97
  attr_reader :data
98
+ # Span origin that tracks what kind of instrumentation created a span
99
+ # @return [String]
100
+ attr_reader :origin
91
101
 
92
102
  # The SpanRecorder the current span belongs to.
93
103
  # SpanRecorder holds all spans under the same Transaction object (including the Transaction itself).
@@ -109,7 +119,8 @@ module Sentry
109
119
  parent_span_id: nil,
110
120
  sampled: nil,
111
121
  start_timestamp: nil,
112
- timestamp: nil
122
+ timestamp: nil,
123
+ origin: nil
113
124
  )
114
125
  @trace_id = trace_id || SecureRandom.uuid.delete("-")
115
126
  @span_id = span_id || SecureRandom.uuid.delete("-").slice(0, 16)
@@ -123,6 +134,7 @@ module Sentry
123
134
  @status = status
124
135
  @data = {}
125
136
  @tags = {}
137
+ @origin = origin || DEFAULT_SPAN_ORIGIN
126
138
  end
127
139
 
128
140
  # Finishes the span by adding a timestamp.
@@ -150,7 +162,7 @@ module Sentry
150
162
 
151
163
  # @return [Hash]
152
164
  def to_hash
153
- {
165
+ hash = {
154
166
  trace_id: @trace_id,
155
167
  span_id: @span_id,
156
168
  parent_span_id: @parent_span_id,
@@ -160,8 +172,14 @@ module Sentry
160
172
  op: @op,
161
173
  status: @status,
162
174
  tags: @tags,
163
- data: @data
175
+ data: @data,
176
+ origin: @origin
164
177
  }
178
+
179
+ summary = metrics_summary
180
+ hash[:_metrics_summary] = summary if summary
181
+
182
+ hash
165
183
  end
166
184
 
167
185
  # Returns the span's context that can be used to embed in an Event.
@@ -173,7 +191,8 @@ module Sentry
173
191
  parent_span_id: @parent_span_id,
174
192
  description: @description,
175
193
  op: @op,
176
- status: @status
194
+ status: @status,
195
+ origin: @origin
177
196
  }
178
197
  end
179
198
 
@@ -269,5 +288,20 @@ module Sentry
269
288
  def set_tag(key, value)
270
289
  @tags[key] = value
271
290
  end
291
+
292
+ # Sets the origin of the span.
293
+ # @param origin [String]
294
+ def set_origin(origin)
295
+ @origin = origin
296
+ end
297
+
298
+ # Collects gauge metrics on the span for metric summaries.
299
+ def metrics_local_aggregator
300
+ @metrics_local_aggregator ||= Sentry::Metrics::LocalAggregator.new
301
+ end
302
+
303
+ def metrics_summary
304
+ @metrics_local_aggregator&.to_hash
305
+ end
272
306
  end
273
307
  end
@@ -20,7 +20,7 @@ module Sentry
20
20
  # set transport to DummyTransport, so we can easily intercept the captured events
21
21
  dummy_config.transport.transport_class = Sentry::DummyTransport
22
22
  # make sure SDK allows sending under the current environment
23
- dummy_config.enabled_environments << dummy_config.environment unless dummy_config.enabled_environments.include?(dummy_config.environment)
23
+ dummy_config.enabled_environments += [dummy_config.environment] unless dummy_config.enabled_environments.include?(dummy_config.environment)
24
24
  # disble async event sending
25
25
  dummy_config.background_worker_threads = 0
26
26
 
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class ThreadedPeriodicWorker
5
+ include LoggingHelper
6
+
7
+ def initialize(logger, internal)
8
+ @thread = nil
9
+ @exited = false
10
+ @interval = internal
11
+ @logger = logger
12
+ end
13
+
14
+ def ensure_thread
15
+ return false if @exited
16
+ return true if @thread&.alive?
17
+
18
+ @thread = Thread.new do
19
+ loop do
20
+ sleep(@interval)
21
+ run
22
+ end
23
+ end
24
+
25
+ true
26
+ rescue ThreadError
27
+ log_debug("[#{self.class.name}] thread creation failed")
28
+ @exited = true
29
+ false
30
+ end
31
+
32
+ def kill
33
+ log_debug("[#{self.class.name}] thread killed")
34
+
35
+ @exited = true
36
+ @thread&.kill
37
+ end
38
+ end
39
+ 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
@@ -62,7 +61,7 @@ module Sentry
62
61
  data, serialized_items = serialize_envelope(envelope)
63
62
 
64
63
  if data
65
- log_info("[Transport] Sending envelope with items [#{serialized_items.map(&:type).join(', ')}] #{envelope.event_id} to Sentry")
64
+ log_debug("[Transport] Sending envelope with items [#{serialized_items.map(&:type).join(', ')}] #{envelope.event_id} to Sentry")
66
65
  send_data(data)
67
66
  end
68
67
  end
@@ -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
@@ -11,10 +11,6 @@ module Sentry
11
11
  end
12
12
  end
13
13
 
14
- def log_info(message)
15
- @logger.info(LOGGER_PROGNAME) { message }
16
- end
17
-
18
14
  def log_debug(message)
19
15
  @logger.debug(LOGGER_PROGNAME) { message }
20
16
  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