sentry-ruby 7.0.0 → 7.1.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/gemfiles/ruby-2.7_rack-2_redis-4.gemfile.lock +6 -6
  3. data/gemfiles/ruby-2.7_rack-3.1_redis-4.gemfile.lock +6 -6
  4. data/gemfiles/ruby-2.7_rack-3_redis-4.gemfile.lock +6 -6
  5. data/gemfiles/ruby-3.0_rack-2_redis-4.gemfile.lock +8 -8
  6. data/gemfiles/ruby-3.0_rack-3.1_redis-4.gemfile.lock +8 -8
  7. data/gemfiles/ruby-3.0_rack-3_redis-4.gemfile.lock +8 -8
  8. data/gemfiles/ruby-3.1_rack-2_redis-4.gemfile.lock +16 -16
  9. data/gemfiles/ruby-3.1_rack-3.1_redis-4.gemfile.lock +16 -16
  10. data/gemfiles/ruby-3.1_rack-3_redis-4.gemfile.lock +16 -16
  11. data/gemfiles/ruby-3.2_rack-0_redis-5.gemfile.lock +16 -16
  12. data/gemfiles/ruby-3.2_rack-2_redis-4.gemfile.lock +16 -16
  13. data/gemfiles/ruby-3.2_rack-2_redis-5.gemfile.lock +16 -16
  14. data/gemfiles/ruby-3.2_rack-3.1_redis-4.gemfile.lock +16 -16
  15. data/gemfiles/ruby-3.2_rack-3_redis-4.gemfile.lock +16 -16
  16. data/gemfiles/ruby-3.2_rack-3_redis-5.gemfile.lock +16 -16
  17. data/gemfiles/ruby-3.3_rack-2_redis-4.gemfile.lock +18 -18
  18. data/gemfiles/ruby-3.3_rack-3.1_redis-4.gemfile.lock +18 -18
  19. data/gemfiles/ruby-3.3_rack-3.1_redis-5.3.gemfile.lock +18 -18
  20. data/gemfiles/ruby-3.3_rack-3_redis-4.gemfile.lock +18 -18
  21. data/gemfiles/ruby-3.4_rack-2_redis-4.gemfile.lock +18 -18
  22. data/gemfiles/ruby-3.4_rack-3.1_redis-4.gemfile.lock +18 -18
  23. data/gemfiles/ruby-3.4_rack-3.1_redis-5.3.gemfile.lock +18 -18
  24. data/gemfiles/ruby-3.4_rack-3_redis-4.gemfile.lock +18 -18
  25. data/gemfiles/ruby-4.0_rack-2_redis-4.gemfile.lock +18 -18
  26. data/gemfiles/ruby-4.0_rack-3.1_redis-4.gemfile.lock +18 -18
  27. data/gemfiles/ruby-4.0_rack-3_redis-4.gemfile.lock +18 -18
  28. data/gemfiles/ruby-jruby-9.4.14.0_rack-2_redis-4.gemfile.lock +18 -18
  29. data/gemfiles/ruby-jruby-9.4.14.0_rack-3.1_redis-4.gemfile.lock +18 -18
  30. data/gemfiles/ruby-jruby-9.4.14.0_rack-3_redis-4.gemfile.lock +18 -18
  31. data/lib/sentry/backtrace.rb +10 -1
  32. data/lib/sentry/client.rb +19 -6
  33. data/lib/sentry/configuration.rb +1 -1
  34. data/lib/sentry/faraday.rb +4 -1
  35. data/lib/sentry/hub.rb +9 -2
  36. data/lib/sentry/integrable.rb +12 -0
  37. data/lib/sentry/log_event_buffer.rb +1 -1
  38. data/lib/sentry/metric_event.rb +4 -2
  39. data/lib/sentry/metric_event_buffer.rb +1 -1
  40. data/lib/sentry/metrics.rb +12 -6
  41. data/lib/sentry/scope.rb +7 -3
  42. data/lib/sentry/session_flusher.rb +7 -0
  43. data/lib/sentry/std_lib_logger.rb +8 -2
  44. data/lib/sentry/telemetry_event_buffer.rb +57 -31
  45. data/lib/sentry/test_helper.rb +4 -0
  46. data/lib/sentry/threaded_periodic_worker.rb +90 -13
  47. data/lib/sentry/transaction.rb +7 -1
  48. data/lib/sentry/utils/callback_helper.rb +27 -0
  49. data/lib/sentry/version.rb +1 -1
  50. data/lib/sentry-ruby.rb +3 -0
  51. metadata +7 -6
