sentry-ruby 5.28.1 → 6.3.1

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +25 -1
  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 +57 -135
  11. data/lib/sentry/configuration.rb +117 -75
  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/envelope/item.rb +3 -3
  16. data/lib/sentry/error_event.rb +3 -3
  17. data/lib/sentry/event.rb +4 -10
  18. data/lib/sentry/hub.rb +26 -4
  19. data/lib/sentry/interface.rb +1 -1
  20. data/lib/sentry/interfaces/exception.rb +2 -2
  21. data/lib/sentry/interfaces/request.rb +2 -0
  22. data/lib/sentry/interfaces/single_exception.rb +4 -4
  23. data/lib/sentry/interfaces/stacktrace.rb +3 -3
  24. data/lib/sentry/interfaces/stacktrace_builder.rb +0 -8
  25. data/lib/sentry/interfaces/threads.rb +2 -2
  26. data/lib/sentry/log_event.rb +24 -142
  27. data/lib/sentry/log_event_buffer.rb +13 -60
  28. data/lib/sentry/metric_event.rb +49 -0
  29. data/lib/sentry/metric_event_buffer.rb +28 -0
  30. data/lib/sentry/metrics.rb +47 -54
  31. data/lib/sentry/profiler.rb +4 -5
  32. data/lib/sentry/rack/capture_exceptions.rb +5 -1
  33. data/lib/sentry/rspec.rb +1 -1
  34. data/lib/sentry/scope.rb +50 -18
  35. data/lib/sentry/sequel.rb +35 -0
  36. data/lib/sentry/span.rb +2 -17
  37. data/lib/sentry/std_lib_logger.rb +4 -0
  38. data/lib/sentry/telemetry_event_buffer.rb +130 -0
  39. data/lib/sentry/test_helper.rb +8 -0
  40. data/lib/sentry/transaction.rb +52 -103
  41. data/lib/sentry/transaction_event.rb +4 -9
  42. data/lib/sentry/transport.rb +2 -5
  43. data/lib/sentry/utils/encoding_helper.rb +6 -0
  44. data/lib/sentry/utils/logging_helper.rb +25 -9
  45. data/lib/sentry/utils/telemetry_attributes.rb +30 -0
  46. data/lib/sentry/vernier/profiler.rb +4 -3
  47. data/lib/sentry/version.rb +1 -1
  48. data/lib/sentry-ruby.rb +53 -30
  49. data/sentry-ruby-core.gemspec +1 -1
  50. data/sentry-ruby.gemspec +2 -1
  51. metadata +27 -16
  52. data/lib/sentry/metrics/aggregator.rb +0 -248
  53. data/lib/sentry/metrics/configuration.rb +0 -57
  54. data/lib/sentry/metrics/counter_metric.rb +0 -25
  55. data/lib/sentry/metrics/distribution_metric.rb +0 -25
  56. data/lib/sentry/metrics/gauge_metric.rb +0 -35
  57. data/lib/sentry/metrics/local_aggregator.rb +0 -53
  58. data/lib/sentry/metrics/metric.rb +0 -19
  59. data/lib/sentry/metrics/set_metric.rb +0 -28
  60. data/lib/sentry/metrics/timing.rb +0 -51
@@ -9,12 +9,12 @@ require "sentry/dsn"
9
9
  require "sentry/release_detector"
10
10
  require "sentry/transport/configuration"
11
11
  require "sentry/cron/configuration"
12
- require "sentry/metrics/configuration"
13
12
  require "sentry/linecache"
14
13
  require "sentry/interfaces/stacktrace_builder"
15
14
  require "sentry/logger"
16
15
  require "sentry/structured_logger"
17
16
  require "sentry/log_event_buffer"
17
+ require "sentry/metric_event_buffer"
18
18
 
19
19
  module Sentry
20
20
  class Configuration
@@ -31,13 +31,6 @@ module Sentry
31
31
  # @return [Regexp, nil]
32
32
  attr_accessor :app_dirs_pattern
33
33
 
34
- # Provide an object that responds to `call` to send events asynchronously.
35
- # E.g.: lambda { |event| Thread.new { Sentry.send_event(event) } }
36
- #
37
- # @deprecated It will be removed in the next major release. Please read https://github.com/getsentry/sentry-ruby/issues/1522 for more information
38
- # @return [Proc, nil]
39
- attr_reader :async
40
-
41
34
  # to send events in a non-blocking way, sentry-ruby has its own background worker
