sentry-ruby 7.1.0 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/gemfiles/ruby-2.7_rack-2_redis-4.gemfile.lock +19 -7
  4. data/gemfiles/ruby-2.7_rack-3.1_redis-4.gemfile.lock +19 -7
  5. data/gemfiles/ruby-2.7_rack-3_redis-4.gemfile.lock +19 -7
  6. data/gemfiles/ruby-3.0_rack-2_redis-4.gemfile.lock +28 -12
  7. data/gemfiles/ruby-3.0_rack-3.1_redis-4.gemfile.lock +28 -12
  8. data/gemfiles/ruby-3.0_rack-3_redis-4.gemfile.lock +28 -12
  9. data/gemfiles/ruby-3.1_rack-2_redis-4.gemfile.lock +46 -23
  10. data/gemfiles/ruby-3.1_rack-3.1_redis-4.gemfile.lock +46 -23
  11. data/gemfiles/ruby-3.1_rack-3_redis-4.gemfile.lock +46 -23
  12. data/gemfiles/ruby-3.2_rack-0_redis-5.gemfile.lock +50 -27
  13. data/gemfiles/ruby-3.2_rack-2_redis-4.gemfile.lock +48 -25
  14. data/gemfiles/ruby-3.2_rack-2_redis-5.gemfile.lock +50 -27
  15. data/gemfiles/ruby-3.2_rack-3.1_redis-4.gemfile.lock +48 -25
  16. data/gemfiles/ruby-3.2_rack-3_redis-4.gemfile.lock +48 -25
  17. data/gemfiles/ruby-3.2_rack-3_redis-5.gemfile.lock +50 -27
  18. data/gemfiles/ruby-3.3_rack-2_redis-4.gemfile.lock +52 -29
  19. data/gemfiles/ruby-3.3_rack-3.1_redis-4.gemfile.lock +52 -29
  20. data/gemfiles/ruby-3.3_rack-3.1_redis-5.3.gemfile.lock +54 -31
  21. data/gemfiles/ruby-3.3_rack-3_redis-4.gemfile.lock +52 -29
  22. data/gemfiles/ruby-3.4_rack-2_redis-4.gemfile.lock +52 -29
  23. data/gemfiles/ruby-3.4_rack-3.1_redis-4.gemfile.lock +52 -29
  24. data/gemfiles/ruby-3.4_rack-3.1_redis-5.3.gemfile.lock +54 -31
  25. data/gemfiles/ruby-3.4_rack-3_redis-4.gemfile.lock +52 -29
  26. data/gemfiles/ruby-4.0_rack-2_redis-4.gemfile.lock +52 -29
  27. data/gemfiles/ruby-4.0_rack-3.1_redis-4.gemfile.lock +52 -29
  28. data/gemfiles/ruby-4.0_rack-3_redis-4.gemfile.lock +52 -29
  29. data/gemfiles/ruby-jruby-9.4.14.0_rack-2_redis-4.gemfile.lock +53 -35
  30. data/gemfiles/ruby-jruby-9.4.14.0_rack-3.1_redis-4.gemfile.lock +53 -35
  31. data/gemfiles/ruby-jruby-9.4.14.0_rack-3_redis-4.gemfile.lock +53 -35
  32. data/lib/sentry/configuration.rb +7 -2
  33. data/lib/sentry/cron/fugit_schedule.rb +117 -0
  34. data/lib/sentry/cron/monitor_check_ins.rb +33 -27
  35. data/lib/sentry/cron/slug.rb +18 -0
  36. data/lib/sentry/data_collection.rb +6 -1
  37. data/lib/sentry/rufus_scheduler.rb +120 -0
  38. data/lib/sentry/transport/debug_transport.rb +11 -2
  39. data/lib/sentry/transport/dummy_transport.rb +7 -4
  40. data/lib/sentry/transport/spotlight_transport.rb +2 -2
  41. data/lib/sentry/version.rb +1 -1
  42. data/lib/sentry-ruby.rb +3 -0
  43. metadata +9 -6
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ module Cron
5
+ module Slug
6
+ module_function
7
+
8
+ # Returns nil when nothing usable is left.
9
+ def from(name)
10
+ slug = name.to_s.downcase.gsub(/[^a-z0-9_-]+/, "-").sub(/\A-+/, "")
11
+ slug = slug[0, MonitorCheckIns::MAX_SLUG_LENGTH]
12
+ # rindex instead of /-+\z/, which backtracks on long runs of dashes.
13
+ last = slug.rindex(/[^-]/)
14
+ last && slug[0..last]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -131,6 +131,7 @@ module Sentry
131
131
  def self.backfill(configuration)