@@ -6,7 +6,7 @@ GIT
6
6
  PATH
7
7
  remote: ..
8
8
  specs:
9
- sentry-ruby (6.7.0)
9
+ sentry-ruby (7.0.0)
10
10
  bigdecimal
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
12
  logger
@@ -48,7 +48,7 @@ GEM
48
48
  benchmark-memory (0.1.2)
49
49
  memory_profiler (~> 0.9)
50
50
  benchmark_driver (0.16.5)
51
- bigdecimal (4.1.2-java)
51
+ bigdecimal (4.1.3-java)
52
52
  cgi (0.5.2-java)
53
53
  concurrent-ruby (1.3.8)
54
54
  connection_pool (2.5.5)
@@ -63,30 +63,30 @@ GEM
63
63
  cgi (>= 0.3.3)
64
64
  excon (1.6.0)
65
65
  logger
66
- faraday (2.14.3)
66
+ faraday (2.14.4)
67
67
  faraday-net_http (>= 2.0, < 3.5)
68
68
  json
69
69
  logger
70
70
  faraday-net_http (3.4.4)
71
71
  net-http (~> 0.5)
72
72
  fiber-storage (1.0.1)
73
- graphql (2.6.9)
73
+ graphql (2.6.10)
74
74
  base64
75
75
  fiber-storage
76
76
  logger
77
77
  hashdiff (1.2.1)
78
78
  i18n (1.15.2)
79
79
  concurrent-ruby (~> 1.0)
80
- io-console (0.9.2-java)
80
+ io-console (0.9.4-java)
81
81
  irb (1.18.0)
82
82
  pp (>= 0.6.0)
83
83
  prism (>= 1.3.0)
84
84
  rdoc (>= 4.0.0)
85
85
  reline (>= 0.4.2)
86
- jar-dependencies (0.5.7)
86
+ jar-dependencies (0.6.1-java)
87
87
  jdbc-mysql (8.4.0.1)
88
88
  jdbc-sqlite3 (3.46.1.1)
89
- json (2.21.2-java)
89
+ json (3.0.2-java)
90
90
  logger (1.7.0)
91
91
  memory_profiler (0.9.14)
92
92
  minitest (5.27.0)
@@ -129,7 +129,7 @@ GEM
129
129
  rspec-core (> 3.3)
130
130
  rspec-support (3.13.7)
131
131
  securerandom (0.4.1)
132
- sequel (5.107.0)
132
+ sequel (5.108.0)
133
133
  bigdecimal
134
134
  simplecov (0.22.0)
135
135
  docile (~> 1.1)
@@ -146,7 +146,7 @@ GEM
146
146
  tzinfo (2.0.6)
147
147
  concurrent-ruby (~> 1.0)
148
148
  uri (1.1.1)
149
- webmock (3.26.3)
149
+ webmock (3.26.4)
150
150
  addressable (>= 2.8.0)
151
151
  crack (>= 0.3.2)
152
152
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -200,7 +200,7 @@ CHECKSUMS
200
200
  benchmark-ipsa (0.2.0) sha256=8be4820765d575691b2f91f6c988a8a3d90393239bf9d35ea53c8ab0fbca7230
201
201
  benchmark-memory (0.1.2) sha256=aa7bfe6776174d0ddefe6fb39945d88fff6d76eac165690188391d9acd441c87
202
202
  benchmark_driver (0.16.5) sha256=f675df0fe1de7e18e40df313ae24ebe4c7ee7814a4165f29a1a37b863a685831
203
- bigdecimal (4.1.2-java) sha256=ccc836eab720a525529f70ed0de26a206fdbc9a9e8ac67b3b4ac7318b03e114d
203
+ bigdecimal (4.1.3-java) sha256=9a6a1fa67723a27ab1b3a6d5526322d8c82170af03199da7c915b8d9a1770532
204
204
  cgi (0.5.2-java) sha256=08bbfe06e10e771d36f10db6c1dfb81727ea2a25c3dbcd28d890a1794414a73d
205
205
  concurrent-ruby (1.3.8) sha256=b2f1be836e968ccc78ccfce277ea79c72a88633f22306782c16ff23fb415d1e1
