sentry-ruby-core 5.17.2 → 5.17.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be9c1bd29350d0e6a59ee415c3ab1b2509172c9e6e566b3c2bdcd013c80fc8cf
4
- data.tar.gz: 39b5b3fe8b54be43ecfd06cc39981e670a9c07d86d303a412aa4d83577155513
3
+ metadata.gz: fe82a2b6001d48448ad45cfdfcf6eca4c99708b33ca289afc1777dac54dcd851
4
+ data.tar.gz: db84b44742d0e847b6fd66dac5a3338e63d4497723979b7c71fbbea46eb50480
5
5
  SHA512:
6
- metadata.gz: 7efacb821bec171862390a6cda4353a94a32cdb064b63eb4b6b665a52798fa7338dd41df5648e6e32a5f45311455f13eb69cf8a852d197c44863aa16adc6dce1
7
- data.tar.gz: d75b0125443e8cff217fc1c4a6c9ff5dc1ff7ee51542e19ab3d3768e2f716233196afdcc72883b9b451d42817bd7a974c73095c27b48abfaffa089ae9a78d066
6
+ metadata.gz: 0b5cd84206fa239965fdfddc7a9570c2ca8c490f61055ec7c4b919d5e9ab299accbb6b8588a939101e4c3605a043f2e33392baa14f11a8bf1868ed78bf0f8fb7
7
+ data.tar.gz: 1348bd6636f8283af3d85934ffe414606072758939cc0027c70730f8711f933ab72d9ee23d49cd921ca3562dcd4a034f93255fe5f3eb257a0e4288815be840e5
data/lib/sentry/client.rb CHANGED
@@ -49,16 +49,17 @@ module Sentry
49
49
  return unless configuration.sending_allowed?
50
50
 
51
51
  if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
52
- transport.record_lost_event(:sample_rate, 'event')
52
+ transport.record_lost_event(:sample_rate, 'error')
53
53
  return
54
54
  end
55
55
 
56
56
  event_type = event.is_a?(Event) ? event.type : event["type"]
57
+ data_category = Envelope::Item.data_category(event_type)
57
58
  event = scope.apply_to_event(event, hint)
58
59
 
59
60
  if event.nil?
60
61
  log_debug("Discarded event because one of the event processors returned nil")
61
- transport.record_lost_event(:event_processor, event_type)
62
+ transport.record_lost_event(:event_processor, data_category)
62
63
  return
63
64
  end
64
65
 
@@ -66,7 +67,7 @@ module Sentry
66
67
  dispatch_async_event(async_block, event, hint)
67
68
  elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
68
69
  queued = dispatch_background_event(event, hint)
69
- transport.record_lost_event(:queue_overflow, event_type) unless queued
70
+ transport.record_lost_event(:queue_overflow, data_category) unless queued
70
71
  else
71
72
  send_event(event, hint)
72
73
  end
@@ -77,6 +78,20 @@ module Sentry
77
78
  nil
78
79
  end
79
80
 
81
+ # Capture an envelope directly.
82
+ # @param envelope [Envelope] the envelope to be captured.
83
+ # @return [void]
84
+ def capture_envelope(envelope)
85
+ Sentry.background_worker.perform { send_envelope(envelope) }
86
+ end
87
+
88
+ # Flush pending events to Sentry.
89
+ # @return [void]
90
+ def flush
91
+ transport.flush if configuration.sending_to_dsn_allowed?
92
+ spotlight_transport.flush if spotlight_transport
93
+ end
94
+
80
95
  # Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
81
96
  # @param exception [Exception] the exception to be reported.
82
97
  # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
@@ -152,13 +167,14 @@ module Sentry
152
167
  # @!macro send_event
153
168
  def send_event(event, hint = nil)
154
169
  event_type = event.is_a?(Event) ? event.type : event["type"]
170
+ data_category = Envelope::Item.data_category(event_type)
155
171
 
156
172
  if event_type != TransactionEvent::TYPE && configuration.before_send
157
173
  event = configuration.before_send.call(event, hint)
158
174
 
159
175
  if event.nil?
160
176
  log_debug("Discarded event because before_send returned nil")
161
- transport.record_lost_event(:before_send, 'event')
177
+ transport.record_lost_event(:before_send, data_category)
162
178
  return
163
179
  end
164
180
  end
@@ -168,7 +184,7 @@ module Sentry
168
184
 
169
185
  if event.nil?
