sentry-ruby-core 5.1.0 → 5.2.1

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: e8b9d0c43497ccc151613d208b6e9a51489586a41cbb7849cbcfcd3e5795765f
4
- data.tar.gz: 79e7e9f621b2fe8bfc1c1dc292a16392e499925c13bdc1c31c3f8e05240f42e0
3
+ metadata.gz: 896f183ea604d1e6857591eff87175f8bb8a83dd1e40fc3e80982a71dd3abe0e
4
+ data.tar.gz: ffc931b4d436be3c5b1858260a5e2a0508d75455c23d0971bd0f1d2a02f0e178
5
5
  SHA512:
6
- metadata.gz: 3def5710a658f0365dbe11292f548aafcaf6d467d04abd5e0973035c5c3243307d49347b829ae0aa93d459c2bf4036813ec2a4589471c8da21d438318144c0aa
7
- data.tar.gz: 99eab89037a4e468c7bb257d33aaf85ec8830102aa233a9af4c5091c92d67726f4ffab47b3eeedba07f079b4b3600145458e9283274532b534824acd21236617
6
+ metadata.gz: 467c2493df9a8ba98148b1d467d313bfc23defd9b34a9355242b01ed7ac4f092932b19607ad79e16883f83ba9b1fa53b736872f920f4fb0590761fcdbfc12a25
7
+ data.tar.gz: 074c4ac8eff86f456646ceef087433abf38a81ad1e8a3d0cec465caddf5a4e96459ed9c641854f7dba37ac9e851fde8f7e09798f35420f4d12586b89039282d4
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source "https://rubygems.org"
2
+ git_source(:github) { |name| "https://github.com/#{name}.git" }
2
3
 
3
4
  gem "sentry-ruby-core", path: "./"
4
5
  gem "sentry-ruby", path: "./"
@@ -207,6 +207,10 @@ module Sentry
207
207
  # @return [Boolean]
208
208
  attr_accessor :send_client_reports
209
209
 
210
+ # Track sessions in request/response cycles automatically
211
+ # @return [Boolean]
212
+ attr_accessor :auto_session_tracking
213
+
210
214
  # these are not config options
211
215
  # @!visibility private
212
216
  attr_reader :errors, :gem_specs
@@ -261,6 +265,7 @@ module Sentry
261
265
  self.send_default_pii = false
262
266
  self.skip_rake_integration = false
263
267
  self.send_client_reports = true
268
+ self.auto_session_tracking = true
264
269
  self.trusted_proxies = []
265
270
  self.dsn = ENV['SENTRY_DSN']
266
271
  self.server_name = server_name_from_env
@@ -3,24 +3,43 @@
3
3
  module Sentry
4
4
  # @api private
5
5
  class Envelope
6
- def initialize(headers)
6
+ class Item
7
+ attr_accessor :headers, :payload
8
+
9
+ def initialize(headers, payload)
10
+ @headers = headers
11
+ @payload = payload
12
+ end
13
+
14
+ def type
15
+ @headers[:type] || 'event'
16
+ end
17
+
18
+ def to_s
19
+ <<~ITEM
20
+ #{JSON.generate(@headers)}
21
+ #{JSON.generate(@payload)}
22
+ ITEM
23
+ end
24
+ end
25
+
26
+ attr_accessor :headers, :items
27
+
28
+ def initialize(headers = {})
7
29
  @headers = headers
8
30
  @items = []
9
31
  end
10
32
 
11
33
  def add_item(headers, payload)
12
- @items << [headers, payload]
34
+ @items << Item.new(headers, payload)
13
35
  end
14
36
 
15
- def to_s
16
- payload = @items.map do |item_headers, item_payload|
17
- <<~ENVELOPE
18
- #{JSON.generate(item_headers)}
19
- #{JSON.generate(item_payload)}
20
- ENVELOPE
21
- end.join("\n")
37
+ def item_types
38
+ @items.map(&:type)
39
+ end
22
40
 
23
- "#{JSON.generate(@headers)}\n#{payload}"
41
+ def event_id
42
+ @headers[:event_id]
24
43
  end