42
35
  # by default, the worker holds a thread pool that has [the number of processors] threads
43
36
  # but you can configure it with this configuration option
@@ -75,11 +68,10 @@ module Sentry
75
68
  # @return [Proc]
76
69
  attr_reader :before_breadcrumb
77
70
 
78
- # Optional Proc, called before sending an event to the server
71
+ # Optional Proc, called before sending an error event to the server
79
72
  # @example
80
73
  # config.before_send = lambda do |event, hint|
81
74
  # # skip ZeroDivisionError exceptions
82
- # # note: hint[:exception] would be a String if you use async callback
83
75
  # if hint[:exception].is_a?(ZeroDivisionError)
84
76
  # nil
85
77
  # else
@@ -89,7 +81,7 @@ module Sentry
89
81
  # @return [Proc]
90
82
  attr_reader :before_send
91
83
 
92
- # Optional Proc, called before sending an event to the server
84
+ # Optional Proc, called before sending a transaction event to the server
93
85
  # @example
94
86
  # config.before_send_transaction = lambda do |event, hint|
95
87
  # # skip unimportant transactions or strip sensitive data
@@ -102,6 +94,18 @@ module Sentry
102
94
  # @return [Proc]
103
95
  attr_reader :before_send_transaction
104
96
 
97
+ # Optional Proc, called before sending a check-in event to the server
98
+ # @example
99
+ # config.before_send_check_in = lambda do |event, hint|
100
+ # if event.monitor_slug == "unimportant_job"
101
+ # nil
102
+ # else
103
+ # event
104
+ # end
105
+ # end
106
+ # @return [Proc]
107
+ attr_reader :before_send_check_in
108
+
105
109
  # Optional Proc, called before sending an event to the server
106
110
  # @example
107
111
  # config.before_send_log = lambda do |log|
@@ -118,7 +122,6 @@ module Sentry
118
122
  #
119
123
  # And if you also use sentry-rails:
120
124
  # - :active_support_logger
121
- # - :monotonic_active_support_logger
122
125
  #
123
126
  # @return [Array<Symbol>]
124
127
  attr_reader :breadcrumbs_logger
@@ -145,7 +148,7 @@ module Sentry
145
148
  attr_reader :dsn
146
149
 
147
150
  # Whitelist of enabled_environments that will send notifications to Sentry. Array of Strings.
148
- # @return [Array<String>]
151
+ # @return [Array<String>, nil]
149
152
  attr_accessor :enabled_environments
150
153
 
151
154
  # Logger 'progname's to exclude from breadcrumbs
@@ -174,18 +177,6 @@ module Sentry
174
177
  # @return [Boolean, String]
175
178
  attr_accessor :spotlight
176
179
 
177
- # @deprecated Use {#include_local_variables} instead.
178
- alias_method :capture_exception_frame_locals, :include_local_variables
179
-
180
- # @deprecated Use {#include_local_variables=} instead.
181
- def capture_exception_frame_locals=(value)
182
- log_warn <<~MSG
183
- `capture_exception_frame_locals` is now deprecated in favor of `include_local_variables`.
184
- MSG
185
-
186
- self.include_local_variables = value
187
- end
188
-
189
180
  # You may provide your own LineCache for matching paths with source files.
190
181
  # This may be useful if you need to get source code from places other than the disk.
191
182
  # @see LineCache
@@ -202,18 +193,6 @@ module Sentry
202
193
  # @return [String, nil]
203
194
  attr_accessor :sdk_debug_transport_log_file
204
195
 
205
- # @deprecated Use {#sdk_logger=} instead.
206
- def logger=(logger)
207
- warn "[sentry] `config.logger=` is deprecated. Please use `config.sdk_logger=` instead."
208
- self.sdk_logger = logger
209
- end
210
-
211
- # @deprecated Use {#sdk_logger} instead.
212
- def logger
213
- warn "[sentry] `config.logger` is deprecated. Please use `config.sdk_logger` instead."
214
- self.sdk_logger
215
- end
216
-
217
196
  # Project directory root for in_app detection. Could be Rails root, etc.
218
197
  # Set automatically for Rails.
219
198
  # @return [String]
@@ -273,10 +252,6 @@ module Sentry
273
252
  # @return [Cron::Configuration]
