sentry-ruby 5.28.1 → 6.5.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +26 -2
  3. data/README.md +3 -3
  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/baggage.rb +2 -2
  8. data/lib/sentry/breadcrumb.rb +1 -1
  9. data/lib/sentry/breadcrumb_buffer.rb +2 -2
  10. data/lib/sentry/check_in_event.rb +2 -2
  11. data/lib/sentry/client.rb +57 -135
  12. data/lib/sentry/configuration.rb +155 -75
  13. data/lib/sentry/cron/monitor_check_ins.rb +3 -3
  14. data/lib/sentry/cron/monitor_config.rb +2 -2
  15. data/lib/sentry/cron/monitor_schedule.rb +2 -2
  16. data/lib/sentry/dsn.rb +33 -1
  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/exceptions.rb +3 -0
  21. data/lib/sentry/hub.rb +26 -4
  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 +24 -142
  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 -54
  34. data/lib/sentry/profiler.rb +4 -5
  35. data/lib/sentry/propagation_context.rb +48 -8
  36. data/lib/sentry/rack/capture_exceptions.rb +90 -2
  37. data/lib/sentry/release_detector.rb +1 -1
  38. data/lib/sentry/rspec.rb +1 -1
  39. data/lib/sentry/scope.rb +51 -18
  40. data/lib/sentry/sequel.rb +35 -0
  41. data/lib/sentry/span.rb +5 -17
  42. data/lib/sentry/std_lib_logger.rb +4 -0
  43. data/lib/sentry/telemetry_event_buffer.rb +130 -0
  44. data/lib/sentry/test_helper.rb +8 -0
  45. data/lib/sentry/transaction.rb +53 -103
  46. data/lib/sentry/transaction_event.rb +4 -9
  47. data/lib/sentry/transport/http_transport.rb +7 -11
  48. data/lib/sentry/transport.rb +9 -7
  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/telemetry_attributes.rb +30 -0
  52. data/lib/sentry/vernier/profiler.rb +4 -3
  53. data/lib/sentry/version.rb +1 -1
  54. data/lib/sentry-ruby.rb +53 -30
  55. data/sentry-ruby-core.gemspec +1 -1
  56. data/sentry-ruby.gemspec +2 -1
  57. metadata +27 -16
  58. data/lib/sentry/metrics/aggregator.rb +0 -248
  59. data/lib/sentry/metrics/configuration.rb +0 -57
  60. data/lib/sentry/metrics/counter_metric.rb +0 -25
  61. data/lib/sentry/metrics/distribution_metric.rb +0 -25
  62. data/lib/sentry/metrics/gauge_metric.rb +0 -35
  63. data/lib/sentry/metrics/local_aggregator.rb +0 -53
  64. data/lib/sentry/metrics/metric.rb +0 -19
  65. data/lib/sentry/metrics/set_metric.rb +0 -28
  66. data/lib/sentry/metrics/timing.rb +0 -51
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
  }
@@ -1,134 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sentry/utils/telemetry_attributes"
4
+
3
5
  module Sentry
4
6
  # Event type that represents a log entry with its attributes
5
7
  #
6
8
  # @see https://develop.sentry.dev/sdk/telemetry/logs/#log-envelope-item-payload
7
9
  class LogEvent
10
+ include Sentry::Utils::TelemetryAttributes
11
+
8
12
  TYPE = "log"
9
13
 
10
14
  DEFAULT_PARAMETERS = [].freeze
11
- DEFAULT_ATTRIBUTES = {}.freeze
12
-
13
- SERIALIZEABLE_ATTRIBUTES = %i[
14
- level
15
- body
16
- timestamp
17
- environment
18
- release
19
- server_name
20
- trace_id
21
- attributes
22
- contexts
23
- ]
24
-
25
- SENTRY_ATTRIBUTES = {
26
- "sentry.trace.parent_span_id" => :parent_span_id,
27
- "sentry.environment" => :environment,
28
- "sentry.release" => :release,
29
- "sentry.address" => :server_name,
30
- "sentry.sdk.name" => :sdk_name,
31
- "sentry.sdk.version" => :sdk_version,
32
- "sentry.message.template" => :template,
33
- "sentry.origin" => :origin
34
- }
35
15
 