206
206
  connection_pool (2.5.5) sha256=e54ff92855753df1fd7c59fa04a398833355f27dd14c074f8c83a05f72a716ad
@@ -211,18 +211,18 @@ CHECKSUMS
211
211
  drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
212
212
  erb (4.0.4.1-java) sha256=3e4805edebd25f48cdb43ad4ebf1d61c11538f29373f0a48716b688819e3f7ce
213
213
  excon (1.6.0) sha256=ebe2ab83c055ef8e117c62c91a3535b966a59a64868188219d49ab90cd83b65f
214
- faraday (2.14.3) sha256=1882247e6766615c8220b4392bf1d27f6ebb63d8e28267587cef1fb0bf37f278
214
+ faraday (2.14.4) sha256=9bb4408c44621b0dbaaaa39e5dbfc4dbe58cc6751b6eb94d16ae9e1f2f2fab6e
215
215
  faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
216
216
  fiber-storage (1.0.1) sha256=f48e5b6d8b0be96dac486332b55cee82240057065dc761c1ea692b2e719240e1
217
- graphql (2.6.9) sha256=afe7bc03164f1a61abc66a415744ffd315c5aca116c9f3438c57391a431e4fe5
217
+ graphql (2.6.10) sha256=9b7c8633767f516ff9d48a8d6305b2a00a2101c82aa871b92e69086944f9f83e
218
218
  hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
219
219
  i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
220
- io-console (0.9.2-java) sha256=929c09163ad227cda17f5dc57861b995dbecf69c7ca2ce7b0c5f941f1f3da7d3
220
+ io-console (0.9.4-java) sha256=789188c38b937fc2d04400e35fd3b2838ffdf061e846571e51524036bc1bc185
221
221
  irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
222
- jar-dependencies (0.5.7) sha256=013ce5f4639414ac8cf1169cdbe763da164b81e2d2c983d11042b5ff7bfcce80
222
+ jar-dependencies (0.6.1-java) sha256=2746643482d139fd9cecb524b57df63b71d9b5d734c7275171701201e3164f23
223
223
  jdbc-mysql (8.4.0.1) sha256=429cb7999d11c4f46a7153a382b6ac07935a4c10ddc52dd98e2d52b22c17fa13
224
224
  jdbc-sqlite3 (3.46.1.1) sha256=2498fea7d37c0d51c6bad1b95ffc909173c014ba6bd36825f37910113d0230cf
225
- json (2.21.2-java) sha256=f01521cd90639cc26b63040fb00d2b949f18f41ecaab5c82b02fb31d0b8b736c
225
+ json (3.0.2-java) sha256=2afafb9c82faabfb60ed2f37707973fdcb766dba2c99f0b9ed85f073d1d4c3d0
226
226
  logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
227
227
  memory_profiler (0.9.14) sha256=de558cf6525d8d56d2c0ea465b1664517fbe45560f892dc7a898d3b8c2863b12
228
228
  minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
@@ -247,8 +247,8 @@ CHECKSUMS
247
247
  rspec-retry (0.6.2) sha256=6101ba23a38809811ae3484acde4ab481c54d846ac66d5037ccb40131a60d858
248
248
  rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
249
249
  securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
250
- sentry-ruby (6.7.0)
251
- sequel (5.107.0) sha256=019629313205295b007f6df2c5eab19ddc40710d549fd445ac300f2853a370db
250
+ sentry-ruby (7.0.0)
251
+ sequel (5.108.0) sha256=ae5996d1196775427916a2fa36e02f99762ead9affb8ea9b1aec2c0b16bdb3a3
252
252
  simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
253
253
  simplecov-cobertura (3.2.0) sha256=70d702658677fcb20e5aceb6915ccf8bc62ff2ccd38b62b3ad5c9db5c0888740
254
254
  simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
@@ -258,7 +258,7 @@ CHECKSUMS
258
258
  tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
259
259
  tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
260
260
  uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
261
- webmock (3.26.3) sha256=77c612816bdcb2fc43db0e42fd98b19be7d4770fd708816fdde65a006664ddec
261
+ webmock (3.26.4) sha256=8d8da206d217ebe6968cfb09c77f4533c23074e1432bad865f3994eacbaad50d
262
262
  webrick (1.9.2) sha256=beb4a15fc474defed24a3bda4ffd88a490d517c9e4e6118c3edce59e45864131