274
253
  attr_reader :cron
275
254
 
276
- # Metrics related configuration.
277
- # @return [Metrics::Configuration]
278
- attr_reader :metrics
279
-
280
255
  # Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
281
256
  # @return [Float, nil]
282
257
  attr_reader :traces_sample_rate
@@ -299,12 +274,6 @@ module Sentry
299
274
  # @return [StructuredLoggingConfiguration]
300
275
  attr_reader :structured_logging
301
276
 
302
- # Easier way to use performance tracing
303
- # If set to true, will set traces_sample_rate to 1.0
304
- # @deprecated It will be removed in the next major release.
305
- # @return [Boolean, nil]
306
- attr_reader :enable_tracing
307
-
308
277
  # Send diagnostic client reports about dropped events, true by default
309
278
  # tries to attach to an existing envelope max once every 30s
310
279
  # @return [Boolean]
@@ -325,6 +294,18 @@ module Sentry
325
294
  # @return [Array<String, Regexp>]
326
295
  attr_accessor :trace_propagation_targets
327
296
 
297
+ # Collection of HTTP status codes or ranges of codes to ignore when tracing incoming requests.
298
+ # If a transaction's http.response.status_code matches one of these values,
299
+ # the transaction will be dropped and marked as not sampled.
300
+ # Defaults to TRACE_IGNORE_STATUS_CODES_DEFAULT.
301
+ #
302
+ # @example
303
+ # # ignore 404 and 502 <= status_code <= 511
304
+ # config.trace_ignore_status_codes = [404, (502..511)]
305
+ #
306
+ # @return [Array<Integer>, Array<Range>]
307
+ attr_reader :trace_ignore_status_codes
308
+
328
309
  # The instrumenter to use, :sentry or :otel
329
310
  # @return [Symbol]
330
311
  attr_reader :instrumenter
@@ -339,6 +320,15 @@ module Sentry
339
320
  # @return [Float, nil]
340
321
  attr_reader :profiles_sample_rate
341
322
 
323
+ # Interval in microseconds at which to take samples.
324
+ # The default is 1e6 / 101, or 101Hz.
325
+ # Note that the 101 is intentional to avoid lockstep sampling.
326
+ #
327
+ # @example
328
+ # config.profiles_sample_interval = 1e5 / 101
329
+ # @return [Float]
330
+ attr_accessor :profiles_sample_interval
331
+
342
332
  # Array of patches to apply.
343
333
  # Default is {DEFAULT_PATCHES}
344
334
  # @return [Array<Symbol>]
@@ -348,6 +338,32 @@ module Sentry
348
338
  # @return [Integer]
349
339
  attr_accessor :max_log_events
350
340
 
341
+ # Enable metrics collection, defaults to true
342
+ # @return [Boolean]
343
+ attr_accessor :enable_metrics
344
+
345
+ # Maximum number of metric events to buffer before sending
346
+ # @return [Integer]
347
+ attr_accessor :max_metric_events
348
+
349
+ # Optional Proc, called before sending a metric
350
+ # @example
351
+ # config.before_send_metric = lambda do |metric|
352
+ # # return nil to drop the metric
353
+ # metric
354
+ # end
355
+ # @return [Proc, nil]
356
+ attr_reader :before_send_metric
357
+
358
+ # Optional Proc, called to filter log messages before sending to Sentry
359
+ # @example
360
+ # config.std_lib_logger_filter = lambda do |logger, message, level|
361
+ # # Only send error and fatal logs to Sentry
362
+ # [:error, :fatal].include?(level)
363
+ # end
364
+ # @return [Proc, nil]
365
+ attr_reader :std_lib_logger_filter
366
+
351
367
  # these are not config options
352
368
  # @!visibility private
353
369
  attr_reader :errors, :gem_specs
@@ -376,6 +392,8 @@ module Sentry
376
392
  SERVER_PORT
377
393
  ].freeze
378
394
 
395
+ TRACE_IGNORE_STATUS_CODES_DEFAULT = [(301..303), (305..399), (401..404)]
396
+
379
397
  HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
380
398
  "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
381
399
 
@@ -391,6 +409,9 @@ module Sentry
391
409
 
392
410
  APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/
393
411
 
412
+ # 101 Hz in microseconds
413
+ DEFAULT_PROFILES_SAMPLE_INTERVAL = 1e6 / 101
414
+
394
415
  class << self