132
132
  data_collection = new
133
133
  data_collection.backfill_stack_frame_variables(configuration)
134
+ data_collection.backfill_frame_context_lines(configuration)
134
135
  return data_collection if configuration.send_default_pii
135
136
 
136
137
  # TODO-neel-data map to exact ruby behaviour for backwards compat behavior
@@ -146,7 +147,6 @@ module Sentry
146
147
  data_collection.graphql.variables = false
147
148
  data_collection.database_query_data = false
148
149
  data_collection.queues = false
149
- data_collection.frame_context_lines = configuration.context_lines
150
150
  data_collection
151
151
  end
152
152
 
@@ -171,6 +171,11 @@ module Sentry
171
171
  self.stack_frame_variables = configuration.include_local_variables
172
172
  end
173
173
 
174
+ # Copies the legacy context_lines configuration.
175
+ def backfill_frame_context_lines(configuration)
176
+ self.frame_context_lines = configuration.context_lines
177
+ end
178
+
174
179
  # Returns whether stack frame local variables should be captured.
175
180
  def collect_stack_frame_variables?
176
181
  stack_frame_variables.mode != :off
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # Sends Crons check-ins for rufus-scheduler `cron`, `every` and `interval` jobs.
5
+ # Enable with `config.enabled_patches << :rufus_scheduler`.
6
+ module RufusScheduler
7
+ module Job
8
+ protected
9
+
10
+ def do_call(time, do_rescue)
11
+ return super unless Sentry.initialized? && (monitor = sentry_monitor)
12
+
13
+ slug, monitor_config = monitor
14
+ check_in_id = Sentry.capture_check_in(slug, :in_progress, monitor_config: monitor_config)
15
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
16
+
17
+ begin
18
+ # Run without rufus's rescue so the error is seen, then handle it like Job#do_call.
19
+ ret = super(time, false)
20
+ rescue Exception => e
21
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
22
+ Sentry.capture_check_in(slug, :error, check_in_id: check_in_id, duration: duration, monitor_config: monitor_config)
23
+
24
+ raise unless do_rescue && e.is_a?(StandardError)
25
+ return if e.is_a?(::Rufus::Scheduler::Job::KillSignal)
26
+
27
+ return @scheduler.on_error(self, e)
28
+ end
29
+
30
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
31
+ Sentry.capture_check_in(slug, :ok, check_in_id: check_in_id, duration: duration, monitor_config: monitor_config)
32
+
33
+ ret
34
+ end
35
+
36
+ private
37
+
38
+ def sentry_monitor
39
+ return @sentry_monitor if defined?(@sentry_monitor)
40
+
41
+ @sentry_monitor = Sentry::RufusScheduler.monitor_for(self)
42
+ rescue StandardError => e
43
+ Sentry.sdk_logger.error(Sentry::LOGGER_PROGNAME) { "Not monitoring rufus-scheduler job #{id}: #{e.class}: #{e.message}" }
44
+ @sentry_monitor = nil
45
+ end
46
+ end
47
+
48
+ class << self
49
+ # Returns [slug, monitor_config], or nil for jobs that aren't monitored (like `at`/`in`).
50
+ def monitor_for(job)
51
+ return unless job.is_a?(::Rufus::Scheduler::RepeatJob)
52
+ return if job.opts[:sentry_monitor] == false
53
+ return if sidekiq_scheduler_job?(job)
54
+
55
+ slug = slug_for(job)
56
+ unless slug
57
+ Sentry.sdk_logger.warn(Sentry::LOGGER_PROGNAME) do
58
+ "Not monitoring rufus-scheduler job #{job.id} at #{job.source_location&.join(":")}: " \
59
+ "pass `name:` to give it a stable monitor slug."
60
+ end
61
+ return
62
+ end
63
+
64
+ [slug, monitor_config_for(job)]
65
+ end
66
+
67
+ private
68
+
69
+ # sidekiq-scheduler jobs are monitored by the :sidekiq_scheduler patch.
70
+ def sidekiq_scheduler_job?(job)
71
+ file, _ = job.callable.source_location if job.callable.respond_to?(:source_location)
72
+ file&.end_with?("sidekiq-scheduler/scheduler.rb")
73
+ end
74
+
75
+ # Job ids are random per process and block paths change between deploys,
76
+ # so the slug comes from `name:`, then the handler method or class.
77
+ def slug_for(job)
78
+ handler = job.handler
79
+ source =
80
+ if job.name
81
+ job.name.to_s
82
+ elsif handler.is_a?(Method)
83
+ # The receiver's class, not the method owner, so inherited and mixin methods get distinct slugs.
84
+ namespace = handler.receiver.is_a?(Module) ? handler.receiver : handler.receiver.class
85
+ [namespace == Object ? nil : namespace.name, handler.name].compact.join("::")
86
+ elsif !handler.is_a?(Proc)
87
+ handler.class.name
88
+ end
89
+ return unless source
90
+
91
+ Sentry::Cron::Slug.from(source)
92
+ end
93
+
94
+ def monitor_config_for(job)
95
+ case job
96
+ when ::Rufus::Scheduler::CronJob
97
+ Sentry::Cron::FugitSchedule.from_cron(job.cron_line)
98
+ when ::Rufus::Scheduler::EveryJob
99
+ Sentry::Cron::FugitSchedule.from_seconds(job.frequency)
100
+ end
101
+ # IntervalJob waits `interval` after each run ends, so it has no fixed
102
+ # schedule to monitor against.
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ Sentry.register_patch(:rufus_scheduler) do |config|
109
+ # Load rufus-scheduler in case it's required after Sentry.init.
110
+ begin
111
+ require "rufus-scheduler"
112
+ rescue LoadError
113
+ end
114
+
115
+ if defined?(::Rufus::Scheduler::RepeatJob)
116
+ ::Rufus::Scheduler::Job.prepend(Sentry::RufusScheduler::Job) unless ::Rufus::Scheduler::Job.ancestors.include?(Sentry::RufusScheduler::Job)
117
+ else
118
+ config.sdk_logger.warn(Sentry::LOGGER_PROGNAME) { "You tried to enable the rufus-scheduler integration but the `rufus-scheduler` gem was not detected." }
119
+ end
120
+ end
@@ -27,6 +27,11 @@ module Sentry
27
27
  backend.send_event(event)