263
263
  yard (0.9.45) sha256=52e211493f7cb8a3ebf7e104a25a1e73937a3103092545d34cb88fafebb3dc51
264
264
 
@@ -7,6 +7,8 @@ require "sentry/backtrace/line"
7
7
  module Sentry
8
8
  # @api private
9
9
  class Backtrace
10
+ extend CallbackHelper
11
+
10
12
  # holder for an Array of Backtrace::Line instances
11
13
  attr_reader :lines
12
14
 
@@ -15,7 +17,14 @@ module Sentry
15
17
  def self.parse(backtrace, project_root, app_dirs_pattern, in_app_pattern: nil, &backtrace_cleanup_callback)
16
18
  ruby_lines = backtrace.is_a?(Array) ? backtrace : backtrace.split(/\n\s*/)
17
19
 
18
- ruby_lines = backtrace_cleanup_callback.call(ruby_lines) if backtrace_cleanup_callback
20
+ if backtrace_cleanup_callback
21
+ ruby_lines = safe_dispatch_callback(
22
+ "backtrace_cleanup_callback",
23
+ backtrace_cleanup_callback,
24
+ [ruby_lines],
25
+ fallback: ruby_lines
26
+ )
27
+ end
19
28
 
20
29
  # in_app_pattern is now passed in from StacktraceBuilder, so this regex won't be triggered
21
30
  # only here for backwards compat and will be deleted
data/lib/sentry/client.rb CHANGED
@@ -11,6 +11,7 @@ require "sentry/utils/encoding_helper"
11
11
  module Sentry
12
12
  class Client
13
13
  include LoggingHelper
14
+ include CallbackHelper
14
15
 
15
16
  # The Transport object that'll send events for the client.
16
17
  # @return [Transport]
@@ -89,7 +90,7 @@ module Sentry
89
90
  transport.record_lost_event(:queue_overflow, "span", num: spans_before + 1) if is_transaction
90
91
  end
91
92
  else
92
- send_event(event, hint)
93
+ event = send_event(event, hint)
93
94
  end
94
95
 
95
96
  event
@@ -129,8 +130,8 @@ module Sentry
129
130
  def flush
130
131
  transport.flush if configuration.sending_to_dsn_allowed?
131
132
  spotlight_transport.flush if spotlight_transport
132
- @log_event_buffer&.flush
133
- @metric_event_buffer&.flush
133
+ @log_event_buffer.flush
134
+ @metric_event_buffer.flush
134
135
  end
135
136
 
136
137
  # Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
@@ -237,7 +238,11 @@ module Sentry
237
238
  spans_before = event.is_a?(TransactionEvent) ? event.spans.size : 0
238
239
 
239
240
  if event.is_a?(ErrorEvent) && configuration.before_send
240
- event = configuration.before_send.call(event, hint)
241
+ event = safe_dispatch_callback(
242
+ "before_send",
243
+ configuration.before_send,
244
+ [event, hint]
245
+ )
241
246
 
242
247
  if !event.is_a?(ErrorEvent)
243
248
  # Avoid serializing the event object in this case because we aren't sure what it is and what it contains
@@ -250,7 +255,11 @@ module Sentry
250
255
  end
251
256
 
252
257
  if event.is_a?(TransactionEvent) && configuration.before_send_transaction
253
- event = configuration.before_send_transaction.call(event, hint)
258
+ event = safe_dispatch_callback(
259
+ "before_send_transaction",
260
+ configuration.before_send_transaction,
261
+ [event, hint]
262
+ )
254
263
 
255
264
  if !event.is_a?(TransactionEvent)
256
265
  # Avoid serializing the event object in this case because we aren't sure what it is and what it contains
@@ -268,7 +277,11 @@ module Sentry
268
277
  end
269
278
 
270
279
  if event.is_a?(CheckInEvent) && configuration.before_send_check_in
271
- event = configuration.before_send_check_in.call(event, hint)
280
+ event = safe_dispatch_callback(
281
+ "before_send_check_in",
282
+ configuration.before_send_check_in,
283
+ [event, hint]
284
+ )
272
285
 
273
286
  if !event.is_a?(CheckInEvent)
274
287
  # Avoid serializing the event object in this case because we aren't sure what it is and what it contains
@@ -442,7 +442,7 @@ module Sentry
442
442
  SERVER_PORT
443
443
  ].freeze
444
444
 