395
416
  # Post initialization callbacks are called at the end of initialization process
396
417
  # allowing extending the configuration of sentry-ruby by multiple extensions
@@ -473,7 +494,7 @@ module Sentry
473
494
  self.context_lines = 3
474
495
  self.include_local_variables = false
475
496
  self.environment = environment_from_env
476
- self.enabled_environments = []
497
+ self.enabled_environments = nil
477
498
  self.exclude_loggers = []
478
499
  self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
479
500
  self.inspect_exception_causes_for_exclusion = true
@@ -498,25 +519,30 @@ module Sentry
498
519
  self.server_name = server_name_from_env
499
520
  self.instrumenter = :sentry
500
521
  self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
522
+ self.trace_ignore_status_codes = TRACE_IGNORE_STATUS_CODES_DEFAULT
501
523
  self.enabled_patches = DEFAULT_PATCHES.dup
502
524
 
503
525
  self.before_send = nil
504
526
  self.before_send_transaction = nil
527
+ self.before_send_check_in = nil
505
528
  self.before_send_log = nil
529
+ self.before_send_metric = nil
530
+ self.std_lib_logger_filter = nil
506
531
  self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
507
532
  self.traces_sampler = nil
508
- self.enable_tracing = nil
509
533
  self.enable_logs = false
534
+ self.enable_metrics = true
510
535
 
511
536
  self.profiler_class = Sentry::Profiler
537
+ self.profiles_sample_interval = DEFAULT_PROFILES_SAMPLE_INTERVAL
512
538
 
513
539
  @transport = Transport::Configuration.new
514
540
  @cron = Cron::Configuration.new
515
- @metrics = Metrics::Configuration.new(self.sdk_logger)
516
541
  @structured_logging = StructuredLoggingConfiguration.new
517
542
  @gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
518
543
 
519
544
  self.max_log_events = LogEventBuffer::DEFAULT_MAX_EVENTS
545
+ self.max_metric_events = MetricEventBuffer::DEFAULT_MAX_METRICS
520
546
 
521
547
  run_callbacks(:after, :initialize)
522
548
 
@@ -555,22 +581,6 @@ module Sentry
555
581
  @release = value
556
582
  end
557
583
 