25
44
  end
26
45
  end
data/lib/sentry/event.rb CHANGED
@@ -23,6 +23,7 @@ module Sentry
23
23
  WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i(type timestamp level)
24
24
 
25
25
  MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
26
+ MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 200
26
27
 
27
28
  SKIP_INSPECTION_ATTRIBUTES = [:@modules, :@stacktrace_builder, :@send_default_pii, :@trusted_proxies, :@rack_env_whitelist]
28
29
 
data/lib/sentry/hub.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "sentry/scope"
4
4
  require "sentry/client"
5
+ require "sentry/session"
5
6
 
6
7
  module Sentry
7
8
  class Hub
@@ -94,6 +95,8 @@ module Sentry
94
95
  def capture_exception(exception, **options, &block)
95
96
  check_argument_type!(exception, ::Exception)
96
97
 
98
+ return if Sentry.exception_captured?(exception)
99
+
97
100
  return unless current_client
98
101
 
99
102
  options[:hint] ||= {}
@@ -102,9 +105,11 @@ module Sentry
102
105
 
103
106
  return unless event
104
107
 
108
+ current_scope.session&.update_from_exception(event.exception)
109
+
105
110
  capture_event(event, **options, &block).tap do
106
111
  # mark the exception as captured so we can use this information to avoid duplicated capturing
107
- exception.instance_variable_set(:@__sentry_captured, true)
112
+ exception.instance_variable_set(Sentry::CAPTURED_SIGNATURE, true)
108
113
  end
109
114
  end
110
115
 
@@ -141,7 +146,6 @@ module Sentry
141
146
 
142
147
  event = current_client.capture_event(event, scope, hint)
143
148
 
144
-
145
149
  if event && configuration.debug
146
150
  configuration.log_debug(event.to_json_compatible)
147
151
  end
@@ -173,6 +177,30 @@ module Sentry
173
177
  configuration.background_worker_threads = original_background_worker_threads
174
178
  end
175
179
 
180
+ def start_session
181
+ return unless current_scope
182
+ current_scope.set_session(Session.new)
183
+ end
184
+
185
+ def end_session
186
+ return unless current_scope
187
+ session = current_scope.session
188
+ current_scope.set_session(nil)
189
+
190
+ return unless session
191
+ session.close
192
+ Sentry.session_flusher.add_session(session)
193
+ end
194
+
195
+ def with_session_tracking(&block)
196
+ return yield unless configuration.auto_session_tracking
197
+
198
+ start_session
199
+ yield
200
+ ensure
201
+ end_session
202
+ end
203
+
176
204
  private
177
205
 
178
206
  def current_layer
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "set"
2
3
 
3
4
  module Sentry
4
5
  class ExceptionInterface < Interface
@@ -14,30 +14,32 @@ module Sentry
14
14
  Sentry.clone_hub_to_current_thread
15
15
 
16
16
  Sentry.with_scope do |scope|
17
- scope.clear_breadcrumbs
18
- scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
19
- scope.set_rack_env(env)
20
-
21
- transaction = start_transaction(env, scope)
22
- scope.set_span(transaction) if transaction
23
-
24
- begin
25
- response = @app.call(env)
26
- rescue Sentry::Error
27
- finish_transaction(transaction, 500)
28
- raise # Don't capture Sentry errors
29
- rescue Exception => e
30
- capture_exception(e)
31
- finish_transaction(transaction, 500)
32
- raise
17
+ Sentry.with_session_tracking do
18
+ scope.clear_breadcrumbs
19
+ scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
20
+ scope.set_rack_env(env)
21
+
22
+ transaction = start_transaction(env, scope)
23
+ scope.set_span(transaction) if transaction
24
+
25
+ begin
26
+ response = @app.call(env)
27
+ rescue Sentry::Error
28
+ finish_transaction(transaction, 500)
29
+ raise # Don't capture Sentry errors
30
+ rescue Exception => e
31
+ capture_exception(e)
32
+ finish_transaction(transaction, 500)
33
+ raise
34
+ end
35
+
36
+ exception = collect_exception(env)
37
+ capture_exception(exception) if exception
38
+
39
+ finish_transaction(transaction, response[0])
40
+
41
+ response
33
42
  end
