sentry-ruby 5.26.0 → 6.3.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +26 -4
  3. data/README.md +2 -2
  4. data/lib/sentry/background_worker.rb +1 -4
  5. data/lib/sentry/backtrace/line.rb +99 -0
  6. data/lib/sentry/backtrace.rb +44 -76
  7. data/lib/sentry/breadcrumb.rb +1 -1
  8. data/lib/sentry/breadcrumb_buffer.rb +2 -2
  9. data/lib/sentry/check_in_event.rb +2 -2
  10. data/lib/sentry/client.rb +59 -136
  11. data/lib/sentry/configuration.rb +168 -78
  12. data/lib/sentry/cron/monitor_check_ins.rb +3 -3
  13. data/lib/sentry/cron/monitor_config.rb +2 -2
  14. data/lib/sentry/cron/monitor_schedule.rb +2 -2
  15. data/lib/sentry/debug_structured_logger.rb +94 -0
  16. data/lib/sentry/dsn.rb +32 -0
  17. data/lib/sentry/envelope/item.rb +3 -3
  18. data/lib/sentry/error_event.rb +3 -3
  19. data/lib/sentry/event.rb +4 -10
  20. data/lib/sentry/graphql.rb +1 -1
  21. data/lib/sentry/hub.rb +29 -5
  22. data/lib/sentry/interface.rb +1 -1
  23. data/lib/sentry/interfaces/exception.rb +2 -2
  24. data/lib/sentry/interfaces/request.rb +2 -0
  25. data/lib/sentry/interfaces/single_exception.rb +4 -4
  26. data/lib/sentry/interfaces/stacktrace.rb +3 -3
  27. data/lib/sentry/interfaces/stacktrace_builder.rb +0 -8
  28. data/lib/sentry/interfaces/threads.rb +2 -2
  29. data/lib/sentry/log_event.rb +33 -138
  30. data/lib/sentry/log_event_buffer.rb +13 -60
  31. data/lib/sentry/metric_event.rb +49 -0
  32. data/lib/sentry/metric_event_buffer.rb +28 -0
  33. data/lib/sentry/metrics.rb +47 -42
  34. data/lib/sentry/profiler.rb +4 -5
  35. data/lib/sentry/propagation_context.rb +55 -18
  36. data/lib/sentry/rspec.rb +1 -1
  37. data/lib/sentry/scope.rb +32 -5
  38. data/lib/sentry/sequel.rb +35 -0
  39. data/lib/sentry/span.rb +2 -17
  40. data/lib/sentry/std_lib_logger.rb +10 -1
  41. data/lib/sentry/telemetry_event_buffer.rb +130 -0
  42. data/lib/sentry/test_helper.rb +30 -0
  43. data/lib/sentry/transaction.rb +72 -95
  44. data/lib/sentry/transaction_event.rb +4 -9
  45. data/lib/sentry/transport/debug_transport.rb +70 -0
  46. data/lib/sentry/transport/dummy_transport.rb +1 -0
  47. data/lib/sentry/transport/http_transport.rb +9 -5
  48. data/lib/sentry/transport.rb +3 -5
  49. data/lib/sentry/utils/encoding_helper.rb +6 -0
  50. data/lib/sentry/utils/logging_helper.rb +25 -9
  51. data/lib/sentry/utils/sample_rand.rb +97 -0
  52. data/lib/sentry/utils/telemetry_attributes.rb +30 -0
  53. data/lib/sentry/vernier/profiler.rb +4 -3
  54. data/lib/sentry/version.rb +1 -1
  55. data/lib/sentry-ruby.rb +25 -30
  56. data/sentry-ruby-core.gemspec +1 -1
  57. data/sentry-ruby.gemspec +1 -1
  58. metadata +17 -17
  59. data/lib/sentry/metrics/aggregator.rb +0 -248
  60. data/lib/sentry/metrics/configuration.rb +0 -47
  61. data/lib/sentry/metrics/counter_metric.rb +0 -25
  62. data/lib/sentry/metrics/distribution_metric.rb +0 -25
  63. data/lib/sentry/metrics/gauge_metric.rb +0 -35
  64. data/lib/sentry/metrics/local_aggregator.rb +0 -53
  65. data/lib/sentry/metrics/metric.rb +0 -19
  66. data/lib/sentry/metrics/set_metric.rb +0 -28
  67. data/lib/sentry/metrics/timing.rb +0 -51
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb03eb536d1060c3a097a1ff3726ae71c8ffbd0012580d75c491665e054ac7c1
4
- data.tar.gz: 65df577369b281f3e1d1d9335e78786a800947c2014b35608d88c863458f24ca
3
+ metadata.gz: ea228d904661a633e6bdfd3eb0ea4dc6ac129a0fed8f4a0e378e9a6e84de30e0
4
+ data.tar.gz: 71c6db91301a24a1b05afa798a249de12b31a5d68c45d16f138f73c0999b3183
5
5
  SHA512:
6
- metadata.gz: b4e398e02a8fe619afc8982760c290a168785c4557dca30767fbeb039032d7907135e84d0598a5ac90b7b1cfb8413ceda83ebe4647702ba5c10c613ff0543574
7
- data.tar.gz: 285a3e0f650a41bcb6cc4539f48c7efcb9bc3442f31c76f301089c4672e6d9c790f407dd9d53db4e216df4eacd9be019b5bc46e453437fa1614aa48555541c9a
6
+ metadata.gz: 07adab1cfe625b662c7cc89867225f40f07a36b0b73b70c916969ad5bac6ec1516bda791b767398e0b48246e5f23e31601d954cec9f724a79d33980e45d6e4d5
7
+ data.tar.gz: 5072c6873787d7e070050df7aeeb3e9040ca3add4c04f1c4e21c63d12fb241ee6615eced7f71fac5edeee4381d60272069bdc38ce967033ead0e2e76894b2573
data/Gemfile CHANGED
@@ -3,15 +3,16 @@
3
3
  source "https://rubygems.org"
4
4
  git_source(:github) { |name| "https://github.com/#{name}.git" }
5
5
 
6
- eval_gemfile "../Gemfile"
6
+ eval_gemfile "../Gemfile.dev"
7
7
 
8
8
  gem "sentry-ruby", path: "./"
9
9
 
10
+ ruby_version = Gem::Version.new(RUBY_VERSION)
11
+
10
12
  rack_version = ENV["RACK_VERSION"]
11
13
  rack_version = "3.0.0" if rack_version.nil?
12
- gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
13
14
 
14
- gem "ostruct" if RUBY_VERSION >= "3.4"
15
+ gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
15
16
 
16
17
  redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
17
18
  gem "redis", "~> #{redis_rb_version}"
@@ -22,7 +23,7 @@ gem "timecop"
22
23
  gem "stackprof" unless RUBY_PLATFORM == "java"
23
24
  gem "vernier", platforms: :ruby if RUBY_VERSION >= "3.2.1"
24
25
 
25
- gem "graphql", ">= 2.2.6" if RUBY_VERSION.to_f >= 2.7
26
+ gem "graphql", ">= 2.2.6"
26
27
 
27
28
  gem "benchmark-ips"
28
29
  gem "benchmark_driver"
@@ -34,3 +35,24 @@ gem "webrick"
34
35
  gem "faraday"
35
36
  gem "excon"
36
37
  gem "webmock"
