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.
- checksums.yaml +4 -4
- data/Gemfile +26 -2
- data/README.md +3 -3
- data/lib/sentry/background_worker.rb +1 -4
- data/lib/sentry/backtrace/line.rb +99 -0
- data/lib/sentry/backtrace.rb +44 -76
- data/lib/sentry/baggage.rb +2 -2
- data/lib/sentry/breadcrumb.rb +1 -1
- data/lib/sentry/breadcrumb_buffer.rb +2 -2
- data/lib/sentry/check_in_event.rb +2 -2
- data/lib/sentry/client.rb +57 -135
- data/lib/sentry/configuration.rb +155 -75
- data/lib/sentry/cron/monitor_check_ins.rb +3 -3
- data/lib/sentry/cron/monitor_config.rb +2 -2
- data/lib/sentry/cron/monitor_schedule.rb +2 -2
- data/lib/sentry/dsn.rb +33 -1
- data/lib/sentry/envelope/item.rb +3 -3
- data/lib/sentry/error_event.rb +3 -3
- data/lib/sentry/event.rb +4 -10
- data/lib/sentry/exceptions.rb +3 -0
- data/lib/sentry/hub.rb +26 -4
- data/lib/sentry/interface.rb +1 -1
- data/lib/sentry/interfaces/exception.rb +2 -2
- data/lib/sentry/interfaces/request.rb +2 -0
- data/lib/sentry/interfaces/single_exception.rb +4 -4
- data/lib/sentry/interfaces/stacktrace.rb +3 -3
- data/lib/sentry/interfaces/stacktrace_builder.rb +0 -8
- data/lib/sentry/interfaces/threads.rb +2 -2
- data/lib/sentry/log_event.rb +24 -142
- data/lib/sentry/log_event_buffer.rb +13 -60
- data/lib/sentry/metric_event.rb +49 -0
- data/lib/sentry/metric_event_buffer.rb +28 -0
- data/lib/sentry/metrics.rb +47 -54
- data/lib/sentry/profiler.rb +4 -5
- data/lib/sentry/propagation_context.rb +48 -8
- data/lib/sentry/rack/capture_exceptions.rb +90 -2
- data/lib/sentry/release_detector.rb +1 -1
- data/lib/sentry/rspec.rb +1 -1
- data/lib/sentry/scope.rb +51 -18
- data/lib/sentry/sequel.rb +35 -0
- data/lib/sentry/span.rb +5 -17
- data/lib/sentry/std_lib_logger.rb +4 -0
- data/lib/sentry/telemetry_event_buffer.rb +130 -0
- data/lib/sentry/test_helper.rb +8 -0
- data/lib/sentry/transaction.rb +53 -103
- data/lib/sentry/transaction_event.rb +4 -9
- data/lib/sentry/transport/http_transport.rb +7 -11
- data/lib/sentry/transport.rb +9 -7
- data/lib/sentry/utils/encoding_helper.rb +6 -0
- data/lib/sentry/utils/logging_helper.rb +25 -9
- data/lib/sentry/utils/telemetry_attributes.rb +30 -0
- data/lib/sentry/vernier/profiler.rb +4 -3
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +53 -30
- data/sentry-ruby-core.gemspec +1 -1
- data/sentry-ruby.gemspec +2 -1
- metadata +27 -16
- data/lib/sentry/metrics/aggregator.rb +0 -248
- data/lib/sentry/metrics/configuration.rb +0 -57
- data/lib/sentry/metrics/counter_metric.rb +0 -25
- data/lib/sentry/metrics/distribution_metric.rb +0 -25
- data/lib/sentry/metrics/gauge_metric.rb +0 -35
- data/lib/sentry/metrics/local_aggregator.rb +0 -53
- data/lib/sentry/metrics/metric.rb +0 -19
- data/lib/sentry/metrics/set_metric.rb +0 -28
- 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
|
|
119
|
+
transaction ||= Transaction.new(**options)
|
|
120
120
|
|
|
121
121
|
sampling_context = {
|
|
122
|
-
transaction_context: transaction.
|
|
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,
|
data/lib/sentry/interface.rb
CHANGED
|
@@ -32,10 +32,10 @@ module Sentry
|
|
|
32
32
|
@mechanism = mechanism
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def
|
|
35
|
+
def to_h
|
|
36
36
|
data = super
|
|
37
|
-
data[:stacktrace] = data[:stacktrace].
|
|
38
|
-
data[:mechanism] = data[:mechanism].
|
|
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
|
|
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
|
|
15
|
-
{ frames: @frames.map(&:
|
|
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
|
|
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
|
|
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&.
|
|
24
|
+
stacktrace: @stacktrace&.to_h
|
|
25
25
|
}
|
|
26
26
|
]
|
|
27
27
|
}
|
data/lib/sentry/log_event.rb
CHANGED
|
@@ -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, :
|
|
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(
|
|
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] ||
|
|
85
|
-
@user = options[:user] || {}
|
|
31
|
+
@attributes = options[:attributes] || {}
|
|
86
32
|
@origin = options[:origin]
|
|
87
|
-
@
|
|
33
|
+
@trace_id = nil
|
|
34
|
+
@span_id = nil
|
|
88
35
|
end
|
|
89
36
|
|
|
90
|
-
def
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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
|
|
185
|
-
|
|
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/
|
|
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 <
|
|
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(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
data/lib/sentry/metrics.rb
CHANGED
|
@@ -1,67 +1,60 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "sentry/
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Sentry.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|