34
-
35
- exception = collect_exception(env)
36
- capture_exception(exception) if exception
37
-
38
- finish_transaction(transaction, response[0])
39
-
40
- response
41
43
  end
42
44
  end
43
45
 
@@ -59,7 +61,7 @@ module Sentry
59
61
  sentry_trace = env["HTTP_SENTRY_TRACE"]
60
62
  options = { name: scope.transaction_name, op: transaction_op }
61
63
  transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, **options) if sentry_trace
62
- Sentry.start_transaction(transaction: transaction, **options)
64
+ Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
63
65
  end
64
66
 
65
67
 
data/lib/sentry/redis.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  module Sentry
4
4
  # @api private
5
5
  class Redis
6
- OP_NAME ||= "db.redis.command"
7
- LOGGER_NAME ||= :redis_logger
6
+ OP_NAME = "db.redis.command"
7
+ LOGGER_NAME = :redis_logger
8
8
 
9
9
  def initialize(commands, host, port, db)
10
10
  @commands, @host, @port, @db = commands, host, port, db
@@ -60,9 +60,11 @@ module Sentry
60
60
 
61
61
  def parsed_commands
62
62
  commands.map do |statement|
63
- command, key, *_values = statement
63
+ command, key, *arguments = statement
64
64
 
65
- { command: command.to_s.upcase, key: key }
65
+ { command: command.to_s.upcase, key: key }.tap do |command_set|
66
+ command_set[:arguments] = arguments.join(" ") if Sentry.configuration.send_default_pii
67
+ end
66
68
  end
67
69
  end
68
70
 
data/lib/sentry/scope.rb CHANGED
@@ -7,7 +7,7 @@ module Sentry
7
7
  class Scope
8
8
  include ArgumentCheckingHelper
9
9
 
10
- ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env, :span]
10
+ ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env, :span, :session]
11
11
 
12
12
  attr_reader(*ATTRIBUTES)
13
13
 
@@ -76,6 +76,7 @@ module Sentry
76
76
  copy.transaction_names = transaction_names.deep_dup
77
77
  copy.fingerprint = fingerprint.deep_dup
78
78
  copy.span = span.deep_dup
79
+ copy.session = session.deep_dup
79
80
  copy
80
81
  end
81
82
 
@@ -173,7 +174,7 @@ module Sentry
173
174
  def set_contexts(contexts_hash)
174
175
  check_argument_type!(contexts_hash, Hash)
175
176
  @contexts.merge!(contexts_hash) do |key, old, new|
176
- new.merge(old)
177
+ old.merge(new)
177
178
  end
178
179
  end
179
180
 
@@ -198,6 +199,13 @@ module Sentry
198
199
  @transaction_names << transaction_name
199
200
  end
200
201
 
202
+ # Sets the currently active session on the scope.
203
+ # @param session [Session, nil]
204
+ # @return [void]
205
+ def set_session(session)
206
+ @session = session
207
+ end
208
+
201
209
  # Returns current transaction name.
202
210
  # The "transaction" here does not refer to `Transaction` objects.
203
211
  # @return [String, nil]
@@ -251,6 +259,7 @@ module Sentry
251
259
  @event_processors = []
252
260
  @rack_env = {}
253
261
  @span = nil
262
+ @session = nil
254
263
  set_new_breadcrumb_buffer
255
264
  end
