sentry-ruby-core 4.2.0 → 4.3.2
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/CHANGELOG.md +63 -0
- data/Gemfile +1 -0
- data/README.md +39 -55
- data/lib/sentry-ruby.rb +7 -9
- data/lib/sentry/background_worker.rb +1 -0
- data/lib/sentry/breadcrumb/sentry_logger.rb +2 -1
- data/lib/sentry/breadcrumb_buffer.rb +3 -2
- data/lib/sentry/client.rb +47 -27
- data/lib/sentry/configuration.rb +16 -0
- data/lib/sentry/event.rb +28 -47
- data/lib/sentry/exceptions.rb +7 -0
- data/lib/sentry/hub.rb +12 -2
- data/lib/sentry/interfaces/exception.rb +19 -1
- data/lib/sentry/interfaces/request.rb +10 -10
- data/lib/sentry/interfaces/single_exception.rb +16 -4
- data/lib/sentry/interfaces/stacktrace.rb +9 -26
- data/lib/sentry/interfaces/stacktrace_builder.rb +50 -0
- data/lib/sentry/interfaces/threads.rb +9 -3
- data/lib/sentry/rack/capture_exceptions.rb +18 -14
- data/lib/sentry/scope.rb +11 -6
- data/lib/sentry/span.rb +10 -2
- data/lib/sentry/transaction.rb +34 -36
- data/lib/sentry/transaction_event.rb +3 -1
- data/lib/sentry/transport.rb +10 -29
- data/lib/sentry/transport/configuration.rb +3 -1
- data/lib/sentry/transport/http_transport.rb +18 -2
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- metadata +5 -3
@@ -16,30 +16,24 @@ module Sentry
|
|
16
16
|
scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
|
17
17
|
scope.set_rack_env(env)
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
Sentry::Transaction.from_sentry_trace(sentry_trace, name: scope.transaction_name, op: transaction_op)
|
22
|
-
else
|
23
|
-
Sentry.start_transaction(name: scope.transaction_name, op: transaction_op)
|
24
|
-
end
|
25
|
-
|
26
|
-
scope.set_span(span)
|
19
|
+
transaction = start_transaction(env, scope)
|
20
|
+
scope.set_span(transaction) if transaction
|
27
21
|
|
28
22
|
begin
|
29
23
|
response = @app.call(env)
|
30
24
|
rescue Sentry::Error
|
31
|
-
|
25
|
+
finish_transaction(transaction, 500)
|
32
26
|
raise # Don't capture Sentry errors
|
33
27
|
rescue Exception => e
|
34
28
|
capture_exception(e)
|
35
|
-
|
29
|
+
finish_transaction(transaction, 500)
|
36
30
|
raise
|
37
31
|
end
|
38
32
|
|
39
33
|
exception = collect_exception(env)
|
40
34
|
capture_exception(exception) if exception
|
41
35
|
|
42
|
-
|
36
|
+
finish_transaction(transaction, response[0])
|
43
37
|
|
44
38
|
response
|
45
39
|
end
|
@@ -59,9 +53,19 @@ module Sentry
|
|
59
53
|
Sentry.capture_exception(exception)
|
60
54
|
end
|
61
55
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
56
|
+
def start_transaction(env, scope)
|
57
|
+
sentry_trace = env["HTTP_SENTRY_TRACE"]
|
58
|
+
options = { name: scope.transaction_name, op: transaction_op }
|
59
|
+
transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, **options) if sentry_trace
|
60
|
+
Sentry.start_transaction(transaction: transaction, **options)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def finish_transaction(transaction, status_code)
|
65
|
+
return unless transaction
|
66
|
+
|
67
|
+
transaction.set_http_status(status_code)
|
68
|
+
transaction.finish
|
65
69
|
end
|
66
70
|
end
|
67
71
|
end
|
data/lib/sentry/scope.rb
CHANGED
@@ -9,7 +9,8 @@ module Sentry
|
|
9
9
|
|
10
10
|
attr_reader(*ATTRIBUTES)
|
11
11
|
|
12
|
-
def initialize
|
12
|
+
def initialize(max_breadcrumbs: nil)
|
13
|
+
@max_breadcrumbs = max_breadcrumbs
|
13
14
|
set_default_value
|
14
15
|
end
|
15
16
|
|
@@ -47,7 +48,7 @@ module Sentry
|
|
47
48
|
end
|
48
49
|
|
49
50
|
def clear_breadcrumbs
|
50
|
-
|
51
|
+
set_new_breadcrumb_buffer
|
51
52
|
end
|
52
53
|
|
53
54
|
def dup
|
@@ -125,7 +126,7 @@ module Sentry
|
|
125
126
|
|
126
127
|
def set_contexts(contexts_hash)
|
127
128
|
check_argument_type!(contexts_hash, Hash)
|
128
|
-
@contexts
|
129
|
+
@contexts.merge!(contexts_hash)
|
129
130
|
end
|
130
131
|
|
131
132
|
def set_context(key, value)
|
@@ -145,8 +146,7 @@ module Sentry
|
|
145
146
|
end
|
146
147
|
|
147
148
|
def get_transaction
|
148
|
-
|
149
|
-
span.span_recorder.spans.first if span
|
149
|
+
span.transaction if span
|
150
150
|
end
|
151
151
|
|
152
152
|
def get_span
|
@@ -171,7 +171,6 @@ module Sentry
|
|
171
171
|
private
|
172
172
|
|
173
173
|
def set_default_value
|
174
|
-
@breadcrumbs = BreadcrumbBuffer.new
|
175
174
|
@contexts = { :os => self.class.os_context, :runtime => self.class.runtime_context }
|
176
175
|
@extra = {}
|
177
176
|
@tags = {}
|
@@ -182,8 +181,14 @@ module Sentry
|
|
182
181
|
@event_processors = []
|
183
182
|
@rack_env = {}
|
184
183
|
@span = nil
|
184
|
+
set_new_breadcrumb_buffer
|
185
185
|
end
|
186
186
|
|
187
|
+
def set_new_breadcrumb_buffer
|
188
|
+
@breadcrumbs = BreadcrumbBuffer.new(@max_breadcrumbs)
|
189
|
+
end
|
190
|
+
|
191
|
+
|
187
192
|
class << self
|
188
193
|
def os_context
|
189
194
|
@os_context ||=
|
data/lib/sentry/span.rb
CHANGED
@@ -19,7 +19,7 @@ module Sentry
|
|
19
19
|
|
20
20
|
|
21
21
|
attr_reader :trace_id, :span_id, :parent_span_id, :sampled, :start_timestamp, :timestamp, :description, :op, :status, :tags, :data
|
22
|
-
attr_accessor :span_recorder
|
22
|
+
attr_accessor :span_recorder, :transaction
|
23
23
|
|
24
24
|
def initialize(description: nil, op: nil, status: nil, trace_id: nil, parent_span_id: nil, sampled: nil, start_timestamp: nil, timestamp: nil)
|
25
25
|
@trace_id = trace_id || SecureRandom.uuid.delete("-")
|
@@ -78,7 +78,15 @@ module Sentry
|
|
78
78
|
|
79
79
|
def start_child(**options)
|
80
80
|
options = options.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
|
81
|
-
Span.new(**options)
|
81
|
+
new_span = Span.new(**options)
|
82
|
+
new_span.transaction = transaction
|
83
|
+
new_span.span_recorder = span_recorder
|
84
|
+
|
85
|
+
if span_recorder
|
86
|
+
span_recorder.add(new_span)
|
87
|
+
end
|
88
|
+
|
89
|
+
new_span
|
82
90
|
end
|
83
91
|
|
84
92
|
def with_child_span(**options, &block)
|
data/lib/sentry/transaction.rb
CHANGED
@@ -17,23 +17,26 @@ module Sentry
|
|
17
17
|
|
18
18
|
@name = name
|
19
19
|
@parent_sampled = parent_sampled
|
20
|
-
|
20
|
+
@transaction = self
|
21
|
+
init_span_recorder
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
-
|
25
|
-
@span_recorder.add(self)
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.from_sentry_trace(sentry_trace, **options)
|
24
|
+
def self.from_sentry_trace(sentry_trace, configuration: Sentry.configuration, **options)
|
25
|
+
return unless configuration.tracing_enabled?
|
29
26
|
return unless sentry_trace
|
30
27
|
|
31
28
|
match = SENTRY_TRACE_REGEXP.match(sentry_trace)
|
29
|
+
return if match.nil?
|
32
30
|
trace_id, parent_span_id, sampled_flag = match[1..3]
|
33
31
|
|
34
|
-
|
32
|
+
parent_sampled =
|
33
|
+
if sampled_flag.nil?
|
34
|
+
nil
|
35
|
+
else
|
36
|
+
sampled_flag != "0"
|
37
|
+
end
|
35
38
|
|
36
|
-
new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled:
|
39
|
+
new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: parent_sampled, **options)
|
37
40
|
end
|
38
41
|
|
39
42
|
def to_hash
|
@@ -42,20 +45,9 @@ module Sentry
|
|
42
45
|
hash
|
43
46
|
end
|
44
47
|
|
45
|
-
def start_child(**options)
|
46
|
-
child_span = super
|
47
|
-
child_span.span_recorder = @span_recorder
|
48
|
-
|
49
|
-
if @sampled
|
50
|
-
@span_recorder.add(child_span)
|
51
|
-
end
|
52
|
-
|
53
|
-
child_span
|
54
|
-
end
|
55
|
-
|
56
48
|
def deep_dup
|
57
49
|
copy = super
|
58
|
-
copy.
|
50
|
+
copy.init_span_recorder(@span_recorder.max_length)
|
59
51
|
|
60
52
|
@span_recorder.spans.each do |span|
|
61
53
|
# span_recorder's first span is the current span, which should not be added to the copy's spans
|
@@ -66,30 +58,29 @@ module Sentry
|
|
66
58
|
copy
|
67
59
|
end
|
68
60
|
|
69
|
-
def
|
70
|
-
unless
|
61
|
+
def set_initial_sample_decision(sampling_context:, configuration: Sentry.configuration)
|
62
|
+
unless configuration.tracing_enabled?
|
71
63
|
@sampled = false
|
72
64
|
return
|
73
65
|
end
|
74
66
|
|
75
67
|
return unless @sampled.nil?
|
76
68
|
|
77
|
-
|
78
|
-
|
79
|
-
logger = Sentry.configuration.logger
|
80
|
-
sample_rate = Sentry.configuration.traces_sample_rate
|
81
|
-
traces_sampler = Sentry.configuration.traces_sampler
|
69
|
+
traces_sampler = configuration.traces_sampler
|
82
70
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
71
|
+
sample_rate =
|
72
|
+
if traces_sampler.is_a?(Proc)
|
73
|
+
traces_sampler.call(sampling_context)
|
74
|
+
elsif !sampling_context[:parent_sampled].nil?
|
75
|
+
sampling_context[:parent_sampled]
|
76
|
+
else
|
77
|
+
configuration.traces_sample_rate
|
78
|
+
end
|
88
79
|
|
89
|
-
|
90
|
-
|
80
|
+
transaction_description = generate_transaction_description
|
81
|
+
logger = configuration.logger
|
91
82
|
|
92
|
-
unless [true, false].include?(sample_rate) || (sample_rate.is_a?(
|
83
|
+
unless [true, false].include?(sample_rate) || (sample_rate.is_a?(Numeric) && sample_rate >= 0.0 && sample_rate <= 1.0)
|
93
84
|
@sampled = false
|
94
85
|
logger.warn("#{MESSAGE_PREFIX} Discarding #{transaction_description} because of invalid sample_rate: #{sample_rate}")
|
95
86
|
return
|
@@ -130,6 +121,13 @@ module Sentry
|
|
130
121
|
hub.capture_event(event)
|
131
122
|
end
|
132
123
|
|
124
|
+
protected
|
125
|
+
|
126
|
+
def init_span_recorder(limit = 1000)
|
127
|
+
@span_recorder = SpanRecorder.new(limit)
|
128
|
+
@span_recorder.add(self)
|
129
|
+
end
|
130
|
+
|
133
131
|
private
|
134
132
|
|
135
133
|
def generate_transaction_description
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module Sentry
|
4
4
|
class TransactionEvent < Event
|
5
|
+
TYPE = "transaction"
|
6
|
+
|
5
7
|
ATTRIBUTES = %i(
|
6
8
|
event_id level timestamp start_timestamp
|
7
9
|
release environment server_name modules
|
@@ -17,7 +19,7 @@ module Sentry
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def type
|
20
|
-
|
22
|
+
TYPE
|
21
23
|
end
|
22
24
|
|
23
25
|
def to_hash
|
data/lib/sentry/transport.rb
CHANGED
@@ -24,16 +24,13 @@ module Sentry
|
|
24
24
|
return
|
25
25
|
end
|
26
26
|
|
27
|
-
encoded_data =
|
27
|
+
encoded_data = encode(event)
|
28
28
|
|
29
29
|
return nil unless encoded_data
|
30
30
|
|
31
31
|
send_data(encoded_data)
|
32
32
|
|
33
33
|
event
|
34
|
-
rescue => e
|
35
|
-
failed_for_exception(e, event)
|
36
|
-
nil
|
37
34
|
end
|
38
35
|
|
39
36
|
def generate_auth_header
|
@@ -48,38 +45,22 @@ module Sentry
|
|
48
45
|
'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
|
49
46
|
end
|
50
47
|
|
51
|
-
def encode(
|
52
|
-
|
53
|
-
|
48
|
+
def encode(event)
|
49
|
+
# Convert to hash
|
50
|
+
event_hash = event.to_hash
|
51
|
+
|
52
|
+
event_id = event_hash[:event_id] || event_hash["event_id"]
|
53
|
+
item_type = event_hash[:type] || event_hash["type"] || "event"
|
54
54
|
|
55
55
|
envelope = <<~ENVELOPE
|
56
56
|
{"event_id":"#{event_id}","dsn":"#{configuration.dsn.to_s}","sdk":#{Sentry.sdk_meta.to_json},"sent_at":"#{Sentry.utc_now.iso8601}"}
|
57
|
-
{"type":"#{
|
57
|
+
{"type":"#{item_type}","content_type":"application/json"}
|
58
58
|
#{JSON.generate(event_hash)}
|
59
59
|
ENVELOPE
|
60
60
|
|
61
|
-
envelope
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def prepare_encoded_event(event)
|
67
|
-
# Convert to hash
|
68
|
-
event_hash = event.to_hash
|
69
|
-
|
70
|
-
event_id = event_hash[:event_id] || event_hash["event_id"]
|
71
|
-
event_type = event_hash[:type] || event_hash["type"]
|
72
|
-
configuration.logger.info(LOGGER_PROGNAME) { "Sending #{event_type} #{event_id} to Sentry" }
|
73
|
-
encode(event_hash)
|
74
|
-
end
|
75
|
-
|
76
|
-
def failed_for_exception(e, event)
|
77
|
-
configuration.logger.warn(LOGGER_PROGNAME) { "Unable to record event with remote Sentry server (#{e.class} - #{e.message}):\n#{e.backtrace[0..10].join("\n")}" }
|
78
|
-
log_not_sending(event)
|
79
|
-
end
|
61
|
+
configuration.logger.info(LOGGER_PROGNAME) { "Sending envelope [#{item_type}] #{event_id} to Sentry" }
|
80
62
|
|
81
|
-
|
82
|
-
configuration.logger.warn(LOGGER_PROGNAME) { "Failed to submit event. Unreported Event: #{Event.get_log_message(event.to_hash)}" }
|
63
|
+
envelope
|
83
64
|
end
|
84
65
|
end
|
85
66
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
module Sentry
|
2
2
|
class Transport
|
3
3
|
class Configuration
|
4
|
-
attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :http_adapter, :faraday_builder,
|
4
|
+
attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :http_adapter, :faraday_builder,
|
5
|
+
:transport_class, :encoding
|
5
6
|
|
6
7
|
def initialize
|
7
8
|
@ssl_verification = true
|
8
9
|
@open_timeout = 1
|
9
10
|
@timeout = 2
|
11
|
+
@encoding = HTTPTransport::GZIP_ENCODING
|
10
12
|
end
|
11
13
|
|
12
14
|
def transport_class=(klass)
|
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'faraday'
|
2
|
+
require 'zlib'
|
2
3
|
|
3
4
|
module Sentry
|
4
5
|
class HTTPTransport < Transport
|
5
|
-
|
6
|
+
GZIP_ENCODING = "gzip"
|
7
|
+
GZIP_THRESHOLD = 1024 * 30
|
8
|
+
CONTENT_TYPE = 'application/x-sentry-envelope'
|
9
|
+
|
6
10
|
attr_reader :conn, :adapter
|
7
11
|
|
8
12
|
def initialize(*args)
|
@@ -13,8 +17,16 @@ module Sentry
|
|
13
17
|
end
|
14
18
|
|
15
19
|
def send_data(data)
|
20
|
+
encoding = ""
|
21
|
+
|
22
|
+
if should_compress?(data)
|
23
|
+
data = Zlib.gzip(data)
|
24
|
+
encoding = GZIP_ENCODING
|
25
|
+
end
|
26
|
+
|
16
27
|
conn.post @endpoint do |req|
|
17
28
|
req.headers['Content-Type'] = CONTENT_TYPE
|
29
|
+
req.headers['Content-Encoding'] = encoding
|
18
30
|
req.headers['X-Sentry-Auth'] = generate_auth_header
|
19
31
|
req.body = data
|
20
32
|
end
|
@@ -26,11 +38,15 @@ module Sentry
|
|
26
38
|
error_info += " Error in headers is: #{e.response[:headers]['x-sentry-error']}" if e.response[:headers]['x-sentry-error']
|
27
39
|
end
|
28
40
|
|
29
|
-
raise Sentry::
|
41
|
+
raise Sentry::ExternalError, error_info
|
30
42
|
end
|
31
43
|
|
32
44
|
private
|
33
45
|
|
46
|
+
def should_compress?(data)
|
47
|
+
@transport_configuration.encoding == GZIP_ENCODING && data.bytesize >= GZIP_THRESHOLD
|
48
|
+
end
|
49
|
+
|
34
50
|
def set_conn
|
35
51
|
server = @dsn.server
|
36
52
|
|
data/lib/sentry/utils/real_ip.rb
CHANGED
@@ -29,7 +29,7 @@ module Sentry
|
|
29
29
|
@client_ip = client_ip
|
30
30
|
@real_ip = real_ip
|
31
31
|
@forwarded_for = forwarded_for
|
32
|
-
@trusted_proxies = (LOCAL_ADDRESSES + Array(trusted_proxies)).map { |proxy| IPAddr.new(proxy) }.uniq
|
32
|
+
@trusted_proxies = (LOCAL_ADDRESSES + Array(trusted_proxies)).map { |proxy| IPAddr.new(proxy.to_s) }.uniq
|
33
33
|
end
|
34
34
|
|
35
35
|
def calculate_ip
|
data/lib/sentry/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sentry-ruby-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.2
|
4
|
+
version: 4.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sentry Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -71,6 +71,7 @@ files:
|
|
71
71
|
- lib/sentry/core_ext/object/duplicable.rb
|
72
72
|
- lib/sentry/dsn.rb
|
73
73
|
- lib/sentry/event.rb
|
74
|
+
- lib/sentry/exceptions.rb
|
74
75
|
- lib/sentry/hub.rb
|
75
76
|
- lib/sentry/integrable.rb
|
76
77
|
- lib/sentry/interface.rb
|
@@ -78,6 +79,7 @@ files:
|
|
78
79
|
- lib/sentry/interfaces/request.rb
|
79
80
|
- lib/sentry/interfaces/single_exception.rb
|
80
81
|
- lib/sentry/interfaces/stacktrace.rb
|
82
|
+
- lib/sentry/interfaces/stacktrace_builder.rb
|
81
83
|
- lib/sentry/interfaces/threads.rb
|
82
84
|
- lib/sentry/linecache.rb
|
83
85
|
- lib/sentry/logger.rb
|
@@ -122,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
124
|
- !ruby/object:Gem::Version
|
123
125
|
version: '0'
|
124
126
|
requirements: []
|
125
|
-
rubygems_version: 3.0.3
|
127
|
+
rubygems_version: 3.0.3.1
|
126
128
|
signing_key:
|
127
129
|
specification_version: 4
|
128
130
|
summary: A gem that provides a client interface for the Sentry error logger
|