28
28
  end
29
29
 
30
+ def send_envelope(envelope)
31
+ log_envelope(envelope)
32
+ backend.send_envelope(envelope)
33
+ end
34
+
30
35
  def log_envelope(envelope)
31
36
  envelope_json = {
32
37
  timestamp: Time.now.utc.iso8601,
@@ -36,13 +41,13 @@ module Sentry
36
41
  end
37
42
  }
38
43
 
39
- File.open(log_file, "a") { |file| file << JSON.dump(envelope_json) << "\n" }
44
+ File.open(log_file, "a") { |file| file.write("#{JSON.dump(envelope_json)}\n") }
40
45
  end
41
46
 
42
47
  def logged_envelopes
43
48
  return [] unless File.exist?(log_file)
44
49
 
45
- File.readlines(log_file).map do |line|
50
+ File.readlines(log_file).select { |line| fully_written?(line) }.map do |line|
46
51
  JSON.parse(line)
47
52
  end
48
53
  end
@@ -54,6 +59,10 @@ module Sentry
54
59
 
55
60
  private
56
61
 
62
+ def fully_written?(line)
63
+ line.end_with?("\n")
64
+ end
65
+
57
66
  def initialize_backend(configuration)
58
67
  backend = configuration.dsn.local? ? DummyTransport : HTTPTransport
59
68
  backend.new(configuration)
@@ -8,22 +8,25 @@ module Sentry
8
8
  super
9
9
  @events = []
10
10
  @envelopes = []
11
+ @mutex = Mutex.new
11
12
  end
12
13
 
13
14
  def send_event(event)
14
- @events << event
15
+ @mutex.synchronize { @events << event }
15
16
  super
16
17
  end
17
18
 
18
19
  def send_envelope(envelope)
19
- @envelopes << envelope
20
+ @mutex.synchronize { @envelopes << envelope }
20
21
  end
21
22
 
22
23
  # Empties the captured events and envelopes so `TestHelper.clear_sentry_events`
23
24
  # also clears the dummy transport instance
24
25
  def clear