36
16
  PARAMETER_PREFIX = "sentry.message.parameter"
37
17
 
38
- USER_ATTRIBUTES = {
39
- "user.id" => :user_id,
40
- "user.name" => :user_username,
41
- "user.email" => :user_email
42
- }
43
-
44
18
  LEVELS = %i[trace debug info warn error fatal].freeze
45
19
 
46
- attr_accessor :level, :body, :template, :attributes, :user, :origin
47
-
48
- attr_reader :configuration, *(SERIALIZEABLE_ATTRIBUTES - %i[level body attributes])
49
-
50
- SERIALIZERS = %i[
51
- attributes
52
- body
53
- level
54
- parent_span_id
55
- sdk_name
56
- sdk_version
57
- template
58
- timestamp
59
- trace_id
60
- user_id
61
- user_username
62
- user_email
63
- ].map { |name| [name, :"serialize_#{name}"] }.to_h
64
-
65
- VALUE_TYPES = Hash.new("string").merge!({
66
- TrueClass => "boolean",
67
- FalseClass => "boolean",
68
- Integer => "integer",
69
- Float => "double"
70
- }).freeze
20
+ attr_accessor :level, :body, :template, :attributes, :origin, :trace_id, :span_id
21
+ attr_reader :timestamp
71
22
 
72
23
  TOKEN_REGEXP = /%\{(\w+)\}/
73
24
 
74
- def initialize(configuration: Sentry.configuration, **options)
75
- @configuration = configuration
25
+ def initialize(**options)
76
26
  @type = TYPE
77
- @server_name = configuration.server_name
78
- @environment = configuration.environment
79
- @release = configuration.release
80
27
  @timestamp = Sentry.utc_now
81
28
  @level = options.fetch(:level)
82
29
  @body = options[:body]
83
30
  @template = @body if is_template?
84
- @attributes = options[:attributes] || DEFAULT_ATTRIBUTES
85
- @user = options[:user] || {}
31
+ @attributes = options[:attributes] || {}
86
32
  @origin = options[:origin]
87
- @contexts = {}
33
+ @trace_id = nil
34
+ @span_id = nil
88
35
  end
89
36
 
90
- def to_hash
91
- SERIALIZEABLE_ATTRIBUTES.each_with_object({}) do |name, memo|
92
- memo[name] = serialize(name)
93
- end
37
+ def to_h
38
+ {
39
+ level: level.to_s,
40
+ timestamp: timestamp.to_f,
41
+ trace_id: @trace_id,
42
+ span_id: @span_id,
43
+ body: serialize_body,
44
+ attributes: serialize_attributes
45
+ }.compact
94
46
  end
95
47
 
96
48
  private
97
49
 
98
- def serialize(name)
99
- serializer = SERIALIZERS[name]
100
-
101
- if serializer
102
- __send__(serializer)
103
- else
104
- public_send(name)
105
- end
106
- end
107
-
108
- def serialize_level
109
- level.to_s
110
- end
111
-
112
- def serialize_sdk_name
113
- Sentry.sdk_meta["name"]
114
- end
115
-
116
- def serialize_sdk_version
117
- Sentry.sdk_meta["version"]
118
- end
119
-
120
- def serialize_timestamp
121
- timestamp.to_f
122
- end
123
-
124
- def serialize_trace_id
125
- contexts.dig(:trace, :trace_id)
126
- end
127
-
128
- def serialize_parent_span_id
129
- contexts.dig(:trace, :parent_span_id)
130
- end
131
-
132
50
  def serialize_body