558
- def async=(value)
559
- check_callable!("async", value)
560
-
561
- log_warn <<~MSG
562
-
563
- sentry-ruby now sends events asynchronously by default with its background worker (supported since 4.1.0).
564
- The `config.async` callback has become redundant while continuing to cause issues.
565
- (The problems of `async` are detailed in https://github.com/getsentry/sentry-ruby/issues/1522)
566
-
567
- Therefore, we encourage you to remove it and let the background worker take care of async job sending.
568
- It's deprecation is planned in the next major release (6.0), which is scheduled around the 3rd quarter of 2022.
569
- MSG
570
-
571
- @async = value
572
- end
573
-
574
584
  def breadcrumbs_logger=(logger)
575
585
  loggers =
576
586
  if logger.is_a?(Array)
@@ -596,12 +606,30 @@ module Sentry
596
606
  @before_send_transaction = value
597
607
  end
598
608
 
609
+ def before_send_check_in=(value)
610
+ check_callable!("before_send_check_in", value)
611
+
612
+ @before_send_check_in = value
613
+ end
614
+
615
+ def before_send_metric=(value)
616
+ check_callable!("before_send_metric", value)
617
+
618
+ @before_send_metric = value
619
+ end
620
+
599
621
  def before_breadcrumb=(value)
600
622
  check_callable!("before_breadcrumb", value)
601
623
 
602
624
  @before_breadcrumb = value
603
625
  end
604
626
 
627
+ def std_lib_logger_filter=(value)
628
+ check_callable!("std_lib_logger_filter", value)
629
+
630
+ @std_lib_logger_filter = value
631
+ end
632
+
605
633
  def environment=(environment)
606
634
  @environment = environment.to_s
607
635
  end
@@ -610,15 +638,12 @@ module Sentry
610
638
  @instrumenter = INSTRUMENTERS.include?(instrumenter) ? instrumenter : :sentry
611
639
  end
612
640
 
613
- def enable_tracing=(enable_tracing)
614
- unless enable_tracing.nil?
615
- log_warn <<~MSG
616
- `enable_tracing` is now deprecated in favor of `traces_sample_rate = 1.0`.
617
- MSG
641
+ def trace_ignore_status_codes=(codes)
642
+ unless codes.is_a?(Array) && codes.all? { |code| valid_status_code_entry?(code) }
643
+ raise ArgumentError, "trace_ignore_status_codes must be an Array of integers or ranges between (100-599) where begin <= end"
618
644
  end
619
645
 
620
- @enable_tracing = enable_tracing
621
- @traces_sample_rate ||= 1.0 if enable_tracing
646
+ @trace_ignore_status_codes = codes
622
647
  end
623
648
 
624
649
  def traces_sample_rate=(traces_sample_rate)
@@ -674,7 +699,7 @@ module Sentry
674
699
  end
675
700
 
676
701
  def enabled_in_current_env?
677
- enabled_environments.empty? || enabled_environments.include?(environment)
702
+ enabled_environments.nil? || enabled_environments.include?(environment)
678
703
  end
679
704
 
680
705
  def valid_sample_rate?(sample_rate)
@@ -685,7 +710,7 @@ module Sentry
685
710
  def tracing_enabled?
686
711
  valid_sampler = !!((valid_sample_rate?(@traces_sample_rate)) || @traces_sampler)
687
712
 
688
- (@enable_tracing != false) && valid_sampler && sending_allowed?
713
+ valid_sampler && sending_allowed?
689
714
  end
690
715
 
691
716
  def profiling_enabled?
@@ -816,6 +841,23 @@ module Sentry
816
841
  available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
817
842
  available_processor_count || Concurrent.processor_count
818
843
  end
844
+
845
+ def valid_http_status_code?(code)
846
+ code.is_a?(Integer) && code >= 100 && code <= 599
847
+ end
848
+
849
+ def valid_status_code_entry?(entry)
850
+ case entry
851
+ when Integer
852
+ valid_http_status_code?(entry)
853
+ when Range
854
+ valid_http_status_code?(entry.begin) &&
855
+ valid_http_status_code?(entry.end) &&
856
+ entry.begin <= entry.end
857
+ else
858
+ false
859
+ end
860
+ end
819
861
  end
820
862
 
821
863
  class StructuredLoggingConfiguration
@@ -14,12 +14,12 @@ module Sentry
14
14
  :in_progress,
15
15
  monitor_config: monitor_config)
16
16
 
17
- start = Metrics::Timing.duration_start
17
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
18
18
 
19
19
  begin
20
20
  # need to do this on ruby <= 2.6 sadly
21
21
  ret = method(:perform).super_method.arity == 0 ? super() : super
22
- duration = Metrics::Timing.duration_end(start)
22
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
23
23
 