256
265
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class Session
5
+ attr_reader :started, :status
6
+
7
+ # TODO-neel add :crashed after adding handled mechanism
8
+ STATUSES = %i(ok errored exited)
9
+ AGGREGATE_STATUSES = %i(errored exited)
10
+
11
+ def initialize
12
+ @started = Sentry.utc_now
13
+ @status = :ok
14
+ end
15
+
16
+ # TODO-neel add :crashed after adding handled mechanism
17
+ def update_from_exception(_exception = nil)
18
+ @status = :errored
19
+ end
20
+
21
+ def close
22
+ @status = :exited if @status == :ok
23
+ end
24
+
25
+ # truncate seconds from the timestamp since we only care about
26
+ # minute level granularity for aggregation
27
+ def aggregation_key
28
+ Time.utc(started.year, started.month, started.day, started.hour, started.min)
29
+ end
30
+
31
+ def deep_dup
32
+ dup
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class SessionFlusher
5
+ include LoggingHelper
6
+
7
+ FLUSH_INTERVAL = 60
8
+
9
+ def initialize(configuration, client)
10
+ @thread = nil
11
+ @client = client
12
+ @pending_aggregates = {}
13
+ @release = configuration.release
14
+ @environment = configuration.environment
15
+ @logger = configuration.logger
16
+
17
+ log_debug("[Sessions] Sessions won't be captured without a valid release") unless @release
18
+ end
19
+
20
+ def flush
21
+ return if @pending_aggregates.empty?
22
+ envelope = pending_envelope
23
+
24
+ Sentry.background_worker.perform do
25
+ @client.transport.send_envelope(envelope)
26
+ end
27
+
28
+ @pending_aggregates = {}
29
+ end
30
+
31
+ def add_session(session)
32
+ return unless @release
33
+
34
+ ensure_thread
35
+
36
+ return unless Session::AGGREGATE_STATUSES.include?(session.status)
37
+ @pending_aggregates[session.aggregation_key] ||= init_aggregates(session.aggregation_key)
38
+ @pending_aggregates[session.aggregation_key][session.status] += 1
39
+ end
40
+
41
+ def kill
42
+ @thread&.kill
43
+ end
44
+
45
+ private
46
+
47
+ def init_aggregates(aggregation_key)
48
+ aggregates = { started: aggregation_key.iso8601 }
49
+ Session::AGGREGATE_STATUSES.each { |k| aggregates[k] = 0 }
50
+ aggregates
51
+ end
52
+
53
+ def pending_envelope
54
+ envelope = Envelope.new
55
+
56
+ header = { type: 'sessions' }
57
+ payload = { attrs: attrs, aggregates: @pending_aggregates.values }
58
+
59
+ envelope.add_item(header, payload)
60
+ envelope
61
+ end
62
+
63
+ def attrs
64
+ { release: @release, environment: @environment }
65
+ end
66
+
67
+ def ensure_thread
68
+ return if @thread&.alive?
69
+
70
+ @thread = Thread.new do
71
+ loop do
72
+ sleep(FLUSH_INTERVAL)
73
+ flush
74
+ end
75
+ end
76
+ end
77
+
78
+ end
79
+ end
@@ -25,6 +25,7 @@ module Sentry
25
25
  def initialize(configuration:, integration_meta: nil, message: nil)
26
26
  super
27
27
  @type = TYPE
28
+ self.level = nil
28
29
  end
29
30
 
30
31
  # Sets the event's start_timestamp.
@@ -2,15 +2,20 @@
2
2
 
3
3
  module Sentry
4
4
  class DummyTransport < Transport
5
- attr_accessor :events
5
+ attr_accessor :events, :envelopes
6
6
 
7
7
  def initialize(*)
8
8
  super
9
9
  @events = []
10
+ @envelopes = []
10
11
  end
11
12
 
12
13
  def send_event(event)
13
14
  @events << event
14
15
  end
16
+
17
+ def send_envelope(envelope)
18
+ @envelopes << envelope
19
+ end
15
20
  end
16
21
  end
@@ -46,23 +46,59 @@ module Sentry
46
46
  end
47
47
 
48
48
  def send_event(event)
49
- event_hash = event.to_hash
50
- item_type = get_item_type(event_hash)
49
+ envelope = envelope_from_event(event)
50
+ send_envelope(envelope)
51
51
 
52
- if is_rate_limited?(item_type)
53
- log_info("Envelope [#{item_type}] not sent: rate limiting")
54
- record_lost_event(:ratelimit_backoff, item_type)
52
+ event
53
+ end
54
+
55
+ def send_envelope(envelope)
56
+ reject_rate_limited_items(envelope)
55
57
 