170
186
  log_debug("Discarded event because before_send_transaction returned nil")
171
- transport.record_lost_event(:before_send, 'transaction')
187
+ transport.record_lost_event(:before_send, data_category)
172
188
  return
173
189
  end
174
190
  end
@@ -179,7 +195,23 @@ module Sentry
179
195
  event
180
196
  rescue => e
181
197
  log_error("Event sending failed", e, debug: configuration.debug)
182
- transport.record_lost_event(:network_error, event_type)
198
+ transport.record_lost_event(:network_error, data_category)
199
+ raise
200
+ end
201
+
202
+ # Send an envelope directly to Sentry.
203
+ # @param envelope [Envelope] the envelope to be sent.
204
+ # @return [void]
205
+ def send_envelope(envelope)
206
+ transport.send_envelope(envelope) if configuration.sending_to_dsn_allowed?
207
+ spotlight_transport.send_envelope(envelope) if spotlight_transport
208
+ rescue => e
209
+ log_error("Envelope sending failed", e, debug: configuration.debug)
210
+
211
+ envelope.items.map(&:data_category).each do |data_category|
212
+ transport.record_lost_event(:network_error, data_category)
213
+ end
214
+
183
215
  raise
184
216
  end
185
217
 
@@ -18,6 +18,23 @@ module Sentry
18
18
  @headers[:type] || 'event'
19
19
  end
20
20
 
21
+ # rate limits and client reports use the data_category rather than envelope item type
22
+ def self.data_category(type)
23
+ case type
24
+ when 'session', 'attachment', 'transaction', 'profile' then type
25
+ when 'sessions' then 'session'
26
+ when 'check_in' then 'monitor'
27
+ when 'statsd', 'metric_meta' then 'metric_bucket'
28
+ when 'event' then 'error'
29
+ when 'client_report' then 'internal'
30
+ else 'default'
31
+ end
32
+ end
33
+
34
+ def data_category
35
+ self.class.data_category(type)
36
+ end
37
+
21
38
  def to_s