24
24
  Sentry.capture_check_in(slug,
25
25
  :ok,
@@ -29,7 +29,7 @@ module Sentry
29
29
 
30
30
  ret
31
31
  rescue Exception
32
- duration = Metrics::Timing.duration_end(start)
32
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
33
33
 
34
34
  Sentry.capture_check_in(slug,
35
35
  :error,
@@ -40,9 +40,9 @@ module Sentry
40
40
  new(MonitorSchedule::Interval.new(num, unit), **options)
41
41
  end
42
42
 
43
- def to_hash
43
+ def to_h
44
44
  {
45
- schedule: schedule.to_hash,
45
+ schedule: schedule.to_h,
46
46
  checkin_margin: checkin_margin,
47
47
  max_runtime: max_runtime,
48
48
  timezone: timezone
@@ -12,7 +12,7 @@ module Sentry
12
12
  @value = value
13
13
  end
14
14
 
15
- def to_hash
15
+ def to_h
16
16
  { type: :crontab, value: value }
17
17
  end
18
18
  end
@@ -33,7 +33,7 @@ module Sentry
33
33
  @unit = unit
34
34
  end
35
35
 
36
- def to_hash
36
+ def to_h
37
37
  { type: :interval, value: value, unit: unit }
38
38
  end
39
39
  end
@@ -3,7 +3,7 @@
3
3
  module Sentry
4
4
  # @api private
5
5
  class Envelope::Item
6
- STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
6
+ STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 1000
7
7
  MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
8
8
 
9
9
  SIZE_LIMITS = Hash.new(MAX_SERIALIZED_PAYLOAD_SIZE).update(
@@ -15,10 +15,10 @@ module Sentry
15
15
  # rate limits and client reports use the data_category rather than envelope item type
16
16
  def self.data_category(type)
17
17
  case type
18
- when "session", "attachment", "transaction", "profile", "span", "log" then type
18
+ when "session", "attachment", "transaction", "profile", "span", "trace_metric" then type
19
+ when "log" then "log_item"
19
20
  when "sessions" then "session"
20
21
  when "check_in" then "monitor"
21
- when "statsd", "metric_meta" then "metric_bucket"
22
22
  when "event" then "error"
23
23
  when "client_report" then "internal"
24
24
  else "default"
@@ -10,10 +10,10 @@ module Sentry
10
10
  attr_reader :threads
11
11
 
12
12
  # @return [Hash]
13
- def to_hash
13
+ def to_h
14
14
  data = super
15
- data[:threads] = threads.to_hash if threads
16
- data[:exception] = exception.to_hash if exception
15
+ data[:threads] = threads.to_h if threads
16
+ data[:exception] = exception.to_h if exception
17
17
  data
18
18
  end
19
19
 
data/lib/sentry/event.rb CHANGED
@@ -81,12 +81,6 @@ module Sentry
81
81
  @message = (message || "").byteslice(0..MAX_MESSAGE_SIZE_IN_BYTES)
82
82
  end
83
83
 
84
- # @deprecated This method will be removed in v5.0.0. Please just use Sentry.configuration
85
- # @return [Configuration]
86
- def configuration
87
- Sentry.configuration
88
- end
89
-
90
84
  # Sets the event's timestamp.
91
85
  # @param time [Time, Float]
92
86
  # @return [void]
@@ -118,16 +112,16 @@ module Sentry
118
112
  end
119
113
 
120
114
  # @return [Hash]
121
- def to_hash
115
+ def to_h
122
116
  data = serialize_attributes
123
- data[:breadcrumbs] = breadcrumbs.to_hash if breadcrumbs
124
- data[:request] = request.to_hash if request
117
+ data[:breadcrumbs] = breadcrumbs.to_h if breadcrumbs
118
+ data[:request] = request.to_h if request
125
119
  data
126
120
  end
127
121
 
128
122
  # @return [Hash]
129
123
  def to_json_compatible
130
- JSON.parse(JSON.generate(to_hash))
124
+ JSON.parse(JSON.generate(to_h))
131
125
  end
132
126
 
133
127
  private
data/lib/sentry/hub.rb CHANGED
@@ -116,10 +116,10 @@ module Sentry
116
116
  return unless configuration.tracing_enabled?
117
117
  return unless instrumenter == configuration.instrumenter
118
118
 
119
- transaction ||= Transaction.new(**options.merge(hub: self))
119
+ transaction ||= Transaction.new(**options)
120
120
 
121
121
  sampling_context = {
122
- transaction_context: transaction.to_hash,
122
+ transaction_context: transaction.to_h,
123
123
  parent_sampled: transaction.parent_sampled,
124
124
  parent_sample_rate: transaction.parent_sample_rate
125
125
  }
@@ -218,7 +218,7 @@ module Sentry
218
218
  end
219
219
 
220
220
  def capture_log_event(message, **options)
221
- return unless current_client
221
+ return unless current_client && current_client.configuration.enable_logs
222
222
 
223
223
  event = current_client.event_from_log(message, **options)
224
224
 
@@ -227,6 +227,29 @@ module Sentry
227
227
  current_client.buffer_log_event(event, current_scope)
228
228
  end
229
229
 
230
+ # Captures a metric and sends it to Sentry
231
+ #
232
+ # @param name [String] the metric name
233
+ # @param type [Symbol] the metric type (:counter, :gauge, :distribution)
234
+ # @param value [Numeric] the metric value
235
+ # @param unit [String, nil] (optional) the metric unit
236
+ # @param attributes [Hash, nil] (optional) additional attributes for the metric
237
+ # @return [void]
238
+ def capture_metric(name:, type:, value:, unit: nil, attributes: nil)
239
+ return unless current_client&.configuration.enable_metrics
240
+
241
+ metric = MetricEvent.new(
242
+ name: name,
243
+ value: value,
244
+ type: type,
245
+ unit: unit,
246
+ attributes: attributes,
247
+ )
248
+
249
+ current_client.buffer_metric_event(metric, current_scope)
250
+ end
251
+
252
+
230
253
  def capture_event(event, **options, &block)
231
254
  check_argument_type!(event, Sentry::Event)
232
255
 
@@ -353,7 +376,6 @@ module Sentry
353
376
  return nil unless propagation_context.incoming_trace
354
377
 
355
378
  Transaction.new(
356
- hub: self,
357
379
  trace_id: propagation_context.trace_id,
358
380
  parent_span_id: propagation_context.parent_span_id,
359
381
  parent_sampled: propagation_context.parent_sampled,
@@ -3,7 +3,7 @@
3
3
  module Sentry
4
4
  class Interface
5
5
  # @return [Hash]
6
- def to_hash
6
+ def to_h
7
7
  Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
8
8
  end
9
9
  end
@@ -13,9 +13,9 @@ module Sentry
13
13
  end
14
14
 
15
15
  # @return [Hash]
16
- def to_hash
16
+ def to_h
17
17
  data = super
18
- data[:values] = data[:values].map(&:to_hash) if data[:values]
18
+ data[:values] = data[:values].map(&:to_h) if data[:values]
19
19
  data
20
20
  end
21
21
 
@@ -69,6 +69,8 @@ module Sentry
69
69
  private
70
70
 
71
71
  def read_data_from(request)
72
+ return "Skipped non-rewindable request body" unless request.body.respond_to?(:rewind)
73
+
72
74
  if request.form_data?
73
75
  request.POST
74
76
  elsif request.body # JSON requests, etc
@@ -32,10 +32,10 @@ module Sentry
32
32
  @mechanism = mechanism
33
33
  end
34
34
 
35
- def to_hash
35
+ def to_h
36
36
  data = super
37
- data[:stacktrace] = data[:stacktrace].to_hash if data[:stacktrace]
38
- data[:mechanism] = data[:mechanism].to_hash
37
+ data[:stacktrace] = data[:stacktrace].to_h if data[:stacktrace]
38
+ data[:mechanism] = data[:mechanism].to_h
39
39
  data
40
40
  end
41
41
 
@@ -60,7 +60,7 @@ module Sentry
60
60
  end
61
61
  end
62
62
 
63
- stacktrace.frames.last.vars = locals
63
+ stacktrace.frames.last&.vars = locals
64
64
  end
65
65
 
66
66
  new(exception: exception, stacktrace: stacktrace, mechanism: mechanism)
@@ -11,8 +11,8 @@ module Sentry
11
11
  end
12
12
 
13
13
  # @return [Hash]
14
- def to_hash
15
- { frames: @frames.map(&:to_hash) }
14
+ def to_h
15
+ { frames: @frames.map(&:to_h) }
16
16
  end
17
17
 
18
18
  # @return [String]
@@ -66,7 +66,7 @@ module Sentry
66
66
  linecache.get_file_context(abs_path, lineno, context_lines)
67
67
  end
68
68
 
69
- def to_hash(*args)
69
+ def to_h(*args)
70
70
  data = super(*args)
71
71
  data.delete(:vars) unless vars && !vars.empty?
72
72
  data.delete(:pre_context) unless pre_context && !pre_context.empty?
@@ -75,14 +75,6 @@ module Sentry
75
75
  StacktraceInterface.new(frames: frames)
76
76
  end
77
77
 
78
- # Get the code location hash for a single line for where metrics where added.
79
- # @return [Hash]
80
- def metrics_code_location(unparsed_line)
81
- parsed_line = Backtrace::Line.parse(unparsed_line)
82
- frame = convert_parsed_line_into_frame(parsed_line)
83
- frame.to_hash.reject { |k, _| %i[project_root in_app].include?(k) }
84
- end
85
-
86
78
  private
87
79
 
88
80
  def convert_parsed_line_into_frame(line)
@@ -13,7 +13,7 @@ module Sentry
13
13
  end
14
14
 
15
15
  # @return [Hash]
16
- def to_hash
16
+ def to_h
17
17
  {
18
18
  values: [
19
19
  {
@@ -21,7 +21,7 @@ module Sentry
21
21
  name: @name,
22
22
  crashed: @crashed,
23
23
  current: @current,
24
- stacktrace: @stacktrace&.to_hash
24
+ stacktrace: @stacktrace&.to_h
25
25
  }
26
26
  ]
27
27
  }