56
- return
58
+ return if envelope.items.empty?
59
+
60
+ data, serialized_items = serialize_envelope(envelope)
61
+
62
+ if data
63
+ log_info("[Transport] Sending envelope with items [#{serialized_items.map(&:type).join(', ')}] #{envelope.event_id} to Sentry")
64
+ send_data(data)
57
65
  end
66
+ end
58
67
 
59
- encoded_data = encode(event)
68
+ def serialize_envelope(envelope)
69
+ serialized_items = []
70
+ serialized_results = []
60
71
 
61
- return nil unless encoded_data
72
+ envelope.items.each do |item|
73
+ result = item.to_s
62
74
 
63
- send_data(encoded_data)
75
+ if result.bytesize > Event::MAX_SERIALIZED_PAYLOAD_SIZE
76
+ if item.payload.key?(:breadcrumbs)
77
+ item.payload.delete(:breadcrumbs)
78
+ elsif item.payload.key?("breadcrumbs")
79
+ item.payload.delete("breadcrumbs")
80
+ end
64
81
 
65
- event
82
+ result = item.to_s
83
+ end
84
+
85
+ if result.bytesize > Event::MAX_SERIALIZED_PAYLOAD_SIZE
86
+ size_breakdown = item.payload.map do |key, value|
87
+ "#{key}: #{JSON.generate(value).bytesize}"
88
+ end.join(", ")
89
+
90
+ log_debug("Envelope item [#{item.type}] is still oversized without breadcrumbs: {#{size_breakdown}}")
91
+
92
+ next
93
+ end
94
+
95
+ serialized_results << result
96
+ serialized_items << item
97
+ end
98
+
99
+ data = [JSON.generate(envelope.headers), *serialized_results].join("\n") unless serialized_results.empty?
100
+
101
+ [data, serialized_items]
66
102
  end
67
103
 
68
104
  def is_rate_limited?(item_type)
@@ -71,6 +107,8 @@ module Sentry
71
107
  case item_type
72
108
  when "transaction"
73
109
  @rate_limits["transaction"]
110
+ when "sessions"
111
+ @rate_limits["session"]
74
112
  else
75
113
  @rate_limits["error"]
76
114
  end
@@ -106,7 +144,7 @@ module Sentry
106
144
  'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
107
145
  end
108
146
 
109
- def encode(event)
147
+ def envelope_from_event(event)
110
148
  # Convert to hash
111
149
  event_payload = event.to_hash
112
150
  event_id = event_payload[:event_id] || event_payload["event_id"]
@@ -129,9 +167,7 @@ module Sentry
129
167
  client_report_headers, client_report_payload = fetch_pending_client_report
130
168
  envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
131
169
 
132
- log_info("Sending envelope [#{item_type}] #{event_id} to Sentry")
133
-
134
- envelope.to_s
170
+ envelope
135
171
  end
136
172
 
137
173
  def record_lost_event(reason, item_type)
@@ -173,6 +209,19 @@ module Sentry
173
209
 
174
210
  [item_header, item_payload]
175
211
  end