445
- TRACE_IGNORE_STATUS_CODES_DEFAULT = [(301..303), (305..399), (401..404)]
445
+ TRACE_IGNORE_STATUS_CODES_DEFAULT = [301, (305..399), (401..404)]
446
446
 
447
447
  HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
448
448
  "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
@@ -14,10 +14,13 @@ module Sentry
14
14
 
15
15
  # Ensure that we attach instrumentation only if the adapter is not net/http
16
16
  # because if is is, then the net/http instrumentation will take care of it
17
- if builder.adapter.name != "Faraday::Adapter::NetHttp"
17
+ if builder.adapter.name != "Faraday::Adapter::NetHttp" &&
18
+ !builder.locked? &&
19
+ !builder.instance_variable_defined?(:@sentry_patched)
18
20
  # Make sure that it's going to be the first middleware so that it can capture
19
21
  # the entire request processing involving other middlewares
20
22
  builder.insert(0, ::Faraday::Request::Instrumentation, name: OP_NAME, instrumenter: Instrumenter.new)
23
+ builder.instance_variable_set(:@sentry_patched, true)
21
24
  end
22
25
  end
23
26
  end
data/lib/sentry/hub.rb CHANGED
@@ -7,6 +7,7 @@ require "sentry/session"
7
7
  module Sentry
8
8
  class Hub
9
9
  include ArgumentCheckingHelper
10
+ include CallbackHelper
10
11
 
11
12
  MUTEX = Mutex.new
12
13
 
@@ -240,8 +241,9 @@ module Sentry
240
241
  # @param value [Numeric] the metric value
241
242
  # @param unit [String, nil] (optional) the metric unit
242
243
  # @param attributes [Hash, nil] (optional) additional attributes for the metric
244
+ # @param integration [String, Symbol, nil] (optional) registered integration emitting the metric
243
245
  # @return [void]
244
- def capture_metric(name:, type:, value:, unit: nil, attributes: nil)
246
+ def capture_metric(name:, type:, value:, unit: nil, attributes: nil, integration: nil)
245
247
  return unless current_client
246
248
 
247
249
  metric = MetricEvent.new(
@@ -250,6 +252,7 @@ module Sentry
250
252
  type: type,
251
253
  unit: unit,
252
254
  attributes: attributes&.dup,
255
+ integration_meta: Sentry.integrations[integration.to_s]
253
256
  )
254
257
 
255
258
  current_client.buffer_metric_event(metric, current_scope)
@@ -294,7 +297,11 @@ module Sentry
294
297
  return unless configuration.enabled_in_current_env?
295
298
 
296
299
  if before_breadcrumb = current_client.configuration.before_breadcrumb
297
- breadcrumb = before_breadcrumb.call(breadcrumb, hint)
300
+ breadcrumb = safe_dispatch_callback(
301
+ "before_breadcrumb",
302
+ before_breadcrumb,
303
+ [breadcrumb, hint]
304
+ )
298
305
  end
299
306
 
300
307
  return unless breadcrumb
@@ -32,5 +32,17 @@ module Sentry
32
32
  options[:hint][:integration] = integration_name
33
33
  Sentry.capture_check_in(slug, status, **options, &block)
34
34
  end
35
+
36
+ def count(name, value: 1, attributes: nil)
37
+ Sentry.metrics.count(name, value: value, attributes: attributes, integration: integration_name)
38
+ end
39
+
40
+ def gauge(name, value, unit: nil, attributes: nil)
41
+ Sentry.metrics.gauge(name, value, unit: unit, attributes: attributes, integration: integration_name)
42
+ end
43
+
44
+ def distribution(name, value, unit: nil, attributes: nil)
45
+ Sentry.metrics.distribution(name, value, unit: unit, attributes: attributes, integration: integration_name)
46
+ end
35
47
  end
36
48
  end
@@ -21,7 +21,7 @@ module Sentry
21
21
  max_items_before_drop: MAX_EVENTS_BEFORE_DROP,
22
22
  envelope_type: "log",
23
23
  envelope_content_type: "application/vnd.sentry.items.log+json",
24
- before_send: configuration.before_send_log
24
+ before_send: :before_send_log
25
25
  )
26
26
  end
27
27
  end
@@ -6,7 +6,7 @@ module Sentry
6
6
  class MetricEvent
7
7
  include Sentry::Utils::TelemetryAttributes
8
8
 
