sentry-ruby 5.10.0 → 5.17.3
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 +2 -13
- data/README.md +10 -10
- data/Rakefile +1 -1
- data/lib/sentry/background_worker.rb +9 -2
- data/lib/sentry/backpressure_monitor.rb +75 -0
- data/lib/sentry/backtrace.rb +7 -3
- data/lib/sentry/breadcrumb.rb +8 -2
- data/lib/sentry/check_in_event.rb +60 -0
- data/lib/sentry/client.rb +88 -17
- data/lib/sentry/configuration.rb +66 -12
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +75 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- data/lib/sentry/dsn.rb +1 -1
- data/lib/sentry/envelope.rb +19 -2
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +14 -36
- data/lib/sentry/hub.rb +70 -2
- data/lib/sentry/integrable.rb +10 -0
- data/lib/sentry/interface.rb +1 -0
- data/lib/sentry/interfaces/exception.rb +5 -3
- data/lib/sentry/interfaces/mechanism.rb +20 -0
- data/lib/sentry/interfaces/request.rb +2 -2
- data/lib/sentry/interfaces/single_exception.rb +10 -6
- data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
- data/lib/sentry/metrics/aggregator.rb +276 -0
- data/lib/sentry/metrics/configuration.rb +47 -0
- data/lib/sentry/metrics/counter_metric.rb +25 -0
- data/lib/sentry/metrics/distribution_metric.rb +25 -0
- data/lib/sentry/metrics/gauge_metric.rb +35 -0
- data/lib/sentry/metrics/local_aggregator.rb +53 -0
- data/lib/sentry/metrics/metric.rb +19 -0
- data/lib/sentry/metrics/set_metric.rb +28 -0
- data/lib/sentry/metrics/timing.rb +43 -0
- data/lib/sentry/metrics.rb +55 -0
- data/lib/sentry/net/http.rb +25 -22
- data/lib/sentry/profiler.rb +18 -7
- data/lib/sentry/propagation_context.rb +135 -0
- data/lib/sentry/puma.rb +12 -5
- data/lib/sentry/rack/capture_exceptions.rb +7 -5
- data/lib/sentry/rake.rb +3 -14
- data/lib/sentry/redis.rb +8 -3
- data/lib/sentry/release_detector.rb +1 -1
- data/lib/sentry/scope.rb +36 -15
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +1 -6
- data/lib/sentry/span.rb +54 -3
- data/lib/sentry/test_helper.rb +18 -12
- data/lib/sentry/transaction.rb +33 -33
- data/lib/sentry/transaction_event.rb +5 -3
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +68 -37
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +27 -37
- data/lib/sentry/utils/argument_checking_helper.rb +12 -0
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +96 -26
- data/sentry-ruby.gemspec +1 -0
- metadata +35 -2
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
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'
|
10
|
+
|
11
|
+
module Sentry
|
12
|
+
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
|
+
|
19
|
+
class << self
|
20
|
+
def increment(key, value = 1.0, unit: 'none', tags: {}, timestamp: nil)
|
21
|
+
Sentry.metrics_aggregator&.add(:c, key, value, unit: unit, tags: tags, timestamp: timestamp)
|
22
|
+
end
|
23
|
+
|
24
|
+
def distribution(key, value, unit: 'none', tags: {}, timestamp: nil)
|
25
|
+
Sentry.metrics_aggregator&.add(:d, key, value, unit: unit, tags: tags, timestamp: timestamp)
|
26
|
+
end
|
27
|
+
|
28
|
+
def set(key, value, unit: 'none', tags: {}, timestamp: nil)
|
29
|
+
Sentry.metrics_aggregator&.add(:s, key, value, unit: unit, tags: tags, timestamp: timestamp)
|
30
|
+
end
|
31
|
+
|
32
|
+
def gauge(key, value, unit: 'none', tags: {}, timestamp: nil)
|
33
|
+
Sentry.metrics_aggregator&.add(:g, key, value, unit: unit, tags: tags, timestamp: timestamp)
|
34
|
+
end
|
35
|
+
|
36
|
+
def timing(key, unit: 'second', tags: {}, timestamp: nil, &block)
|
37
|
+
return unless block_given?
|
38
|
+
return yield unless DURATION_UNITS.include?(unit)
|
39
|
+
|
40
|
+
result, value = Sentry.with_child_span(op: OP_NAME, description: key) do |span|
|
41
|
+
tags.each { |k, v| span.set_tag(k, v.is_a?(Array) ? v.join(', ') : v.to_s) } if span
|
42
|
+
|
43
|
+
start = Timing.send(unit.to_sym)
|
44
|
+
result = yield
|
45
|
+
value = Timing.send(unit.to_sym) - start
|
46
|
+
|
47
|
+
[result, value]
|
48
|
+
end
|
49
|
+
|
50
|
+
Sentry.metrics_aggregator&.add(:d, key, value, unit: unit, tags: tags, timestamp: timestamp)
|
51
|
+
result
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/sentry/net/http.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "net/http"
|
4
|
+
require "resolv"
|
4
5
|
|
5
6
|
module Sentry
|
6
7
|
# @api private
|
@@ -30,18 +31,21 @@ module Sentry
|
|
30
31
|
return super if from_sentry_sdk?
|
31
32
|
|
32
33
|
Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f) do |sentry_span|
|
33
|
-
|
34
|
+
request_info = extract_request_info(req)
|
35
|
+
|
36
|
+
if propagate_trace?(request_info[:url], Sentry.configuration)
|
37
|
+
set_propagation_headers(req)
|
38
|
+
end
|
34
39
|
|
35
40
|
super.tap do |res|
|
36
|
-
record_sentry_breadcrumb(
|
41
|
+
record_sentry_breadcrumb(request_info, res)
|
37
42
|
|
38
43
|
if sentry_span
|
39
|
-
request_info = extract_request_info(req)
|
40
44
|
sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
|
41
|
-
sentry_span.set_data(
|
42
|
-
sentry_span.set_data(
|
43
|
-
sentry_span.set_data(
|
44
|
-
sentry_span.set_data(
|
45
|
+
sentry_span.set_data(Span::DataConventions::URL, request_info[:url])
|
46
|
+
sentry_span.set_data(Span::DataConventions::HTTP_METHOD, request_info[:method])
|
47
|
+
sentry_span.set_data(Span::DataConventions::HTTP_QUERY, request_info[:query]) if request_info[:query]
|
48
|
+
sentry_span.set_data(Span::DataConventions::HTTP_STATUS_CODE, res.code.to_i)
|
45
49
|
end
|
46
50
|
end
|
47
51
|
end
|
@@ -49,23 +53,13 @@ module Sentry
|
|
49
53
|
|
50
54
|
private
|
51
55
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
client = Sentry.get_current_client
|
56
|
-
|
57
|
-
trace = client.generate_sentry_trace(sentry_span)
|
58
|
-
req[SENTRY_TRACE_HEADER_NAME] = trace if trace
|
59
|
-
|
60
|
-
baggage = client.generate_baggage(sentry_span)
|
61
|
-
req[BAGGAGE_HEADER_NAME] = baggage if baggage && !baggage.empty?
|
56
|
+
def set_propagation_headers(req)
|
57
|
+
Sentry.get_trace_propagation_headers&.each { |k, v| req[k] = v }
|
62
58
|
end
|
63
59
|
|
64
|
-
def record_sentry_breadcrumb(
|
60
|
+
def record_sentry_breadcrumb(request_info, res)
|
65
61
|
return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
|
66
62
|
|
67
|
-
request_info = extract_request_info(req)
|
68
|
-
|
69
63
|
crumb = Sentry::Breadcrumb.new(
|
70
64
|
level: :info,
|
71
65
|
category: BREADCRUMB_CATEGORY,
|
@@ -84,7 +78,10 @@ module Sentry
|
|
84
78
|
end
|
85
79
|
|
86
80
|
def extract_request_info(req)
|
87
|
-
|
81
|
+
# IPv6 url could look like '::1/path', and that won't parse without
|
82
|
+
# wrapping it in square brackets.
|
83
|
+
hostname = address =~ Resolv::IPv6::Regex ? "[#{address}]" : address
|
84
|
+
uri = req.uri || URI.parse("#{use_ssl? ? 'https' : 'http'}://#{hostname}#{req.path}")
|
88
85
|
url = "#{uri.scheme}://#{uri.host}#{uri.path}" rescue uri.to_s
|
89
86
|
|
90
87
|
result = { method: req.method, url: url }
|
@@ -96,8 +93,14 @@ module Sentry
|
|
96
93
|
|
97
94
|
result
|
98
95
|
end
|
96
|
+
|
97
|
+
def propagate_trace?(url, configuration)
|
98
|
+
url &&
|
99
|
+
configuration.propagate_traces &&
|
100
|
+
configuration.trace_propagation_targets.any? { |target| url.match?(target) }
|
101
|
+
end
|
99
102
|
end
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
103
|
-
Sentry.register_patch(Sentry::Net::HTTP, Net::HTTP)
|
106
|
+
Sentry.register_patch(:http, Sentry::Net::HTTP, Net::HTTP)
|
data/lib/sentry/profiler.rb
CHANGED
@@ -9,6 +9,7 @@ module Sentry
|
|
9
9
|
# 101 Hz in microseconds
|
10
10
|
DEFAULT_INTERVAL = 1e6 / 101
|
11
11
|
MICRO_TO_NANO_SECONDS = 1e3
|
12
|
+
MIN_SAMPLES_REQUIRED = 2
|
12
13
|
|
13
14
|
attr_reader :sampled, :started, :event_id
|
14
15
|
|
@@ -73,14 +74,19 @@ module Sentry
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def to_hash
|
76
|
-
|
77
|
+
unless @sampled
|
78
|
+
record_lost_event(:sample_rate)
|
79
|
+
return {}
|
80
|
+
end
|
81
|
+
|
77
82
|
return {} unless @started
|
78
83
|
|
79
84
|
results = StackProf.results
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
85
|
+
|
86
|
+
if !results || results.empty? || results[:samples] == 0 || !results[:raw]
|
87
|
+
record_lost_event(:insufficient_data)
|
88
|
+
return {}
|
89
|
+
end
|
84
90
|
|
85
91
|
frame_map = {}
|
86
92
|
|
@@ -103,7 +109,7 @@ module Sentry
|
|
103
109
|
}
|
104
110
|
|
105
111
|
frame_hash[:module] = mod if mod
|
106
|
-
frame_hash[:lineno] = frame_data[:line] if frame_data[:line]
|
112
|
+
frame_hash[:lineno] = frame_data[:line] if frame_data[:line] && frame_data[:line] >= 0
|
107
113
|
|
108
114
|
frame_hash
|
109
115
|
end
|
@@ -157,8 +163,9 @@ module Sentry
|
|
157
163
|
|
158
164
|
log('Some samples thrown away') if samples.size != results[:samples]
|
159
165
|
|
160
|
-
if samples.size <=
|
166
|
+
if samples.size <= MIN_SAMPLES_REQUIRED
|
161
167
|
log('Not enough samples, discarding profiler')
|
168
|
+
record_lost_event(:insufficient_data)
|
162
169
|
return {}
|
163
170
|
end
|
164
171
|
|
@@ -218,5 +225,9 @@ module Sentry
|
|
218
225
|
|
219
226
|
[function, mod]
|
220
227
|
end
|
228
|
+
|
229
|
+
def record_lost_event(reason)
|
230
|
+
Sentry.get_current_client&.transport&.record_lost_event(reason, 'profile')
|
231
|
+
end
|
221
232
|
end
|
222
233
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
require "sentry/baggage"
|
5
|
+
|
6
|
+
module Sentry
|
7
|
+
class PropagationContext
|
8
|
+
SENTRY_TRACE_REGEXP = Regexp.new(
|
9
|
+
"^[ \t]*" + # whitespace
|
10
|
+
"([0-9a-f]{32})?" + # trace_id
|
11
|
+
"-?([0-9a-f]{16})?" + # span_id
|
12
|
+
"-?([01])?" + # sampled
|
13
|
+
"[ \t]*$" # whitespace
|
14
|
+
)
|
15
|
+
|
16
|
+
# An uuid that can be used to identify a trace.
|
17
|
+
# @return [String]
|
18
|
+
attr_reader :trace_id
|
19
|
+
# An uuid that can be used to identify the span.
|
20
|
+
# @return [String]
|
21
|
+
attr_reader :span_id
|
22
|
+
# Span parent's span_id.
|
23
|
+
# @return [String, nil]
|
24
|
+
attr_reader :parent_span_id
|
25
|
+
# The sampling decision of the parent transaction.
|
26
|
+
# @return [Boolean, nil]
|
27
|
+
attr_reader :parent_sampled
|
28
|
+
# Is there an incoming trace or not?
|
29
|
+
# @return [Boolean]
|
30
|
+
attr_reader :incoming_trace
|
31
|
+
# This is only for accessing the current baggage variable.
|
32
|
+
# Please use the #get_baggage method for interfacing outside this class.
|
33
|
+
# @return [Baggage, nil]
|
34
|
+
attr_reader :baggage
|
35
|
+
|
36
|
+
def initialize(scope, env = nil)
|
37
|
+
@scope = scope
|
38
|
+
@parent_span_id = nil
|
39
|
+
@parent_sampled = nil
|
40
|
+
@baggage = nil
|
41
|
+
@incoming_trace = false
|
42
|
+
|
43
|
+
if env
|
44
|
+
sentry_trace_header = env["HTTP_SENTRY_TRACE"] || env[SENTRY_TRACE_HEADER_NAME]
|
45
|
+
baggage_header = env["HTTP_BAGGAGE"] || env[BAGGAGE_HEADER_NAME]
|
46
|
+
|
47
|
+
if sentry_trace_header
|
48
|
+
sentry_trace_data = self.class.extract_sentry_trace(sentry_trace_header)
|
49
|
+
|
50
|
+
if sentry_trace_data
|
51
|
+
@trace_id, @parent_span_id, @parent_sampled = sentry_trace_data
|
52
|
+
|
53
|
+
@baggage =
|
54
|
+
if baggage_header && !baggage_header.empty?
|
55
|
+
Baggage.from_incoming_header(baggage_header)
|
56
|
+
else
|
57
|
+
# If there's an incoming sentry-trace but no incoming baggage header,
|
58
|
+
# for instance in traces coming from older SDKs,
|
59
|
+
# baggage will be empty and frozen and won't be populated as head SDK.
|
60
|
+
Baggage.new({})
|
61
|
+
end
|
62
|
+
|
63
|
+
@baggage.freeze!
|
64
|
+
@incoming_trace = true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
@trace_id ||= SecureRandom.uuid.delete("-")
|
70
|
+
@span_id = SecureRandom.uuid.delete("-").slice(0, 16)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Extract the trace_id, parent_span_id and parent_sampled values from a sentry-trace header.
|
74
|
+
#
|
75
|
+
# @param sentry_trace [String] the sentry-trace header value from the previous transaction.
|
76
|
+
# @return [Array, nil]
|
77
|
+
def self.extract_sentry_trace(sentry_trace)
|
78
|
+
match = SENTRY_TRACE_REGEXP.match(sentry_trace)
|
79
|
+
return nil if match.nil?
|
80
|
+
|
81
|
+
trace_id, parent_span_id, sampled_flag = match[1..3]
|
82
|
+
parent_sampled = sampled_flag.nil? ? nil : sampled_flag != "0"
|
83
|
+
|
84
|
+
[trace_id, parent_span_id, parent_sampled]
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns the trace context that can be used to embed in an Event.
|
88
|
+
# @return [Hash]
|
89
|
+
def get_trace_context
|
90
|
+
{
|
91
|
+
trace_id: trace_id,
|
92
|
+
span_id: span_id,
|
93
|
+
parent_span_id: parent_span_id
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns the sentry-trace header from the propagation context.
|
98
|
+
# @return [String]
|
99
|
+
def get_traceparent
|
100
|
+
"#{trace_id}-#{span_id}"
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns the Baggage from the propagation context or populates as head SDK if empty.
|
104
|
+
# @return [Baggage, nil]
|
105
|
+
def get_baggage
|
106
|
+
populate_head_baggage if @baggage.nil? || @baggage.mutable
|
107
|
+
@baggage
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns the Dynamic Sampling Context from the baggage.
|
111
|
+
# @return [String, nil]
|
112
|
+
def get_dynamic_sampling_context
|
113
|
+
get_baggage&.dynamic_sampling_context
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def populate_head_baggage
|
119
|
+
return unless Sentry.initialized?
|
120
|
+
|
121
|
+
configuration = Sentry.configuration
|
122
|
+
|
123
|
+
items = {
|
124
|
+
"trace_id" => trace_id,
|
125
|
+
"environment" => configuration.environment,
|
126
|
+
"release" => configuration.release,
|
127
|
+
"public_key" => configuration.dsn&.public_key,
|
128
|
+
"user_segment" => @scope.user && @scope.user["segment"]
|
129
|
+
}
|
130
|
+
|
131
|
+
items.compact!
|
132
|
+
@baggage = Baggage.new(items, mutable: false)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/sentry/puma.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
return unless defined?(Puma::Server)
|
4
|
+
|
3
5
|
module Sentry
|
4
6
|
module Puma
|
5
7
|
module Server
|
6
|
-
|
7
|
-
|
8
|
+
PUMA_4_AND_PRIOR = Gem::Version.new(::Puma::Const::PUMA_VERSION) < Gem::Version.new("5.0.0")
|
9
|
+
|
10
|
+
def lowlevel_error(e, env, status = 500)
|
11
|
+
result =
|
12
|
+
if PUMA_4_AND_PRIOR
|
13
|
+
super(e, env)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
8
17
|
|
9
18
|
begin
|
10
19
|
Sentry.capture_exception(e) do |scope|
|
@@ -20,6 +29,4 @@ module Sentry
|
|
20
29
|
end
|
21
30
|
end
|
22
31
|
|
23
|
-
|
24
|
-
Sentry.register_patch(Sentry::Puma::Server, Puma::Server)
|
25
|
-
end
|
32
|
+
Sentry.register_patch(:puma, Sentry::Puma::Server, Puma::Server)
|
@@ -4,6 +4,7 @@ module Sentry
|
|
4
4
|
module Rack
|
5
5
|
class CaptureExceptions
|
6
6
|
ERROR_EVENT_ID_KEY = "sentry.error_event_id"
|
7
|
+
MECHANISM_TYPE = "rack"
|
7
8
|
|
8
9
|
def initialize(app)
|
9
10
|
@app = app
|
@@ -56,17 +57,14 @@ module Sentry
|
|
56
57
|
end
|
57
58
|
|
58
59
|
def capture_exception(exception, env)
|
59
|
-
Sentry.capture_exception(exception).tap do |event|
|
60
|
+
Sentry.capture_exception(exception, hint: { mechanism: mechanism }).tap do |event|
|
60
61
|
env[ERROR_EVENT_ID_KEY] = event.event_id if event
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
65
|
def start_transaction(env, scope)
|
65
|
-
sentry_trace = env["HTTP_SENTRY_TRACE"]
|
66
|
-
baggage = env["HTTP_BAGGAGE"]
|
67
|
-
|
68
66
|
options = { name: scope.transaction_name, source: scope.transaction_source, op: transaction_op }
|
69
|
-
transaction = Sentry
|
67
|
+
transaction = Sentry.continue_trace(env, **options)
|
70
68
|
Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
|
71
69
|
end
|
72
70
|
|
@@ -77,6 +75,10 @@ module Sentry
|
|
77
75
|
transaction.set_http_status(status_code)
|
78
76
|
transaction.finish
|
79
77
|
end
|
78
|
+
|
79
|
+
def mechanism
|
80
|
+
Sentry::Mechanism.new(type: MECHANISM_TYPE, handled: false)
|
81
|
+
end
|
80
82
|
end
|
81
83
|
end
|
82
84
|
end
|
data/lib/sentry/rake.rb
CHANGED
@@ -8,7 +8,9 @@ module Sentry
|
|
8
8
|
module Application
|
9
9
|
# @api private
|
10
10
|
def display_error_message(ex)
|
11
|
-
Sentry.
|
11
|
+
mechanism = Sentry::Mechanism.new(type: 'rake', handled: false)
|
12
|
+
|
13
|
+
Sentry.capture_exception(ex, hint: { mechanism: mechanism }) do |scope|
|
12
14
|
task_name = top_level_tasks.join(' ')
|
13
15
|
scope.set_transaction_name(task_name, source: :task)
|
14
16
|
scope.set_tag("rake_task", task_name)
|
@@ -17,15 +19,6 @@ module Sentry
|
|
17
19
|
super
|
18
20
|
end
|
19
21
|
end
|
20
|
-
|
21
|
-
module Task
|
22
|
-
# @api private
|
23
|
-
def execute(args=nil)
|
24
|
-
return super unless Sentry.initialized? && Sentry.get_current_hub
|
25
|
-
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
29
22
|
end
|
30
23
|
end
|
31
24
|
|
@@ -34,8 +27,4 @@ module Rake
|
|
34
27
|
class Application
|
35
28
|
prepend(Sentry::Rake::Application)
|
36
29
|
end
|
37
|
-
|
38
|
-
class Task
|
39
|
-
prepend(Sentry::Rake::Task)
|
40
|
-
end
|
41
30
|
end
|
data/lib/sentry/redis.rb
CHANGED
@@ -19,7 +19,10 @@ module Sentry
|
|
19
19
|
|
20
20
|
if span
|
21
21
|
span.set_description(commands_description)
|
22
|
-
span.set_data(
|
22
|
+
span.set_data(Span::DataConventions::DB_SYSTEM, "redis")
|
23
|
+
span.set_data(Span::DataConventions::DB_NAME, db)
|
24
|
+
span.set_data(Span::DataConventions::SERVER_ADDRESS, host)
|
25
|
+
span.set_data(Span::DataConventions::SERVER_PORT, port)
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
@@ -96,8 +99,10 @@ end
|
|
96
99
|
|
97
100
|
if defined?(::Redis::Client)
|
98
101
|
if Gem::Version.new(::Redis::VERSION) < Gem::Version.new("5.0")
|
99
|
-
Sentry.register_patch(Sentry::Redis::OldClientPatch, ::Redis::Client)
|
102
|
+
Sentry.register_patch(:redis, Sentry::Redis::OldClientPatch, ::Redis::Client)
|
100
103
|
elsif defined?(RedisClient)
|
101
|
-
|
104
|
+
Sentry.register_patch(:redis) do
|
105
|
+
RedisClient.register(Sentry::Redis::GlobalRedisInstrumentation)
|
106
|
+
end
|
102
107
|
end
|
103
108
|
end
|
data/lib/sentry/scope.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sentry/breadcrumb_buffer"
|
4
|
+
require "sentry/propagation_context"
|
4
5
|
require "etc"
|
5
6
|
|
6
7
|
module Sentry
|
@@ -20,7 +21,8 @@ module Sentry
|
|
20
21
|
:event_processors,
|
21
22
|
:rack_env,
|
22
23
|
:span,
|
23
|
-
:session
|
24
|
+
:session,
|
25
|
+
:propagation_context
|
24
26
|
]
|
25
27
|
|
26
28
|
attr_reader(*ATTRIBUTES)
|
@@ -42,22 +44,26 @@ module Sentry
|
|
42
44
|
# @param hint [Hash] the hint data that'll be passed to event processors.
|
43
45
|
# @return [Event]
|
44
46
|
def apply_to_event(event, hint = nil)
|
45
|
-
event.
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
unless event.is_a?(CheckInEvent)
|
48
|
+
event.tags = tags.merge(event.tags)
|
49
|
+
event.user = user.merge(event.user)
|
50
|
+
event.extra = extra.merge(event.extra)
|
51
|
+
event.contexts = contexts.merge(event.contexts)
|
52
|
+
event.transaction = transaction_name if transaction_name
|
53
|
+
event.transaction_info = { source: transaction_source } if transaction_source
|
54
|
+
event.fingerprint = fingerprint
|
55
|
+
event.level = level
|
56
|
+
event.breadcrumbs = breadcrumbs
|
57
|
+
event.rack_env = rack_env if rack_env
|
58
|
+
end
|
51
59
|
|
52
60
|
if span
|
53
|
-
event.contexts[:trace]
|
61
|
+
event.contexts[:trace] ||= span.get_trace_context
|
62
|
+
else
|
63
|
+
event.contexts[:trace] ||= propagation_context.get_trace_context
|
64
|
+
event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
|
54
65
|
end
|
55
66
|
|
56
|
-
event.fingerprint = fingerprint
|
57
|
-
event.level = level
|
58
|
-
event.breadcrumbs = breadcrumbs
|
59
|
-
event.rack_env = rack_env if rack_env
|
60
|
-
|
61
67
|
all_event_processors = self.class.global_event_processors + @event_processors
|
62
68
|
|
63
69
|
unless all_event_processors.empty?
|
@@ -95,6 +101,7 @@ module Sentry
|
|
95
101
|
copy.fingerprint = fingerprint.deep_dup
|
96
102
|
copy.span = span.deep_dup
|
97
103
|
copy.session = session.deep_dup
|
104
|
+
copy.propagation_context = propagation_context.deep_dup
|
98
105
|
copy
|
99
106
|
end
|
100
107
|
|
@@ -111,6 +118,7 @@ module Sentry
|
|
111
118
|
self.transaction_sources = scope.transaction_sources
|
112
119
|
self.fingerprint = scope.fingerprint
|
113
120
|
self.span = scope.span
|
121
|
+
self.propagation_context = scope.propagation_context
|
114
122
|
end
|
115
123
|
|
116
124
|
# Updates the scope's data from the given options.
|
@@ -244,6 +252,12 @@ module Sentry
|
|
244
252
|
@transaction_sources.last
|
245
253
|
end
|
246
254
|
|
255
|
+
# These are high cardinality and thus bad.
|
256
|
+
# @return [Boolean]
|
257
|
+
def transaction_source_low_quality?
|
258
|
+
transaction_source == :url
|
259
|
+
end
|
260
|
+
|
247
261
|
# Returns the associated Transaction object.
|
248
262
|
# @return [Transaction, nil]
|
249
263
|
def get_transaction
|
@@ -272,6 +286,13 @@ module Sentry
|
|
272
286
|
@event_processors << block
|
273
287
|
end
|
274
288
|
|
289
|
+
# Generate a new propagation context either from the incoming env headers or from scratch.
|
290
|
+
# @param env [Hash, nil]
|
291
|
+
# @return [void]
|
292
|
+
def generate_propagation_context(env = nil)
|
293
|
+
@propagation_context = PropagationContext.new(self, env)
|
294
|
+
end
|
295
|
+
|
275
296
|
protected
|
276
297
|
|
277
298
|
# for duplicating scopes internally
|
@@ -280,7 +301,7 @@ module Sentry
|
|
280
301
|
private
|
281
302
|
|
282
303
|
def set_default_value
|
283
|
-
@contexts = { :
|
304
|
+
@contexts = { os: self.class.os_context, runtime: self.class.runtime_context }
|
284
305
|
@extra = {}
|
285
306
|
@tags = {}
|
286
307
|
@user = {}
|
@@ -292,6 +313,7 @@ module Sentry
|
|
292
313
|
@rack_env = {}
|
293
314
|
@span = nil
|
294
315
|
@session = nil
|
316
|
+
generate_propagation_context
|
295
317
|
set_new_breadcrumb_buffer
|
296
318
|
end
|
297
319
|
|
@@ -339,6 +361,5 @@ module Sentry
|
|
339
361
|
global_event_processors << block
|
340
362
|
end
|
341
363
|
end
|
342
|
-
|
343
364
|
end
|
344
365
|
end
|
data/lib/sentry/session.rb
CHANGED
@@ -5,8 +5,8 @@ module Sentry
|
|
5
5
|
attr_reader :started, :status, :aggregation_key
|
6
6
|
|
7
7
|
# TODO-neel add :crashed after adding handled mechanism
|
8
|
-
STATUSES = %i
|
9
|
-
AGGREGATE_STATUSES = %i
|
8
|
+
STATUSES = %i[ok errored exited]
|
9
|
+
AGGREGATE_STATUSES = %i[errored exited]
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
@started = Sentry.utc_now
|
@@ -20,12 +20,8 @@ module Sentry
|
|
20
20
|
|
21
21
|
def flush
|
22
22
|
return if @pending_aggregates.empty?
|
23
|
-
envelope = pending_envelope
|
24
|
-
|
25
|
-
Sentry.background_worker.perform do
|
26
|
-
@client.transport.send_envelope(envelope)
|
27
|
-
end
|
28
23
|
|
24
|
+
@client.capture_envelope(pending_envelope)
|
29
25
|
@pending_aggregates = {}
|
30
26
|
end
|
31
27
|
|
@@ -85,6 +81,5 @@ module Sentry
|
|
85
81
|
end
|
86
82
|
end
|
87
83
|
end
|
88
|
-
|
89
84
|
end
|
90
85
|
end
|