212
+
213
+ def reject_rate_limited_items(envelope)
214
+ envelope.items.reject! do |item|
215
+ if is_rate_limited?(item.type)
216
+ log_info("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
217
+ record_lost_event(:ratelimit_backoff, item.type)
218
+
219
+ true
220
+ else
221
+ false
222
+ end
223
+ end
224
+ end
176
225
  end
177
226
  end
178
227
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.1.0"
4
+ VERSION = "5.2.1"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -17,6 +17,7 @@ require "sentry/span"
17
17
  require "sentry/transaction"
18
18
  require "sentry/hub"
19
19
  require "sentry/background_worker"
20
+ require "sentry/session_flusher"
20
21
 
21
22
  [
22
23
  "sentry/rake",
@@ -31,6 +32,8 @@ end
31
32
  module Sentry
32
33
  META = { "name" => "sentry.ruby", "version" => Sentry::VERSION }.freeze
33
34
 
35
+ CAPTURED_SIGNATURE = :@__sentry_captured
36
+
34
37
  LOGGER_PROGNAME = "sentry".freeze
35
38
 
36
39
  SENTRY_TRACE_HEADER_NAME = "sentry-trace".freeze
@@ -59,6 +62,10 @@ module Sentry
59
62
  # @return [BackgroundWorker]
60
63
  attr_accessor :background_worker
61
64
 
65
+ # @!attribute [r] session_flusher
66
+ # @return [SessionFlusher]
67
+ attr_reader :session_flusher
68
+
62
69
  ##### Patch Registration #####
63
70
 
64
71
  # @!visibility private
@@ -92,6 +99,14 @@ module Sentry
92
99
  # @param name [String] name of the integration
93
100
  # @param version [String] version of the integration
94
101
  def register_integration(name, version)
102
+ if initialized?
103
+ logger.warn(LOGGER_PROGNAME) do
104
+ <<~MSG
105
+ Integration '#{name}' is loaded after the SDK is initialized, which can cause expected behavior. Please make sure all integrations are loaded before SDK initialization.
106
+ MSG
107
+ end
108
+ end
109
+
95
110
  meta = { name: "sentry.ruby.#{name}", version: version }.freeze
96
111
  integrations[name.to_s] = meta
97
112
  end
@@ -187,11 +202,18 @@ module Sentry
187
202
  @main_hub = hub
188
203
  @background_worker = Sentry::BackgroundWorker.new(config)
189
204
 
205
+ @session_flusher = if config.auto_session_tracking
206
+ Sentry::SessionFlusher.new(config, client)
207
+ else
208
+ nil
209
+ end
210
+
190
211
  if config.capture_exception_frame_locals
191
212
  exception_locals_tp.enable
192
213
  end
193
214
 
194
215
  at_exit do
216
+ @session_flusher&.kill
195
217
  @background_worker.shutdown
196
218
  end
197
219
  end
@@ -308,6 +330,26 @@ module Sentry
308
330
  get_current_hub.with_scope(&block)
309
331
  end
310
332
 
333
+ # Wrap a given block with session tracking.
334
+ # Aggregate sessions in minutely buckets will be recorded
335
+ # around this block and flushed every minute.
336
+ #
337
+ # @example
338
+ # Sentry.with_session_tracking do
339
+ # a = 1 + 1 # new session recorded with :exited status
340
+ # end
341
+ #
342
+ # Sentry.with_session_tracking do
343
+ # 1 / 0
344
+ # rescue => e
345
+ # Sentry.capture_exception(e) # new session recorded with :errored status
346
+ # end
347
+ # @return [void]
348
+ def with_session_tracking(&block)
349
+ return yield unless initialized?
350
+ get_current_hub.with_session_tracking(&block)
351
+ end
352
+
311
353
  # Takes an exception and reports it to Sentry via the currently active hub.
312
354
  #
313
355
  # @yieldparam scope [Scope]
@@ -350,6 +392,13 @@ module Sentry
350
392
  get_current_hub.last_event_id
351
393
  end
352
394
 
395
+ # Checks if the exception object has been captured by the SDK.
396
+ #
397
+ # @return [Boolean]
398
+ def exception_captured?(exc)
399
+ return false unless initialized?
400
+ !!exc.instance_variable_get(CAPTURED_SIGNATURE)
401
+ end
353
402
 
354
403
  ##### Helpers #####
355
404
 
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.1.0
4
+ version: 5.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-10 00:00:00.000000000 Z
11
+ date: 2022-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -76,6 +76,8 @@ files:
76
76
  - lib/sentry/redis.rb
77
77
  - lib/sentry/release_detector.rb
78
78
  - lib/sentry/scope.rb
79
+ - lib/sentry/session.rb
80
+ - lib/sentry/session_flusher.rb
79
81
  - lib/sentry/span.rb
80
82
  - lib/sentry/transaction.rb
81
83
  - lib/sentry/transaction_event.rb