9
- attr_reader :name, :type, :value, :unit, :timestamp, :trace_id, :span_id, :attributes
9
+ attr_reader :name, :type, :value, :unit, :timestamp, :trace_id, :span_id, :attributes, :integration_meta
10
10
  attr_writer :trace_id, :span_id, :attributes
11
11
 
12
12
  def initialize(
@@ -14,13 +14,15 @@ module Sentry
14
14
  type:,
15
15
  value:,
16
16
  unit: nil,
17
- attributes: nil
17
+ attributes: nil,
18
+ integration_meta: nil
18
19
  )
19
20
  @name = name
20
21
  @type = type
21
22
  @value = value
22
23
  @unit = unit
23
24
  @attributes = attributes || {}
25
+ @integration_meta = integration_meta
24
26
 
25
27
  @timestamp = Sentry.utc_now
26
28
  @trace_id = nil
@@ -21,7 +21,7 @@ module Sentry
21
21
  max_items_before_drop: MAX_METRICS_BEFORE_DROP,
22
22
  envelope_type: "trace_metric",
23
23
  envelope_content_type: "application/vnd.sentry.items.trace-metric+json",
24
- before_send: configuration.before_send_metric
24
+ before_send: :before_send_metric
25
25
  )
26
26
  end
27
27
  end
@@ -9,15 +9,17 @@ module Sentry
9
9
  # @param name [String] the metric name
10
10
  # @param value [Numeric] the value to increment by (default: 1)
11
11
  # @param attributes [Hash, nil] additional attributes for the metric (optional)
12
+ # @param integration [String, Symbol, nil] registered integration emitting the metric (optional)
12
13
  # @return [void]
13
- def count(name, value: 1, attributes: nil)
14
+ def count(name, value: 1, attributes: nil, integration: nil)
14
15
  return unless Sentry.initialized?
15
16
 
16
17
  Sentry.get_current_hub.capture_metric(
17
18
  name: name,
18
19
  type: :counter,
19
20
  value: value,
20
- attributes: attributes
21
+ attributes: attributes,
22
+ integration: integration
21
23
  )
22
24
  end
23
25
 
@@ -26,8 +28,9 @@ module Sentry
26
28
  # @param value [Numeric] the gauge value
27
29
  # @param unit [String, nil] the metric unit (optional)
28
30
  # @param attributes [Hash, nil] additional attributes for the metric (optional)
31
+ # @param integration [String, Symbol, nil] registered integration emitting the metric (optional)
29
32
  # @return [void]
30
- def gauge(name, value, unit: nil, attributes: nil)
33
+ def gauge(name, value, unit: nil, attributes: nil, integration: nil)
31
34
  return unless Sentry.initialized?
32
35
 
33
36
  Sentry.get_current_hub.capture_metric(
@@ -35,7 +38,8 @@ module Sentry
35
38
  type: :gauge,
36
39
  value: value,
37
40
  unit: unit,
38
- attributes: attributes
41
+ attributes: attributes,
42
+ integration: integration
39
43
  )
40
44
  end
41
45
 
@@ -44,8 +48,9 @@ module Sentry
44
48
  # @param value [Numeric] the distribution value
45
49
  # @param unit [String, nil] the metric unit (optional)
46
50
  # @param attributes [Hash, nil] additional attributes for the metric (optional)
51
+ # @param integration [String, Symbol, nil] registered integration emitting the metric (optional)
47
52
  # @return [void]
48
- def distribution(name, value, unit: nil, attributes: nil)
53
+ def distribution(name, value, unit: nil, attributes: nil, integration: nil)
49
54
  return unless Sentry.initialized?
50
55
 
51
56
  Sentry.get_current_hub.capture_metric(
@@ -53,7 +58,8 @@ module Sentry
53
58
  type: :distribution,
54
59
  value: value,
55
60
  unit: unit,
56
- attributes: attributes
61
+ attributes: attributes,
62
+ integration: integration
57
63
  )
58
64
  end
59
65
  end
data/lib/sentry/scope.rb CHANGED
@@ -9,6 +9,7 @@ require "etc"
9
9
  module Sentry
10
10
  class Scope
11
11
  include ArgumentCheckingHelper
12
+ include CallbackHelper
12
13
 