133
51
  if parameters.empty?
134
52
  body
@@ -139,50 +57,14 @@ module Sentry
139
57
  end
140
58
  end
141
59
 
142
- def serialize_user_id
143
- user[:id]
144
- end
145
-
146
- def serialize_user_username
147
- user[:username]
148
- end
149
-
150
- def serialize_user_email
151
- user[:email]
152
- end
153
-
154
- def serialize_template
155
- template if has_parameters?
156
- end
157
-
158
60
  def serialize_attributes
159
- hash = {}
160
-
161
- attributes.each do |key, value|
162
- hash[key] = attribute_hash(value)
163
- end
164
-
165
- SENTRY_ATTRIBUTES.each do |key, name|
166
- if (value = serialize(name))
167
- hash[key] = attribute_hash(value)
168
- end
169
- end
170
-
171
- USER_ATTRIBUTES.each do |key, name|
172
- if (value = serialize(name))
173
- hash[key] = value
174
- end
175
- end
176
-
177
- hash
178
- end
179
-
180
- def attribute_hash(value)
181
- { value: value, type: value_type(value) }
61
+ populate_sentry_attributes!
62
+ @attributes.transform_values! { |v| attribute_hash(v) }
182
63
  end
183
64
 
184
- def value_type(value)
185
- VALUE_TYPES[value.class]
65
+ def populate_sentry_attributes!
66
+ @attributes["sentry.origin"] ||= @origin if @origin
67
+ @attributes["sentry.message.template"] ||= template if has_parameters?
186
68
  end
187
69
 
188
70
  def parameters
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "sentry/threaded_periodic_worker"
3
+ require "sentry/telemetry_event_buffer"
4
4
 
5
5
  module Sentry
6
6
  # LogEventBuffer buffers log events and sends them to Sentry in a single envelope.
@@ -8,68 +8,21 @@ module Sentry
8
8
  # This is used internally by the `Sentry::Client`.
9
9
  #
10
10
  # @!visibility private
11
- class LogEventBuffer < ThreadedPeriodicWorker
12
- FLUSH_INTERVAL = 5 # seconds
11
+ class LogEventBuffer < TelemetryEventBuffer
13
12
  DEFAULT_MAX_EVENTS = 100
14
-
15
- # @!visibility private
16
- attr_reader :pending_events
13
+ MAX_EVENTS_BEFORE_DROP = 1000
17
14
 
18
15
  def initialize(configuration, client)
19
- super(configuration.sdk_logger, FLUSH_INTERVAL)
20
-
21
- @client = client
22
- @pending_events = []
23
- @max_events = configuration.max_log_events || DEFAULT_MAX_EVENTS
24
- @mutex = Mutex.new
25
-
26
- log_debug("[Logging] Initialized buffer with max_events=#{@max_events}, flush_interval=#{FLUSH_INTERVAL}s")
27
- end
28
-
29
- def start
30
- ensure_thread
31
- self
32
- end
33
-
34
- def flush
35
- @mutex.synchronize do
36
- return if empty?
37
-
38
- log_debug("[LogEventBuffer] flushing #{size} log events")
39
-
40
- send_events
41
- end
42
-
43
- log_debug("[LogEventBuffer] flushed #{size} log events")
44
-
45
- self
46
- end
47
- alias_method :run, :flush
48
-
49
- def add_event(event)
50
- raise ArgumentError, "expected a LogEvent, got #{event.class}" unless event.is_a?(LogEvent)
51
-
52
- @mutex.synchronize do
53
- @pending_events << event
54
- send_events if size >= @max_events
55
- end
56
-
57
- self
58
- end
59
-
60
- def empty?
61
- @pending_events.empty?
62
- end
63
-
64
- def size
65
- @pending_events.size
66
- end
67
-
68
- private
69
-
70
- def send_events
71
- @client.send_logs(@pending_events)
72
- @pending_events.clear
16
+ super(
17
+ configuration,
18
+ client,
19
+ event_class: LogEvent,
20
+ max_items: configuration.max_log_events || DEFAULT_MAX_EVENTS,
21
+ max_items_before_drop: MAX_EVENTS_BEFORE_DROP,
22
+ envelope_type: "log",
23
+ envelope_content_type: "application/vnd.sentry.items.log+json",
24
+ before_send: configuration.before_send_log
25
+ )
73
26
  end