25
- @events.clear
26
- @envelopes.clear
26
+ @mutex.synchronize do
27
+ @events.clear
28
+ @envelopes.clear
29
+ end
27
30
  end
28
31
  end
29
32
  end
@@ -39,11 +39,11 @@ module Sentry
39
39
  @failed += 1
40
40
  end
41
41
 
42
- # Similar to HTTPTransport connection, but does not support Proxy and SSL
42
+ # Similar to HTTPTransport connection, but does not support Proxy
43
43
  def conn
44
44
  sidecar = URI(@sidecar_url)
45
45
  connection = ::Net::HTTP.new(sidecar.hostname, sidecar.port, nil)
46
- connection.use_ssl = false
46
+ connection.use_ssl = sidecar.scheme == "https"
47
47
  connection
48
48
  end
49
49
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "7.1.0"
4
+ VERSION = "7.2.0"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -27,6 +27,8 @@ require "sentry/threaded_periodic_worker"
27
27
  require "sentry/session_flusher"
28
28
  require "sentry/backpressure_monitor"
29
29
  require "sentry/cron/monitor_check_ins"
30
+ require "sentry/cron/fugit_schedule"
31
+ require "sentry/cron/slug"
30
32
  require "sentry/vernier/profiler"
31
33
  require "sentry/metrics"
32
34
 
@@ -793,3 +795,4 @@ require "sentry/graphql"
793
795
  require "sentry/faraday"
794
796
  require "sentry/excon"
795
797
  require "sentry/std_lib_logger"
798
+ require "sentry/rufus_scheduler"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.0
4
+ version: 7.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
@@ -122,9 +122,11 @@ files:
122
122
  - lib/sentry/core_ext/object/deep_dup.rb
123
123
  - lib/sentry/core_ext/object/duplicable.rb
124
124
  - lib/sentry/cron/configuration.rb
125
+ - lib/sentry/cron/fugit_schedule.rb
125
126
  - lib/sentry/cron/monitor_check_ins.rb
126
127
  - lib/sentry/cron/monitor_config.rb
127
128
  - lib/sentry/cron/monitor_schedule.rb
129
+ - lib/sentry/cron/slug.rb
128
130
  - lib/sentry/data_collection.rb
129
131
  - lib/sentry/data_collection/key_value_collection.rb
130
132
  - lib/sentry/debug_structured_logger.rb
@@ -166,6 +168,7 @@ files:
166
168
  - lib/sentry/redis.rb
167
169
  - lib/sentry/release_detector.rb
168
170
  - lib/sentry/rspec.rb
171
+ - lib/sentry/rufus_scheduler.rb
169
172
  - lib/sentry/scope.rb
170
173
  - lib/sentry/sequel.rb
171
174
  - lib/sentry/session.rb
@@ -203,15 +206,15 @@ files:
203
206
  - lib/sentry/version.rb
204
207
  - sentry-ruby-core.gemspec
205
208
  - sentry-ruby.gemspec
206
- homepage: https://github.com/getsentry/sentry-ruby/tree/7.1.0/sentry-ruby
209
+ homepage: https://github.com/getsentry/sentry-ruby/tree/7.2.0/sentry-ruby
207
210
  licenses:
208
211
  - MIT
209
212
  metadata:
210
- homepage_uri: https://github.com/getsentry/sentry-ruby/tree/7.1.0/sentry-ruby
211
- source_code_uri: https://github.com/getsentry/sentry-ruby/tree/7.1.0/sentry-ruby
212
- changelog_uri: https://github.com/getsentry/sentry-ruby/blob/7.1.0/CHANGELOG.md
213
+ homepage_uri: https://github.com/getsentry/sentry-ruby/tree/7.2.0/sentry-ruby
214
+ source_code_uri: https://github.com/getsentry/sentry-ruby/tree/7.2.0/sentry-ruby
215
+ changelog_uri: https://github.com/getsentry/sentry-ruby/blob/7.2.0/CHANGELOG.md
213
216
  bug_tracker_uri: https://github.com/getsentry/sentry-ruby/issues
214
- documentation_uri: http://www.rubydoc.info/gems/sentry-ruby/7.1.0
217
+ documentation_uri: http://www.rubydoc.info/gems/sentry-ruby/7.2.0
215
218
  rdoc_options: []
216
219
  require_paths:
217
220
  - lib