sentry-ruby-core 4.8.0 → 5.2.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/.yardopts +2 -0
- data/Gemfile +3 -0
- data/README.md +2 -0
- data/lib/sentry/background_worker.rb +33 -3
- data/lib/sentry/backtrace.rb +1 -3
- data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
- data/lib/sentry/breadcrumb.rb +24 -3
- data/lib/sentry/breadcrumb_buffer.rb +16 -0
- data/lib/sentry/client.rb +38 -2
- data/lib/sentry/configuration.rb +94 -41
- data/lib/sentry/core_ext/object/deep_dup.rb +2 -0
- data/lib/sentry/core_ext/object/duplicable.rb +1 -0
- data/lib/sentry/dsn.rb +2 -0
- data/lib/sentry/envelope.rb +45 -0
- data/lib/sentry/event.rb +55 -18
- data/lib/sentry/exceptions.rb +2 -0
- data/lib/sentry/hub.rb +38 -2
- data/lib/sentry/integrable.rb +2 -0
- data/lib/sentry/interface.rb +3 -10
- data/lib/sentry/interfaces/exception.rb +14 -3
- data/lib/sentry/interfaces/request.rb +37 -20
- data/lib/sentry/interfaces/single_exception.rb +2 -0
- data/lib/sentry/interfaces/stacktrace.rb +6 -0
- data/lib/sentry/interfaces/stacktrace_builder.rb +39 -10
- data/lib/sentry/interfaces/threads.rb +12 -2
- data/lib/sentry/linecache.rb +3 -0
- data/lib/sentry/net/http.rb +54 -65
- data/lib/sentry/rack/capture_exceptions.rb +28 -24
- data/lib/sentry/rack.rb +2 -0
- data/lib/sentry/rake.rb +16 -6
- data/lib/sentry/redis.rb +90 -0
- data/lib/sentry/release_detector.rb +3 -0
- data/lib/sentry/scope.rb +85 -6
- data/lib/sentry/session.rb +35 -0
- data/lib/sentry/session_flusher.rb +79 -0
- data/lib/sentry/span.rb +84 -8
- data/lib/sentry/transaction.rb +48 -14
- data/lib/sentry/transaction_event.rb +8 -0
- data/lib/sentry/transport/configuration.rb +3 -2
- data/lib/sentry/transport/dummy_transport.rb +8 -1
- data/lib/sentry/transport/http_transport.rb +55 -42
- data/lib/sentry/transport.rb +79 -37
- data/lib/sentry/utils/argument_checking_helper.rb +2 -0
- data/lib/sentry/utils/custom_inspection.rb +2 -0
- data/lib/sentry/utils/exception_cause_chain.rb +2 -0
- data/lib/sentry/utils/logging_helper.rb +6 -4
- data/lib/sentry/utils/real_ip.rb +2 -0
- data/lib/sentry/utils/request_id.rb +2 -0
- data/lib/sentry/version.rb +3 -1
- data/lib/sentry-ruby.rb +212 -41
- data/sentry-ruby-core.gemspec +0 -1
- data/sentry-ruby.gemspec +0 -1
- metadata +7 -16
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class SessionFlusher
|
5
|
+
include LoggingHelper
|
6
|
+
|
7
|
+
FLUSH_INTERVAL = 60
|
8
|
+
|
9
|
+
def initialize(configuration, client)
|
10
|
+
@thread = nil
|
11
|
+
@client = client
|
12
|
+
@pending_aggregates = {}
|
13
|
+
@release = configuration.release
|
14
|
+
@environment = configuration.environment
|
15
|
+
@logger = configuration.logger
|
16
|
+
|
17
|
+
log_debug("[Sessions] Sessions won't be captured without a valid release") unless @release
|
18
|
+
end
|
19
|
+
|
20
|
+
def flush
|
21
|
+
return if @pending_aggregates.empty?
|
22
|
+
envelope = pending_envelope
|
23
|
+
|
24
|
+
Sentry.background_worker.perform do
|
25
|
+
@client.transport.send_envelope(envelope)
|
26
|
+
end
|
27
|
+
|
28
|
+
@pending_aggregates = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_session(session)
|
32
|
+
return unless @release
|
33
|
+
|
34
|
+
ensure_thread
|
35
|
+
|
36
|
+
return unless Session::AGGREGATE_STATUSES.include?(session.status)
|
37
|
+
@pending_aggregates[session.aggregation_key] ||= init_aggregates(session.aggregation_key)
|
38
|
+
@pending_aggregates[session.aggregation_key][session.status] += 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def kill
|
42
|
+
@thread&.kill
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def init_aggregates(aggregation_key)
|
48
|
+
aggregates = { started: aggregation_key.iso8601 }
|
49
|
+
Session::AGGREGATE_STATUSES.each { |k| aggregates[k] = 0 }
|
50
|
+
aggregates
|
51
|
+
end
|
52
|
+
|
53
|
+
def pending_envelope
|
54
|
+
envelope = Envelope.new
|
55
|
+
|
56
|
+
header = { type: 'sessions' }
|
57
|
+
payload = { attrs: attrs, aggregates: @pending_aggregates.values }
|
58
|
+
|
59
|
+
envelope.add_item(header, payload)
|
60
|
+
envelope
|
61
|
+
end
|
62
|
+
|
63
|
+
def attrs
|
64
|
+
{ release: @release, environment: @environment }
|
65
|
+
end
|
66
|
+
|
67
|
+
def ensure_thread
|
68
|
+
return if @thread&.alive?
|
69
|
+
|
70
|
+
@thread = Thread.new do
|
71
|
+
loop do
|
72
|
+
sleep(FLUSH_INTERVAL)
|
73
|
+
flush
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/lib/sentry/span.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "securerandom"
|
3
4
|
|
4
5
|
module Sentry
|
@@ -17,9 +18,49 @@ module Sentry
|
|
17
18
|
504 => "deadline_exceeded"
|
18
19
|
}
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
# An uuid that can be used to identify a trace.
|
22
|
+
# @return [String]
|
23
|
+
attr_reader :trace_id
|
24
|
+
# An uuid that can be used to identify the span.
|
25
|
+
# @return [String]
|
26
|
+
attr_reader :span_id
|
27
|
+
# Span parent's span_id.
|
28
|
+
# @return [String]
|
29
|
+
attr_reader :parent_span_id
|
30
|
+
# Sampling result of the span.
|
31
|
+
# @return [Boolean, nil]
|
32
|
+
attr_reader :sampled
|
33
|
+
# Starting timestamp of the span.
|
34
|
+
# @return [Float]
|
35
|
+
attr_reader :start_timestamp
|
36
|
+
# Finishing timestamp of the span.
|
37
|
+
# @return [Float]
|
38
|
+
attr_reader :timestamp
|
39
|
+
# Span description
|
40
|
+
# @return [String]
|
41
|
+
attr_reader :description
|
42
|
+
# Span operation
|
43
|
+
# @return [String]
|
44
|
+
attr_reader :op
|
45
|
+
# Span status
|
46
|
+
# @return [String]
|
47
|
+
attr_reader :status
|
48
|
+
# Span tags
|
49
|
+
# @return [Hash]
|
50
|
+
attr_reader :tags
|
51
|
+
# Span data
|
52
|
+
# @return [Hash]
|
53
|
+
attr_reader :data
|
54
|
+
|
55
|
+
# The SpanRecorder the current span belongs to.
|
56
|
+
# SpanRecorder holds all spans under the same Transaction object (including the Transaction itself).
|
57
|
+
# @return [SpanRecorder]
|
58
|
+
attr_accessor :span_recorder
|
59
|
+
|
60
|
+
# The Transaction object the Span belongs to.
|
61
|
+
# Every span needs to be attached to a Transaction and their child spans will also inherit the same transaction.
|
62
|
+
# @return [Transaction]
|
63
|
+
attr_accessor :transaction
|
23
64
|
|
24
65
|
def initialize(
|
25
66
|
description: nil,
|
@@ -44,6 +85,8 @@ module Sentry
|
|
44
85
|
@tags = {}
|
45
86
|
end
|
46
87
|
|
88
|
+
# Finishes the span by adding a timestamp.
|
89
|
+
# @return [self]
|
47
90
|
def finish
|
48
91
|
# already finished
|
49
92
|
return if @timestamp
|
@@ -52,6 +95,8 @@ module Sentry
|
|
52
95
|
self
|
53
96
|
end
|
54
97
|
|
98
|
+
# Generates a trace string that can be used to connect other transactions.
|
99
|
+
# @return [String]
|
55
100
|
def to_sentry_trace
|
56
101
|
sampled_flag = ""
|
57
102
|
sampled_flag = @sampled ? 1 : 0 unless @sampled.nil?
|
@@ -59,6 +104,7 @@ module Sentry
|
|
59
104
|
"#{@trace_id}-#{@span_id}-#{sampled_flag}"
|
60
105
|
end
|
61
106
|
|
107
|
+
# @return [Hash]
|
62
108
|
def to_hash
|
63
109
|
{
|
64
110
|
trace_id: @trace_id,
|
@@ -74,6 +120,8 @@ module Sentry
|
|
74
120
|
}
|
75
121
|
end
|
76
122
|
|
123
|
+
# Returns the span's context that can be used to embed in an Event.
|
124
|
+
# @return [Hash]
|
77
125
|
def get_trace_context
|
78
126
|
{
|
79
127
|
trace_id: @trace_id,
|
@@ -85,9 +133,11 @@ module Sentry
|
|
85
133
|
}
|
86
134
|
end
|
87
135
|
|
88
|
-
|
89
|
-
|
90
|
-
|
136
|
+
# Starts a child span with given attributes.
|
137
|
+
# @param attributes [Hash] the attributes for the child span.
|
138
|
+
def start_child(**attributes)
|
139
|
+
attributes = attributes.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
|
140
|
+
new_span = Span.new(**attributes)
|
91
141
|
new_span.transaction = transaction
|
92
142
|
new_span.span_recorder = span_recorder
|
93
143
|
|
@@ -98,8 +148,17 @@ module Sentry
|
|
98
148
|
new_span
|
99
149
|
end
|
100
150
|
|
101
|
-
|
102
|
-
|
151
|
+
# Starts a child span, yield it to the given block, and then finish the span after the block is executed.
|
152
|
+
# @example
|
153
|
+
# span.with_child_span do |child_span|
|
154
|
+
# # things happen here will be recorded in a child span
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# @param attributes [Hash] the attributes for the child span.
|
158
|
+
# @param block [Proc] the action to be recorded in the child span.
|
159
|
+
# @yieldparam child_span [Span]
|
160
|
+
def with_child_span(**attributes, &block)
|
161
|
+
child_span = start_child(**attributes)
|
103
162
|
|
104
163
|
yield(child_span)
|
105
164
|
|
@@ -110,22 +169,33 @@ module Sentry
|
|
110
169
|
dup
|
111
170
|
end
|
112
171
|
|
172
|
+
# Sets the span's operation.
|
173
|
+
# @param op [String] operation of the span.
|
113
174
|
def set_op(op)
|
114
175
|
@op = op
|
115
176
|
end
|
116
177
|
|
178
|
+
# Sets the span's description.
|
179
|
+
# @param description [String] description of the span.
|
117
180
|
def set_description(description)
|
118
181
|
@description = description
|
119
182
|
end
|
120
183
|
|
184
|
+
|
185
|
+
# Sets the span's status.
|
186
|
+
# @param satus [String] status of the span.
|
121
187
|
def set_status(status)
|
122
188
|
@status = status
|
123
189
|
end
|
124
190
|
|
191
|
+
# Sets the span's finish timestamp.
|
192
|
+
# @param timestamp [Float] finished time in float format (most precise).
|
125
193
|
def set_timestamp(timestamp)
|
126
194
|
@timestamp = timestamp
|
127
195
|
end
|
128
196
|
|
197
|
+
# Sets the span's status with given http status code.
|
198
|
+
# @param status_code [String] example: "500".
|
129
199
|
def set_http_status(status_code)
|
130
200
|
status_code = status_code.to_i
|
131
201
|
set_data("status_code", status_code)
|
@@ -139,10 +209,16 @@ module Sentry
|
|
139
209
|
set_status(status)
|
140
210
|
end
|
141
211
|
|
212
|
+
# Inserts a key-value pair to the span's data payload.
|
213
|
+
# @param key [String, Symbol]
|
214
|
+
# @param value [Object]
|
142
215
|
def set_data(key, value)
|
143
216
|
@data[key] = value
|
144
217
|
end
|
145
218
|
|
219
|
+
# Sets a tag to the span.
|
220
|
+
# @param key [String, Symbol]
|
221
|
+
# @param value [String]
|
146
222
|
def set_tag(key, value)
|
147
223
|
@tags[key] = value
|
148
224
|
end
|
data/lib/sentry/transaction.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class Transaction < Span
|
3
5
|
SENTRY_TRACE_REGEXP = Regexp.new(
|
@@ -12,7 +14,22 @@ module Sentry
|
|
12
14
|
|
13
15
|
include LoggingHelper
|
14
16
|
|
15
|
-
|
17
|
+
# The name of the transaction.
|
18
|
+
# @return [String]
|
19
|
+
attr_reader :name
|
20
|
+
|
21
|
+
# The sampling decision of the parent transaction, which will be considered when making the current transaction's sampling decision.
|
22
|
+
# @return [String]
|
23
|
+
attr_reader :parent_sampled
|
24
|
+
|
25
|
+
# @deprecated Use Sentry.get_current_hub instead.
|
26
|
+
attr_reader :hub
|
27
|
+
|
28
|
+
# @deprecated Use Sentry.configuration instead.
|
29
|
+
attr_reader :configuration
|
30
|
+
|
31
|
+
# @deprecated Use Sentry.logger instead.
|
32
|
+
attr_reader :logger
|
16
33
|
|
17
34
|
def initialize(name: nil, parent_sampled: nil, hub:, **options)
|
18
35
|
super(**options)
|
@@ -21,11 +38,23 @@ module Sentry
|
|
21
38
|
@parent_sampled = parent_sampled
|
22
39
|
@transaction = self
|
23
40
|
@hub = hub
|
24
|
-
@configuration = hub.configuration
|
25
|
-
@
|
41
|
+
@configuration = hub.configuration # to be removed
|
42
|
+
@tracing_enabled = hub.configuration.tracing_enabled?
|
43
|
+
@traces_sampler = hub.configuration.traces_sampler
|
44
|
+
@traces_sample_rate = hub.configuration.traces_sample_rate
|
45
|
+
@logger = hub.configuration.logger
|
26
46
|
init_span_recorder
|
27
47
|
end
|
28
48
|
|
49
|
+
# Initalizes a Transaction instance with a Sentry trace string from another transaction (usually from an external request).
|
50
|
+
#
|
51
|
+
# The original transaction will become the parent of the new Transaction instance. And they will share the same `trace_id`.
|
52
|
+
#
|
53
|
+
# The child transaction will also store the parent's sampling decision in its `parent_sampled` attribute.
|
54
|
+
# @param sentry_trace [String] the trace string from the previous transaction.
|
55
|
+
# @param hub [Hub] the hub that'll be responsible for sending this transaction when it's finished.
|
56
|
+
# @param options [Hash] the options you want to use to initialize a Transaction instance.
|
57
|
+
# @return [Transaction, nil]
|
29
58
|
def self.from_sentry_trace(sentry_trace, hub: Sentry.get_current_hub, **options)
|
30
59
|
return unless hub.configuration.tracing_enabled?
|
31
60
|
return unless sentry_trace
|
@@ -44,12 +73,14 @@ module Sentry
|
|
44
73
|
new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: parent_sampled, hub: hub, **options)
|
45
74
|
end
|
46
75
|
|
76
|
+
# @return [Hash]
|
47
77
|
def to_hash
|
48
78
|
hash = super
|
49
79
|
hash.merge!(name: @name, sampled: @sampled, parent_sampled: @parent_sampled)
|
50
80
|
hash
|
51
81
|
end
|
52
82
|
|
83
|
+
# @return [Transaction]
|
53
84
|
def deep_dup
|
54
85
|
copy = super
|
55
86
|
copy.init_span_recorder(@span_recorder.max_length)
|
@@ -63,23 +94,24 @@ module Sentry
|
|
63
94
|
copy
|
64
95
|
end
|
65
96
|
|
97
|
+
# Sets initial sampling decision of the transaction.
|
98
|
+
# @param sampling_context [Hash] a context Hash that'll be passed to `traces_sampler` (if provided).
|
99
|
+
# @return [void]
|
66
100
|
def set_initial_sample_decision(sampling_context:)
|
67
|
-
unless
|
101
|
+
unless @tracing_enabled
|
68
102
|
@sampled = false
|
69
103
|
return
|
70
104
|
end
|
71
105
|
|
72
106
|
return unless @sampled.nil?
|
73
107
|
|
74
|
-
traces_sampler = configuration.traces_sampler
|
75
|
-
|
76
108
|
sample_rate =
|
77
|
-
if traces_sampler.is_a?(Proc)
|
78
|
-
traces_sampler.call(sampling_context)
|
109
|
+
if @traces_sampler.is_a?(Proc)
|
110
|
+
@traces_sampler.call(sampling_context)
|
79
111
|
elsif !sampling_context[:parent_sampled].nil?
|
80
112
|
sampling_context[:parent_sampled]
|
81
113
|
else
|
82
|
-
|
114
|
+
@traces_sample_rate
|
83
115
|
end
|
84
116
|
|
85
117
|
transaction_description = generate_transaction_description
|
@@ -111,6 +143,9 @@ module Sentry
|
|
111
143
|
end
|
112
144
|
end
|
113
145
|
|
146
|
+
# Finishes the transaction's recording and send it to Sentry.
|
147
|
+
# @param hub [Hub] the hub that'll send this transaction. (Deprecated)
|
148
|
+
# @return [TransactionEvent]
|
114
149
|
def finish(hub: nil)
|
115
150
|
if hub
|
116
151
|
log_warn(
|
@@ -129,13 +164,12 @@ module Sentry
|
|
129
164
|
@name = UNLABELD_NAME
|
130
165
|
end
|
131
166
|
|
132
|
-
|
167
|
+
if @sampled
|
168
|
+
event = hub.current_client.event_from_transaction(self)
|
169
|
+
hub.capture_event(event)
|
170
|
+
else
|
133
171
|
hub.current_client.transport.record_lost_event(:sample_rate, 'transaction')
|
134
|
-
return
|
135
172
|
end
|
136
|
-
|
137
|
-
event = hub.current_client.event_from_transaction(self)
|
138
|
-
hub.capture_event(event)
|
139
173
|
end
|
140
174
|
|
141
175
|
protected
|
@@ -16,17 +16,25 @@ module Sentry
|
|
16
16
|
attr_writer(*WRITER_ATTRIBUTES)
|
17
17
|
attr_reader(*SERIALIZEABLE_ATTRIBUTES)
|
18
18
|
|
19
|
+
# @return [<Array[Span]>]
|
19
20
|
attr_accessor :spans
|
20
21
|
|
22
|
+
# @param configuration [Configuration]
|
23
|
+
# @param integration_meta [Hash, nil]
|
24
|
+
# @param message [String, nil]
|
21
25
|
def initialize(configuration:, integration_meta: nil, message: nil)
|
22
26
|
super
|
23
27
|
@type = TYPE
|
24
28
|
end
|
25
29
|
|
30
|
+
# Sets the event's start_timestamp.
|
31
|
+
# @param time [Time, Float]
|
32
|
+
# @return [void]
|
26
33
|
def start_timestamp=(time)
|
27
34
|
@start_timestamp = time.is_a?(Time) ? time.to_f : time
|
28
35
|
end
|
29
36
|
|
37
|
+
# @return [Hash]
|
30
38
|
def to_hash
|
31
39
|
data = super
|
32
40
|
data[:spans] = @spans.map(&:to_hash) if @spans
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class Transport
|
3
5
|
class Configuration
|
4
|
-
attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :
|
5
|
-
:encoding
|
6
|
+
attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :encoding
|
6
7
|
attr_reader :transport_class
|
7
8
|
|
8
9
|
def initialize
|
@@ -1,14 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class DummyTransport < Transport
|
3
|
-
attr_accessor :events
|
5
|
+
attr_accessor :events, :envelopes
|
4
6
|
|
5
7
|
def initialize(*)
|
6
8
|
super
|
7
9
|
@events = []
|
10
|
+
@envelopes = []
|
8
11
|
end
|
9
12
|
|
10
13
|
def send_event(event)
|
11
14
|
@events << event
|
12
15
|
end
|
16
|
+
|
17
|
+
def send_envelope(envelope)
|
18
|
+
@envelopes << envelope
|
19
|
+
end
|
13
20
|
end
|
14
21
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "zlib"
|
3
5
|
|
4
6
|
module Sentry
|
5
7
|
class HTTPTransport < Transport
|
@@ -10,14 +12,13 @@ module Sentry
|
|
10
12
|
DEFAULT_DELAY = 60
|
11
13
|
RETRY_AFTER_HEADER = "retry-after"
|
12
14
|
RATE_LIMIT_HEADER = "x-sentry-rate-limits"
|
13
|
-
|
14
|
-
attr_reader :conn, :adapter
|
15
|
+
USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
|
15
16
|
|
16
17
|
def initialize(*args)
|
17
18
|
super
|
18
|
-
@adapter = @transport_configuration.http_adapter || Faraday.default_adapter
|
19
|
-
@conn = set_conn
|
20
19
|
@endpoint = @dsn.envelope_endpoint
|
20
|
+
|
21
|
+
log_debug("Sentry HTTP Transport will connect to #{@dsn.server}")
|
21
22
|
end
|
22
23
|
|
23
24
|
def send_data(data)
|
@@ -28,29 +29,37 @@ module Sentry
|
|
28
29
|
encoding = GZIP_ENCODING
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
headers = {
|
33
|
+
'Content-Type' => CONTENT_TYPE,
|
34
|
+
'Content-Encoding' => encoding,
|
35
|
+
'X-Sentry-Auth' => generate_auth_header,
|
36
|
+
'User-Agent' => USER_AGENT
|
37
|
+
}
|
38
|
+
|
39
|
+
response = conn.start do |http|
|
40
|
+
request = ::Net::HTTP::Post.new(@endpoint, headers)
|
41
|
+
request.body = data
|
42
|
+
http.request(request)
|
36
43
|
end
|
37
44
|
|
38
|
-
if
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
if response.code.match?(/\A2\d{2}/)
|
46
|
+
if has_rate_limited_header?(response)
|
47
|
+
handle_rate_limited_response(response)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
error_info = "the server responded with status #{response.code}"
|
43
51
|
|
44
|
-
|
45
|
-
|
46
|
-
handle_rate_limited_response(e.response[:headers])
|
52
|
+
if response.code == "429"
|
53
|
+
handle_rate_limited_response(response)
|
47
54
|
else
|
48
|
-
error_info += "\nbody: #{
|
49
|
-
error_info += " Error in headers is: #{
|
55
|
+
error_info += "\nbody: #{response.body}"
|
56
|
+
error_info += " Error in headers is: #{response['x-sentry-error']}" if response['x-sentry-error']
|
50
57
|
end
|
51
|
-
end
|
52
58
|
|
53
|
-
|
59
|
+
raise Sentry::ExternalError, error_info
|
60
|
+
end
|
61
|
+
rescue SocketError => e
|
62
|
+
raise Sentry::ExternalError.new(e.message)
|
54
63
|
end
|
55
64
|
|
56
65
|
private
|
@@ -117,32 +126,36 @@ module Sentry
|
|
117
126
|
@transport_configuration.encoding == GZIP_ENCODING && data.bytesize >= GZIP_THRESHOLD
|
118
127
|
end
|
119
128
|
|
120
|
-
def
|
121
|
-
server = @dsn.server
|
129
|
+
def conn
|
130
|
+
server = URI(@dsn.server)
|
122
131
|
|
123
|
-
|
132
|
+
connection =
|
133
|
+
if proxy = @transport_configuration.proxy
|
134
|
+
::Net::HTTP.new(server.hostname, server.port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
|
135
|
+
else
|
136
|
+
::Net::HTTP.new(server.hostname, server.port, nil)
|
137
|
+
end
|
124
138
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
builder.headers[:user_agent] = "sentry-ruby/#{Sentry::VERSION}"
|
130
|
-
builder.adapter(*adapter)
|
131
|
-
end
|
132
|
-
end
|
139
|
+
connection.use_ssl = server.scheme == "https"
|
140
|
+
connection.read_timeout = @transport_configuration.timeout
|
141
|
+
connection.write_timeout = @transport_configuration.timeout if connection.respond_to?(:write_timeout)
|
142
|
+
connection.open_timeout = @transport_configuration.open_timeout
|
133
143
|
|
134
|
-
|
135
|
-
|
136
|
-
[:timeout, :open_timeout].each_with_object({}) do |opt, memo|
|
137
|
-
memo[opt] = @transport_configuration.public_send(opt) if @transport_configuration.public_send(opt)
|
144
|
+
ssl_configuration.each do |key, value|
|
145
|
+
connection.send("#{key}=", value)
|
138
146
|
end
|
147
|
+
|
148
|
+
connection
|
139
149
|
end
|
140
150
|
|
141
151
|
def ssl_configuration
|
142
|
-
|
143
|
-
:
|
144
|
-
:
|
145
|
-
)
|
152
|
+
configuration = {
|
153
|
+
verify: @transport_configuration.ssl_verification,
|
154
|
+
ca_file: @transport_configuration.ssl_ca_file
|
155
|
+
}.merge(@transport_configuration.ssl || {})
|
156
|
+
|
157
|
+
configuration[:verify_mode] = configuration.delete(:verify) ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
158
|
+
configuration
|
146
159
|
end
|
147
160
|
end
|
148
161
|
end
|