38
+
39
+ group :sequel do
40
+ gem "sequel"
41
+
42
+ sqlite_version = if ruby_version >= Gem::Version.new("3.2")
43
+ "2.1.0"
44
+ elsif ruby_version >= Gem::Version.new("3.0")
45
+ "1.4.0"
46
+ else
47
+ "1.3.0"
48
+ end
49
+
50
+ platform :ruby do
51
+ gem "sqlite3", "~> #{sqlite_version}"
52
+ end
53
+
54
+ platform :jruby do
55
+ gem "activerecord-jdbcmysql-adapter"
56
+ gem "jdbc-sqlite3"
57
+ end
58
+ end
data/README.md CHANGED
@@ -105,9 +105,9 @@ To learn more about sampling transactions, please visit the [official documentat
105
105
 
106
106
  * [![Ruby docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=ruby%20docs)](https://docs.sentry.io/platforms/ruby/)
107
107
  * [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks)
108
- * [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K)
108
+ * [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/sentry)
109
109
  * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry)
110
- * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry)
110
+ * [![X Follow](https://img.shields.io/twitter/follow/sentry?label=sentry&style=social)](https://x.com/intent/follow?screen_name=sentry)
111
111
 
112
112
  ## Contributing to the SDK
113
113
 
@@ -23,10 +23,7 @@ module Sentry
23
23
  @shutdown_callback = nil
24
24
 
25
25
  @executor =
26
- if configuration.async
27
- log_debug("config.async is set, BackgroundWorker is disabled")
28
- Concurrent::ImmediateExecutor.new
29
- elsif @number_of_threads == 0
26
+ if @number_of_threads == 0
30
27
  log_debug("config.background_worker_threads is set to 0, all events will be sent synchronously")
31
28
  Concurrent::ImmediateExecutor.new
32
29
  else
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # @api private
5
+ class Backtrace
6
+ # Handles backtrace parsing line by line
7
+ class Line
8
+ RB_EXTENSION = ".rb"
9
+ # regexp (optional leading X: on windows, or JRuby9000 class-prefix)
10
+ RUBY_INPUT_FORMAT = /
11
+ ^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
12
+ (\d+)
13
+ (?: :in\s('|`)(?:([\w:]+)\#)?([^']+)')?$
14
+ /x
15
+
16
+ # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
17
+ JAVA_INPUT_FORMAT = /^([\w$.]+)\.([\w$]+)\(([\w$.]+):(\d+)\)$/
18
+
19
+ # The file portion of the line (such as app/models/user.rb)
20
+ attr_reader :file
21
+
22
+ # The line number portion of the line
23
+ attr_reader :number
24
+
25
+ # The method of the line (such as index)
26
+ attr_reader :method
27
+
28
+ # The module name (JRuby)
29
+ attr_reader :module_name
30
+
31
+ attr_reader :in_app_pattern
32
+
33
+ # Parses a single line of a given backtrace
34
+ # @param [String] unparsed_line The raw line from +caller+ or some backtrace
35
+ # @return [Line] The parsed backtrace line
36
+ def self.parse(unparsed_line, in_app_pattern = nil)
37
+ ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
38
+
39
+ if ruby_match
40
+ _, file, number, _, module_name, method = ruby_match.to_a
41
+ file.sub!(/\.class$/, RB_EXTENSION)
42
+ module_name = module_name
43
+ else
44
+ java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
45
+ _, module_name, method, file, number = java_match.to_a
46
+ end
47
+ new(file, number, method, module_name, in_app_pattern)
48
+ end
49
+
50
+ # Creates a Line from a Thread::Backtrace::Location object
51
+ # This is more efficient than converting to string and parsing with regex
52
+ # @param [Thread::Backtrace::Location] location The location object
53
+ # @param [Regexp, nil] in_app_pattern Optional pattern to determine if the line is in-app
54
+ # @return [Line] The backtrace line
55
+ def self.from_source_location(location, in_app_pattern = nil)
56
+ file = location.absolute_path
57
+ number = location.lineno
58
+ method = location.base_label
59
+
60
+ label = location.label
61
+ index = label.index("#") || label.index(".")
62
+ module_name = label[0, index] if index
63
+
64
+ new(file, number, method, module_name, in_app_pattern)
65
+ end
66
+
67
+ def initialize(file, number, method, module_name, in_app_pattern)
68
+ @file = file
69
+ @module_name = module_name
70
+ @number = number.to_i
71
+ @method = method
72
+ @in_app_pattern = in_app_pattern
73
+ end
74
+
75
+ def in_app
76
+ return false unless in_app_pattern
77
+
78
+ if file =~ in_app_pattern
79
+ true
80
+ else
81
+ false
82
+ end
83
+ end
84
+
85
+ # Reconstructs the line in a readable fashion
86
+ def to_s
87
+ "#{file}:#{number}:in `#{method}'"
88
+ end
89
+
90
+ def ==(other)
91
+ to_s == other.to_s
92
+ end
93
+
94
+ def inspect
95
+ "<Line:#{self}>"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -1,86 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rubygems"
4
+ require "concurrent/map"
5
+ require "sentry/backtrace/line"
4
6
 
5
7
  module Sentry
6
8
  # @api private
7
9
  class Backtrace
8
- # Handles backtrace parsing line by line
9
- class Line
10
- RB_EXTENSION = ".rb"
11
- # regexp (optional leading X: on windows, or JRuby9000 class-prefix)
12
- RUBY_INPUT_FORMAT = /
13
- ^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
14
- (\d+)
15
- (?: :in\s('|`)(?:([\w:]+)\#)?([^']+)')?$
16
- /x
17
-
18
- # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
19
- JAVA_INPUT_FORMAT = /^([\w$.]+)\.([\w$]+)\(([\w$.]+):(\d+)\)$/
20
-
21
- # The file portion of the line (such as app/models/user.rb)
22
- attr_reader :file
23
-
24
- # The line number portion of the line
25
- attr_reader :number
26
-
27
- # The method of the line (such as index)
28
- attr_reader :method
29
-
30
- # The module name (JRuby)
31
- attr_reader :module_name
32
-
33
- attr_reader :in_app_pattern
34
-
35
- # Parses a single line of a given backtrace
36
- # @param [String] unparsed_line The raw line from +caller+ or some backtrace
37
- # @return [Line] The parsed backtrace line
38
- def self.parse(unparsed_line, in_app_pattern = nil)
39
- ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
40
-
41
- if ruby_match
42
- _, file, number, _, module_name, method = ruby_match.to_a
43
- file.sub!(/\.class$/, RB_EXTENSION)
44
- module_name = module_name
45
- else
46
- java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
47
- _, module_name, method, file, number = java_match.to_a
48
- end
49
- new(file, number, method, module_name, in_app_pattern)
50
- end
51
-
52
- def initialize(file, number, method, module_name, in_app_pattern)
53
- @file = file
54
- @module_name = module_name
55
- @number = number.to_i
56
- @method = method
57
- @in_app_pattern = in_app_pattern
58
- end
59
-
60
- def in_app
61
- return false unless in_app_pattern
62
-
63
- if file =~ in_app_pattern
64
- true
65
- else
66
- false
67
- end
68
- end
69
-
70
- # Reconstructs the line in a readable fashion
71
- def to_s
72
- "#{file}:#{number}:in `#{method}'"
73
- end
74
-
75
- def ==(other)
76
- to_s == other.to_s
77
- end
78
-
79
- def inspect
80
- "<Line:#{self}>"
81
- end
82
- end
83
-
84
10
  # holder for an Array of Backtrace::Line instances
85
11
  attr_reader :lines
86
12
 
@@ -100,6 +26,48 @@ module Sentry
100
26
  new(lines)
101
27
  end
102
28
 
29
+ # Thread.each_caller_location is an API added in Ruby 3.2 that doesn't always collect
30
+ # the entire stack like Kernel#caller or #caller_locations do.
31
+ #
32
+ # @see https://github.com/rails/rails/pull/49095 for more context.
33
+ if Thread.respond_to?(:each_caller_location)
34
+ def self.source_location(&backtrace_cleaner)
35
+ Thread.each_caller_location do |location|
36
+ frame_key = [location.absolute_path, location.lineno]
37
+ cached_value = line_cache[frame_key]
38
+
39
+ next if cached_value == :skip
40
+
41
+ if cached_value
42
+ return cached_value
43
+ else
44
+ if cleaned_frame = backtrace_cleaner.(location)
45
+ line = Line.from_source_location(location)
46
+ line_cache[frame_key] = line
47
+
48
+ return line
49
+ else
50
+ line_cache[frame_key] = :skip
51
+
52
+ next
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ def self.line_cache
59
+ @line_cache ||= Concurrent::Map.new
60
+ end
61
+ else
62
+ # Since Sentry is mostly used in production, we don't want to fallback
63
+ # to the slower implementation and adds potentially big overhead to the
64
+ # application.
65
+ def self.source_location(*)
66
+ nil
67
+ end
68
+ end
69
+
70
+
103
71
  def initialize(lines)
104
72
  @lines = lines
105
73
  end
@@ -34,7 +34,7 @@ module Sentry
34
34
  end
35
35
 
36
36
  # @return [Hash]
37
- def to_hash
37
+ def to_h
38
38
  {
39
39
  category: @category,
40
40
  data: serialized_data,
@@ -48,9 +48,9 @@ module Sentry
48
48
  end
49
49
 
50
50
  # @return [Hash]
51
- def to_hash
51
+ def to_h
52
52
  {
53
- values: members.map(&:to_hash)
53
+ values: members.map(&:to_h)
54
54
  }
55
55
  end
56
56
 
@@ -48,13 +48,13 @@ module Sentry
48
48
  end
49
49
 
50
50
  # @return [Hash]
51
- def to_hash
51
+ def to_h
52
52
  data = super
53
53
  data[:check_in_id] = check_in_id
54
54
  data[:monitor_slug] = monitor_slug
55
55
  data[:status] = status
56
56
  data[:duration] = duration if duration
57
- data[:monitor_config] = monitor_config.to_hash if monitor_config
57
+ data[:monitor_config] = monitor_config.to_h if monitor_config
58
58
  data
59
59
  end
60
60
  end
data/lib/sentry/client.rb CHANGED
@@ -3,7 +3,10 @@
3
3
  require "sentry/transport"
4
4
  require "sentry/log_event"
5
5
  require "sentry/log_event_buffer"
6
+ require "sentry/metric_event"
7
+ require "sentry/metric_event_buffer"
6
8
  require "sentry/utils/uuid"
9
+ require "sentry/utils/encoding_helper"
7
10
 
8
11
  module Sentry
9
12
  class Client
@@ -20,6 +23,9 @@ module Sentry
20
23
  # @!visibility private
21
24
  attr_reader :log_event_buffer
22
25
 
26
+ # @!visibility private
27
+ attr_reader :metric_event_buffer
28
+
23
29
  # @!macro configuration
24
30
  attr_reader :configuration
25
31
 
@@ -43,7 +49,11 @@ module Sentry
43
49
  @spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
44
50
 
45
51
  if configuration.enable_logs
46
- @log_event_buffer = LogEventBuffer.new(configuration, self).start
52
+ @log_event_buffer = LogEventBuffer.new(configuration, self)
53
+ end
54
+
55
+ if configuration.enable_metrics
56
+ @metric_event_buffer = MetricEventBuffer.new(configuration, self)
47
57
  end
48
58
  end
49
59
 
@@ -60,8 +70,7 @@ module Sentry
60
70
  return
61
71
  end
62
72
 
63
- event_type = event.is_a?(Event) ? event.type : event["type"]
64
- data_category = Envelope::Item.data_category(event_type)
73
+ data_category = Envelope::Item.data_category(event.type)
65
74
 
66
75
  is_transaction = event.is_a?(TransactionEvent)
67
76
  spans_before = is_transaction ? event.spans.size : 0
@@ -78,9 +87,7 @@ module Sentry
78
87
  transport.record_lost_event(:event_processor, "span", num: spans_delta) if spans_delta > 0
79
88
  end
80
89
 
81
- if async_block = configuration.async
82
- dispatch_async_event(async_block, event, hint)
83
- elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
90
+ if configuration.background_worker_threads != 0 && hint.fetch(:background, true)
84
91
  unless dispatch_background_event(event, hint)
85
92
  transport.record_lost_event(:queue_overflow, data_category)
86
93
  transport.record_lost_event(:queue_overflow, "span", num: spans_before + 1) if is_transaction
@@ -100,7 +107,17 @@ module Sentry
100
107
  # @return [LogEvent]
101
108
  def buffer_log_event(event, scope)
102
109
  return unless event.is_a?(LogEvent)
103
- @log_event_buffer.add_event(scope.apply_to_event(event))
110
+ @log_event_buffer.add_item(scope.apply_to_telemetry(event))
111
+ event
112
+ end
113
+
114
+ # Buffer a metric event to be sent later with other metrics in a single envelope
115
+ # @param event [MetricEvent] the metric event to be buffered
116
+ # @return [MetricEvent]
117
+ def buffer_metric_event(event, scope)
118
+ return unless event.is_a?(MetricEvent)
119
+ event = scope.apply_to_telemetry(event)
120
+ @metric_event_buffer.add_item(event)
104
121
  event
105
122
  end
106
123
 
@@ -117,6 +134,7 @@ module Sentry
117
134
  transport.flush if configuration.sending_to_dsn_allowed?
118
135
  spotlight_transport.flush if spotlight_transport
119
136
  @log_event_buffer&.flush
137
+ @metric_event_buffer&.flush
120
138
  end
121
139
 
122
140
  # Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
@@ -195,9 +213,19 @@ module Sentry
195
213
  def event_from_log(message, level:, **options)
196
214
  return unless configuration.sending_allowed?
197
215
 
198
- attributes = options.reject { |k, _| k == :level || k == :severity }
216
+ attributes = options.reject { |k, _| k == :level || k == :severity || k == :origin }
217
+ origin = options[:origin]
218
+ body = Utils::EncodingHelper.safe_utf_8_string(message)
219
+
220
+ sanitized_attributes = attributes.transform_values do |value|
221
+ if value.is_a?(String)
222
+ Utils::EncodingHelper.safe_utf_8_string(value)
223
+ else
224
+ value
225
+ end
226
+ end
199
227
 
200
- LogEvent.new(level: level, body: message, attributes: attributes)
228
+ LogEvent.new(level: level, body: body, attributes: sanitized_attributes, origin: origin)
201
229
  end
202
230
 
203
231
  # Initializes an Event object with the given Transaction object.
@@ -209,22 +237,13 @@ module Sentry
209
237
 
210
238
  # @!macro send_event
211
239
  def send_event(event, hint = nil)
212
- event_type = event.is_a?(Event) ? event.type : event["type"]
213
- data_category = Envelope::Item.data_category(event_type)
240
+ data_category = Envelope::Item.data_category(event.type)
214
241
  spans_before = event.is_a?(TransactionEvent) ? event.spans.size : 0
215
242
 
216
- if event_type != TransactionEvent::TYPE && configuration.before_send
243
+ if event.is_a?(ErrorEvent) && configuration.before_send
217
244
  event = configuration.before_send.call(event, hint)
218
245
 
219
- case event
220
- when ErrorEvent, CheckInEvent
221
- # do nothing
222
- when Hash
223
- log_debug(<<~MSG)
224
- Returning a Hash from before_send is deprecated and will be removed in the next major version.
225
- Please return a Sentry::ErrorEvent object instead.
226
- MSG
227
- else
246
+ if !event.is_a?(ErrorEvent)
228
247
  # Avoid serializing the event object in this case because we aren't sure what it is and what it contains
229
248
  log_debug(<<~MSG)
230
249
  Discarded event because before_send didn't return a Sentry::ErrorEvent object but an instance of #{event.class}
@@ -234,21 +253,10 @@ module Sentry
234
253
  end
235
254
  end
236
255
 
237
- if event_type == TransactionEvent::TYPE && configuration.before_send_transaction
256
+ if event.is_a?(TransactionEvent) && configuration.before_send_transaction
238
257
  event = configuration.before_send_transaction.call(event, hint)
239
258
 
240
- if event.is_a?(TransactionEvent) || event.is_a?(Hash)
241
- spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
242
- spans_delta = spans_before - spans_after
243
- transport.record_lost_event(:before_send, "span", num: spans_delta) if spans_delta > 0
244
-
245
- if event.is_a?(Hash)
246
- log_debug(<<~MSG)
247
- Returning a Hash from before_send_transaction is deprecated and will be removed in the next major version.
248
- Please return a Sentry::TransactionEvent object instead.
249
- MSG
250
- end
251
- else
259
+ if !event.is_a?(TransactionEvent)
252
260
  # Avoid serializing the event object in this case because we aren't sure what it is and what it contains
253
261
  log_debug(<<~MSG)
254
262
  Discarded event because before_send_transaction didn't return a Sentry::TransactionEvent object but an instance of #{event.class}
@@ -257,6 +265,23 @@ module Sentry
257
265
  transport.record_lost_event(:before_send, "span", num: spans_before + 1)
258
266
  return
259
267
  end
268
+
269
+ spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
270
+ spans_delta = spans_before - spans_after
271
+ transport.record_lost_event(:before_send, "span", num: spans_delta) if spans_delta > 0
272
+ end
273
+
274
+ if event.is_a?(CheckInEvent) && configuration.before_send_check_in
275
+ event = configuration.before_send_check_in.call(event, hint)
276
+
277
+ if !event.is_a?(CheckInEvent)
278
+ # Avoid serializing the event object in this case because we aren't sure what it is and what it contains
279
+ log_debug(<<~MSG)
280
+ Discarded event because before_send_check_in didn't return a Sentry::CheckInEvent object but an instance of #{event.class}
281
+ MSG
282
+ transport.record_lost_event(:before_send, data_category)
283
+ return
284
+ end
260
285
  end
261
286
 
262
287
  transport.send_event(event) if configuration.sending_to_dsn_allowed?
@@ -270,53 +295,6 @@ module Sentry
270
295
  raise
271
296
  end
272
297
 
273
- # Send an envelope with batched logs
274
- # @param log_events [Array<LogEvent>] the log events to be sent
275
- # @api private
276
- # @return [void]
277
- def send_logs(log_events)
278
- envelope = Envelope.new(
279
- event_id: Sentry::Utils.uuid,
280
- sent_at: Sentry.utc_now.iso8601,
281
- dsn: configuration.dsn,
282
- sdk: Sentry.sdk_meta
283
- )
284
-
285
- discarded_count = 0
286
- envelope_items = []
287
-
288
- if configuration.before_send_log
289
- log_events.each do |log_event|
290
- processed_log_event = configuration.before_send_log.call(log_event)
291
-
292
- if processed_log_event
293
- envelope_items << processed_log_event.to_hash
294
- else
295
- discarded_count += 1
296
- end
297
- end
298
-
299
- envelope_items
300
- else
301
- envelope_items = log_events.map(&:to_hash)
302
- end
303
-
304
- envelope.add_item(
305
- {
306
- type: "log",
307
- item_count: envelope_items.size,
308
- content_type: "application/vnd.sentry.items.log+json"
309
- },
310
- { items: envelope_items }
311
- )
312
-
313
- send_envelope(envelope)
314
-
315
- unless discarded_count.zero?
316
- transport.record_lost_event(:before_send, "log_item", num: discarded_count)
317
- end
318
- end
319
-
320
298
  # Send an envelope directly to Sentry.
321
299
  # @param envelope [Envelope] the envelope to be sent.
322
300
  # @return [void]
@@ -333,38 +311,6 @@ module Sentry
333
311
  raise
334
312
  end
335
313
 
336
- # @deprecated use Sentry.get_traceparent instead.
337
- #
338
- # Generates a Sentry trace for distribted tracing from the given Span.
339
- # Returns `nil` if `config.propagate_traces` is `false`.
340
- # @param span [Span] the span to generate trace from.
341
- # @return [String, nil]
342
- def generate_sentry_trace(span)
343
- return unless configuration.propagate_traces
344
-
345
- trace = span.to_sentry_trace
346
- log_debug("[Tracing] Adding #{SENTRY_TRACE_HEADER_NAME} header to outgoing request: #{trace}")
347
- trace
348
- end
349
-
350
- # @deprecated Use Sentry.get_baggage instead.
351
- #
352
- # Generates a W3C Baggage header for distributed tracing from the given Span.
353
- # Returns `nil` if `config.propagate_traces` is `false`.
354
- # @param span [Span] the span to generate trace from.
355
- # @return [String, nil]
356
- def generate_baggage(span)
357
- return unless configuration.propagate_traces
358
-
359
- baggage = span.to_baggage
360
-
361
- if baggage && !baggage.empty?
362
- log_debug("[Tracing] Adding #{BAGGAGE_HEADER_NAME} header to outgoing request: #{baggage}")
363
- end
364
-
365
- baggage
366
- end
367
-
368
314
  private
369
315
 
370
316
  def dispatch_background_event(event, hint)
@@ -372,28 +318,5 @@ module Sentry
372
318
  send_event(event, hint)
373
319
  end
374
320
  end
375
-
376
- def dispatch_async_event(async_block, event, hint)
377
- # We have to convert to a JSON-like hash, because background job
378
- # processors (esp ActiveJob) may not like weird types in the event hash
379
-
380
- event_hash =
381
- begin
382
- event.to_json_compatible
383
- rescue => e
384
- log_error("Converting #{event.type} (#{event.event_id}) to JSON compatible hash failed", e, debug: configuration.debug)
385
- return
386
- end
387
-
388
- if async_block.arity == 2
389
- hint = JSON.parse(JSON.generate(hint))
390
- async_block.call(event_hash, hint)
391
- else
392
- async_block.call(event_hash)
393
- end
394
- rescue => e
395
- log_error("Async #{event_hash["type"]} sending failed", e, debug: configuration.debug)
396
- send_event(event, hint)
397
- end
398
321
  end
399
322
  end