74
27
  end
75
28
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sentry/utils/telemetry_attributes"
4
+
5
+ module Sentry
6
+ class MetricEvent
7
+ include Sentry::Utils::TelemetryAttributes
8
+
9
+ attr_reader :name, :type, :value, :unit, :timestamp, :trace_id, :span_id, :attributes
10
+ attr_writer :trace_id, :span_id, :attributes
11
+
12
+ def initialize(
13
+ name:,
14
+ type:,
15
+ value:,
16
+ unit: nil,
17
+ attributes: nil
18
+ )
19
+ @name = name
20
+ @type = type
21
+ @value = value
22
+ @unit = unit
23
+ @attributes = attributes || {}
24
+
25
+ @timestamp = Sentry.utc_now
26
+ @trace_id = nil
27
+ @span_id = nil
28
+ end
29
+
30
+ def to_h
31
+ {
32
+ name: @name,
33
+ type: @type,
34
+ value: @value,
35
+ unit: @unit,
36
+ timestamp: @timestamp.to_f,
37
+ trace_id: @trace_id,
38
+ span_id: @span_id,
39
+ attributes: serialize_attributes
40
+ }.compact
41
+ end
42
+
43
+ private
44
+
45
+ def serialize_attributes
46
+ @attributes.transform_values { |v| attribute_hash(v) }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sentry/telemetry_event_buffer"
4
+
5
+ module Sentry
6
+ # MetricEventBuffer buffers metric events and sends them to Sentry in a single envelope.
7
+ #
8
+ # This is used internally by the `Sentry::Client`.
9
+ #
10
+ # @!visibility private
11
+ class MetricEventBuffer < TelemetryEventBuffer
12
+ DEFAULT_MAX_METRICS = 1000
13
+ MAX_METRICS_BEFORE_DROP = 10_000
14
+
15
+ def initialize(configuration, client)
16
+ super(
17
+ configuration,
18
+ client,
19
+ event_class: MetricEvent,
20
+ max_items: configuration.max_metric_events || DEFAULT_MAX_METRICS,
21
+ max_items_before_drop: MAX_METRICS_BEFORE_DROP,
22
+ envelope_type: "trace_metric",
23
+ envelope_content_type: "application/vnd.sentry.items.trace-metric+json",
24
+ before_send: configuration.before_send_metric
25
+ )
26
+ end
27
+ end
28
+ end
@@ -1,67 +1,60 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "sentry/metrics/metric"
4
- require "sentry/metrics/counter_metric"
5
- require "sentry/metrics/distribution_metric"
6
- require "sentry/metrics/gauge_metric"
7
- require "sentry/metrics/set_metric"
8
- require "sentry/metrics/timing"
9
- require "sentry/metrics/aggregator"
3
+ require "sentry/metric_event"
10
4
 
11
5
  module Sentry
12
6
  module Metrics
13
- DURATION_UNITS = %w[nanosecond microsecond millisecond second minute hour day week]
14
- INFORMATION_UNITS = %w[bit byte kilobyte kibibyte megabyte mebibyte gigabyte gibibyte terabyte tebibyte petabyte pebibyte exabyte exbibyte]
15
- FRACTIONAL_UNITS = %w[ratio percent]
16
-
17
- OP_NAME = "metric.timing"
18
- SPAN_ORIGIN = "auto.metric.timing"
19
-
20
7
  class << self