13
14
  ATTRIBUTES = [
14
15
  :transaction_name,
@@ -71,7 +72,8 @@ module Sentry
71
72
 
72
73
  unless all_event_processors.empty?
73
74
  all_event_processors.each do |processor_block|
74
- event = processor_block.call(event, hint)
75
+ event = safe_dispatch_callback("event_processor", processor_block, [event, hint])
76
+ return unless event
75
77
  end
76
78
  end
77
79
 
@@ -102,8 +104,10 @@ module Sentry
102
104
  configuration = Sentry.configuration
103
105
  return telemetry unless configuration
104
106
 
105
- telemetry.attributes["sentry.sdk.name"] ||= Sentry.sdk_meta["name"]
106
- telemetry.attributes["sentry.sdk.version"] ||= Sentry.sdk_meta["version"]
107
+ sdk_meta = telemetry.respond_to?(:integration_meta) ? telemetry.integration_meta : nil
108
+ sdk_meta ||= Sentry.sdk_meta
109
+ telemetry.attributes["sentry.sdk.name"] ||= sdk_meta[:name] || sdk_meta["name"]
110
+ telemetry.attributes["sentry.sdk.version"] ||= sdk_meta[:version] || sdk_meta["version"]
107
111
  telemetry.attributes["sentry.environment"] ||= configuration.environment if configuration.environment
108
112
  telemetry.attributes["sentry.release"] ||= configuration.release if configuration.release
109
113
  telemetry.attributes["server.address"] ||= configuration.server_name if configuration.server_name
@@ -35,6 +35,13 @@ module Sentry
35
35
 
36
36
  private
37
37
 
38
+ def reset_if_forked
39
+ return unless super
40
+
41
+ @mutex = Mutex.new
42
+ @pending_aggregates = {}
43
+ end
44
+
38
45
  def init_aggregates(aggregation_key)
39
46
  aggregates = { started: aggregation_key.iso8601 }
40
47
  Session::AGGREGATE_STATUSES.each { |k| aggregates[k] = 0 }
@@ -4,6 +4,8 @@ module Sentry
4
4
  # Ruby Logger support Add commentMore actions
5
5
  # intercepts any logger instance and send the log to Sentry too.
6
6
  module StdLibLogger
7
+ include CallbackHelper
8
+
7
9
  SEVERITY_MAP = {
8
10
  0 => :debug,
9
11
  1 => :info,
@@ -37,8 +39,12 @@ module Sentry
37
39
  message = message.to_s.strip
38
40
 
39
41
  if !message.nil? && message != Sentry::Logger::PROGNAME && method = SEVERITY_MAP[severity]
40
- if (filter = Sentry.configuration.std_lib_logger_filter) && !filter.call(self, message, method)
41
- return result
42
+ if filter = Sentry.configuration.std_lib_logger_filter
43
+ return result unless safe_dispatch_callback(
44
+ "std_lib_logger_filter",
45
+ filter,
46
+ [self, message, method]
47
+ )
42
48
  end
43
49
 
44
50
  Sentry.logger.send(method, message, origin: ORIGIN)
@@ -12,7 +12,10 @@ module Sentry
12
12
  #
13
13
  # @!visibility private
14
14
  class TelemetryEventBuffer < ThreadedPeriodicWorker
15
+ include CallbackHelper
16
+
15
17
  FLUSH_INTERVAL = 5 # seconds
18
+ FLUSH_TIMEOUT = 2 # seconds
16
19
 
17
20
  # @!visibility private
18
21
  attr_reader :pending_items, :envelope_type, :data_category, :thread
@@ -21,6 +24,7 @@ module Sentry
21
24
  super(configuration.sdk_logger, FLUSH_INTERVAL)
22
25
 
23
26
  @client = client
27
+ @configuration = configuration
24
28
  @dsn = configuration.dsn
25
29
  @debug = configuration.debug
26
30
  @event_class = event_class
@@ -38,39 +42,44 @@ module Sentry
38
42
  end
39
43
 
40
44
  def flush
41
- @mutex.synchronize do
42
- return if empty?
43
-
44
- log_debug("[#{self.class}] flushing #{size} #{@event_class}")
45
+ return unless thread&.alive? && wake
45
46
 
46
- send_items
47
- end
47
+ wait_until_idle(FLUSH_TIMEOUT)
48
+ end
48
49
 
49
- self
50
+ def run
51
+ flush_pending_items
50
52
  end
51
- alias_method :run, :flush
52
53
 
53
54
  def add_item(item)
55
+ # the buffer thread can never add telemetry itself to prevent recursion
56
+ return self if Thread.current == thread
57
+ return unless ensure_thread
58
+
54
59
  # Prevent ThreadError from re-entrant locking (e.g. transport instrumentation calling Sentry.metrics.*)
55
60
  return self if @mutex.owned?
56
61
 
57
- @mutex.synchronize do
58
- return unless ensure_thread
59
-
62
+ dropped = false
63
+ size_exceeded = @mutex.synchronize do
60
64
  if size >= @max_items_before_drop
61
- log_debug("[#{self.class}] exceeded max capacity, dropping event")
62
- @client.transport.record_lost_event(
63
- :queue_overflow,
64
- @data_category,
65
- num_bytes: JSON.generate(item.to_h).bytesize
66
- )
65
+ dropped = true
67
66
  else
68
67
  @pending_items << item
69
68
  end
70
69
 
71
- send_items if size >= @max_items
70
+ size >= @max_items
71
+ end
72
+
73
+ if dropped
74
+ log_debug("[#{self.class}] exceeded max capacity, dropping event")
75
+ @client.transport.record_lost_event(
76
+ :queue_overflow,
77
+ @data_category,
78
+ num_bytes: JSON.generate(item.to_h).bytesize
79
+ )
72
80
  end
73
81
 
82
+ wake if size_exceeded
74
83
  self
75
84
  end
76
85
 
@@ -88,21 +97,40 @@ module Sentry
88
97
 
89
98
  private
90
99
 
91
- def send_items
92
- envelope = Envelope.new(
93
- event_id: Sentry::Utils.uuid,
94
- sent_at: Sentry.utc_now.iso8601,
95
- dsn: @dsn,
96
- sdk: Sentry.sdk_meta
97
- )
100
+ def reset_if_forked
101
+ return unless super
102
+
103
+ # Discard items inherited from the parent to avoid duplicate delivery.
104
+ @mutex = Mutex.new
105
+ @pending_items = []
106
+ end
107
+
108
+ def flush_pending_items
109
+ pending_items = @mutex.synchronize do
110
+ next if @pending_items.empty?
111
+
112
+ items = @pending_items
113
+ @pending_items = []
114
+ items
115
+ end
116
+
117
+ return unless pending_items
118
+
119
+ log_debug("[#{self.class}] flushing #{pending_items.size} #{@event_class}")
120
+ send_items(pending_items)
121
+ self
122
+ end
123
+
124
+ def send_items(pending_items)
125
+ envelope = Envelope.new(sent_at: Sentry.utc_now.iso8601)
98
126
 
99
127
  discarded_count = 0
100
128
  discarded_bytes = 0
101
129
  envelope_items = []
102
130
 
103
- if @before_send
104
- @pending_items.each do |item|
105
- processed_item = @before_send.call(item)
131
+ if callback = @configuration.send(@before_send)
132
+ pending_items.each do |item|
133
+ processed_item = safe_dispatch_callback(@before_send.to_s, callback, [item])
106
134
 
107
135
  if processed_item
108
136
  envelope_items << processed_item.to_h
@@ -112,7 +140,7 @@ module Sentry
112
140
  end
113
141
  end
114
142
  else
115
- envelope_items = @pending_items.map(&:to_h)
143
+ envelope_items = pending_items.map(&:to_h)
116
144
  end
117
145
 
118
146
  unless discarded_count.zero?
@@ -133,8 +161,6 @@ module Sentry
133
161
  @client.send_envelope(envelope)
134
162
  rescue => e
135
163
  log_error("[#{self.class}] Failed to send #{@event_class}", e, debug: @debug)
136
- ensure
137
- clear!
138
164
  end
139
165
  end
140
166
  end
@@ -127,6 +127,8 @@ module Sentry
127
127
  end
128
128
 
129
129
  def sentry_logs
130
+ Sentry.get_current_client&.log_event_buffer&.flush
131
+
130
132
  sentry_envelopes
131
133
  .flat_map(&:items)
132
134
  .select { |item| item.headers[:type] == "log" }
@@ -134,6 +136,8 @@ module Sentry
134
136
  end
135
137
 
136
138
  def sentry_metrics
139
+ Sentry.get_current_client&.metric_event_buffer&.flush
140
+
137
141
  sentry_envelopes
138
142
  .flat_map(&:items)
139
143
  .select { |item| item.headers[:type] == "trace_metric" }