22
39
  [JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
23
40
  end
@@ -12,8 +12,18 @@ module Sentry
12
12
  # when we record code locations
13
13
  DEFAULT_STACKLEVEL = 4
14
14
 
15
- KEY_SANITIZATION_REGEX = /[^a-zA-Z0-9_\/.-]+/
16
- VALUE_SANITIZATION_REGEX = /[^[[:word:]][[:digit:]][[:space:]]_:\/@\.{}\[\]$-]+/
15
+ KEY_SANITIZATION_REGEX = /[^a-zA-Z0-9_\-.]+/
16
+ UNIT_SANITIZATION_REGEX = /[^a-zA-Z0-9_]+/
17
+ TAG_KEY_SANITIZATION_REGEX = /[^a-zA-Z0-9_\-.\/]+/
18
+
19
+ TAG_VALUE_SANITIZATION_MAP = {
20
+ "\n" => "\\n",
21
+ "\r" => "\\r",
22
+ "\t" => "\\t",
23
+ "\\" => "\\\\",
24
+ "|" => "\\u{7c}",
25
+ "," => "\\u{2c}"
26
+ }
17
27
 
18
28
  METRIC_TYPES = {
19
29
  c: CounterMetric,
@@ -23,7 +33,7 @@ module Sentry
23
33
  }
24
34
 
25
35
  # exposed only for testing
26
- attr_reader :thread, :buckets, :flush_shift, :code_locations
36
+ attr_reader :client, :thread, :buckets, :flush_shift, :code_locations
27
37
 
28
38
  def initialize(configuration, client)
29
39
  @client = client
@@ -107,9 +117,7 @@ module Sentry
107
117
  end
108
118
  end
109
119
 
110
- Sentry.background_worker.perform do
111
- @client.transport.send_envelope(envelope)
112
- end
120
+ @client.capture_envelope(envelope)
113
121
  end
114
122
 
115
123
  def kill
@@ -182,9 +190,9 @@ module Sentry
182
190
  timestamp_buckets.map do |metric_key, metric|
183
191
  type, key, unit, tags = metric_key
184
192
  values = metric.serialize.join(':')
185
- sanitized_tags = tags.map { |k, v| "#{sanitize_key(k)}:#{sanitize_value(v)}" }.join(',')
193
+ sanitized_tags = tags.map { |k, v| "#{sanitize_tag_key(k)}:#{sanitize_tag_value(v)}" }.join(',')
186
194
 
187
- "#{sanitize_key(key)}@#{unit}:#{values}|#{type}|\##{sanitized_tags}|T#{timestamp}"
195
+ "#{sanitize_key(key)}@#{sanitize_unit(unit)}:#{values}|#{type}|\##{sanitized_tags}|T#{timestamp}"
188
196
  end
189
197
  end.flatten.join("\n")
190
198
  end
@@ -192,7 +200,7 @@ module Sentry
192
200
  def serialize_locations(timestamp, locations)
193
201
  mapping = locations.map do |meta_key, location|
194
202
  type, key, unit = meta_key
195
- mri = "#{type}:#{sanitize_key(key)}@#{unit}"
203
+ mri = "#{type}:#{sanitize_key(key)}@#{sanitize_unit(unit)}"
196
204
 
197
205
  # note this needs to be an array but it really doesn't serve a purpose right now
198
206
  [mri, [location.merge(type: 'location')]]
@@ -205,8 +213,16 @@ module Sentry
205
213
  key.gsub(KEY_SANITIZATION_REGEX, '_')
206
214
  end
207
215
 
208
- def sanitize_value(value)
209
- value.gsub(VALUE_SANITIZATION_REGEX, '')
216
+ def sanitize_unit(unit)
217
+ unit.gsub(UNIT_SANITIZATION_REGEX, '')
218
+ end
219
+
220
+ def sanitize_tag_key(key)
221
+ key.gsub(TAG_KEY_SANITIZATION_REGEX, '')
222
+ end
223
+
224
+ def sanitize_tag_value(value)
225
+ value.chars.map { |c| TAG_VALUE_SANITIZATION_MAP[c] || c }.join
210
226
  end
211
227
 
212
228
  def get_transaction_name
@@ -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
 
@@ -88,18 +88,9 @@ module Sentry
88
88
  [data, serialized_items]
89
89
  end
90
90
 
91
- def is_rate_limited?(item_type)
91
+ def is_rate_limited?(data_category)
92
92
  # check category-specific limit
93
- category_delay =
94
- case item_type
95
- when "transaction"
96
- @rate_limits["transaction"]
97
- when "sessions"
98
- @rate_limits["session"]
99
- else
100
- @rate_limits["error"]
101
- end
102
-
93
+ category_delay = @rate_limits[data_category]
103
94
  # check universal limit if not category limit
104
95
  universal_delay = @rate_limits[nil]
105
96
 
@@ -160,11 +151,11 @@ module Sentry
160
151
  envelope
161
152
  end
162
153
 
163
- def record_lost_event(reason, item_type)
154
+ def record_lost_event(reason, data_category)
164
155
  return unless @send_client_reports
165
156
  return unless CLIENT_REPORT_REASONS.include?(reason)
166
157
 
167
- @discarded_events[[reason, item_type]] += 1
158
+ @discarded_events[[reason, data_category]] += 1
168
159
  end
169
160
 
170
161
  def flush
@@ -184,11 +175,7 @@ module Sentry
184
175
  return nil if @discarded_events.empty?
185
176
 
186
177
  discarded_events_hash = @discarded_events.map do |key, val|
187
- reason, type = key
188
-
189
- # 'event' has to be mapped to 'error'
190
- category = type == 'event' ? 'error' : type
191
-
178
+ reason, category = key
192
179
  { reason: reason, category: category, quantity: val }
193
180
  end
194
181
 
@@ -206,9 +193,9 @@ module Sentry
206
193
 
207
194
  def reject_rate_limited_items(envelope)
208
195
  envelope.items.reject! do |item|
209
- if is_rate_limited?(item.type)
196
+ if is_rate_limited?(item.data_category)
210
197
  log_debug("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
211
- record_lost_event(:ratelimit_backoff, item.type)
198
+ record_lost_event(:ratelimit_backoff, item.data_category)
212
199
 
213
200
  true
214
201
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.17.2"
4
+ VERSION = "5.17.3"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -257,7 +257,7 @@ module Sentry
257
257
  end
258
258
 
259
259
  if client = get_current_client
260
- client.transport.flush
260
+ client.flush
261
261
 
262
262
  if client.configuration.include_local_variables
263
263
  exception_locals_tp.disable
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.17.2
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-04-03 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: sentry-ruby
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 5.17.2
19
+ version: 5.17.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 5.17.2
26
+ version: 5.17.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: concurrent-ruby
29
29
  requirement: !ruby/object:Gem::Requirement