21
- def increment(key, value = 1.0, unit: "none", tags: {}, timestamp: nil)
22
- log_deprecation
23
- Sentry.metrics_aggregator&.add(:c, key, value, unit: unit, tags: tags, timestamp: timestamp)
24
- end
25
-
26
- def distribution(key, value, unit: "none", tags: {}, timestamp: nil)
27
- log_deprecation
28
- Sentry.metrics_aggregator&.add(:d, key, value, unit: unit, tags: tags, timestamp: timestamp)
8
+ # Increments a counter metric
9
+ # @param name [String] the metric name
10
+ # @param value [Numeric] the value to increment by (default: 1)
11
+ # @param attributes [Hash, nil] additional attributes for the metric (optional)
12
+ # @return [void]
13
+ def count(name, value: 1, attributes: nil)
14
+ return unless Sentry.initialized?
15
+
16
+ Sentry.get_current_hub.capture_metric(
17
+ name: name,
18
+ type: :counter,
19
+ value: value,
20
+ attributes: attributes
21
+ )
29
22
  end
30
23
 
31
- def set(key, value, unit: "none", tags: {}, timestamp: nil)
32
- log_deprecation
33
- Sentry.metrics_aggregator&.add(:s, key, value, unit: unit, tags: tags, timestamp: timestamp)
34
- end
35
-
36
- def gauge(key, value, unit: "none", tags: {}, timestamp: nil)
37
- log_deprecation
38
- Sentry.metrics_aggregator&.add(:g, key, value, unit: unit, tags: tags, timestamp: timestamp)
39
- end
40
-
41
- def timing(key, unit: "second", tags: {}, timestamp: nil, &block)
42
- log_deprecation
43
-
44
- return unless block_given?
45
- return yield unless DURATION_UNITS.include?(unit)
46
-
47
- result, value = Sentry.with_child_span(op: OP_NAME, description: key, origin: SPAN_ORIGIN) do |span|
48
- tags.each { |k, v| span.set_tag(k, v.is_a?(Array) ? v.join(", ") : v.to_s) } if span
49
-
50
- start = Timing.send(unit.to_sym)
51
- result = yield
52
- value = Timing.send(unit.to_sym) - start
53
-
54
- [result, value]
55
- end
56
-
57
- Sentry.metrics_aggregator&.add(:d, key, value, unit: unit, tags: tags, timestamp: timestamp)
58
- result
24
+ # Records a gauge metric
25
+ # @param name [String] the metric name
26
+ # @param value [Numeric] the gauge value
27
+ # @param unit [String, nil] the metric unit (optional)
28
+ # @param attributes [Hash, nil] additional attributes for the metric (optional)
29
+ # @return [void]
30
+ def gauge(name, value, unit: nil, attributes: nil)
31
+ return unless Sentry.initialized?
32
+
33
+ Sentry.get_current_hub.capture_metric(
34
+ name: name,
35
+ type: :gauge,
36
+ value: value,
37
+ unit: unit,
38
+ attributes: attributes
39
+ )
59
40
  end
60
41
 
61
- def log_deprecation
62
- Sentry.sdk_logger.warn(LOGGER_PROGNAME) do
63
- "`Sentry::Metrics` is now deprecated and will be removed in the next major."
64
- end
42
+ # Records a distribution metric
43
+ # @param name [String] the metric name
44
+ # @param value [Numeric] the distribution value
45
+ # @param unit [String, nil] the metric unit (optional)
46
+ # @param attributes [Hash, nil] additional attributes for the metric (optional)
47
+ # @return [void]
48
+ def distribution(name, value, unit: nil, attributes: nil)
49
+ return unless Sentry.initialized?
50
+
51
+ Sentry.get_current_hub.capture_metric(
52
+ name: name,
53
+ type: :distribution,
54
+ value: value,
55
+ unit: unit,
56
+ attributes: attributes
57
+ )
65
58
  end
66
59
  end
67
60
  end