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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Gemfile +3 -0
  4. data/README.md +2 -0
  5. data/lib/sentry/background_worker.rb +33 -3
  6. data/lib/sentry/backtrace.rb +1 -3
  7. data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
  8. data/lib/sentry/breadcrumb.rb +24 -3
  9. data/lib/sentry/breadcrumb_buffer.rb +16 -0
  10. data/lib/sentry/client.rb +38 -2
  11. data/lib/sentry/configuration.rb +94 -41
  12. data/lib/sentry/core_ext/object/deep_dup.rb +2 -0
  13. data/lib/sentry/core_ext/object/duplicable.rb +1 -0
  14. data/lib/sentry/dsn.rb +2 -0
  15. data/lib/sentry/envelope.rb +45 -0
  16. data/lib/sentry/event.rb +55 -18
  17. data/lib/sentry/exceptions.rb +2 -0
  18. data/lib/sentry/hub.rb +38 -2
  19. data/lib/sentry/integrable.rb +2 -0
  20. data/lib/sentry/interface.rb +3 -10
  21. data/lib/sentry/interfaces/exception.rb +14 -3
  22. data/lib/sentry/interfaces/request.rb +37 -20
  23. data/lib/sentry/interfaces/single_exception.rb +2 -0
  24. data/lib/sentry/interfaces/stacktrace.rb +6 -0
  25. data/lib/sentry/interfaces/stacktrace_builder.rb +39 -10
  26. data/lib/sentry/interfaces/threads.rb +12 -2
  27. data/lib/sentry/linecache.rb +3 -0
  28. data/lib/sentry/net/http.rb +54 -65
  29. data/lib/sentry/rack/capture_exceptions.rb +28 -24
  30. data/lib/sentry/rack.rb +2 -0
  31. data/lib/sentry/rake.rb +16 -6
  32. data/lib/sentry/redis.rb +90 -0
  33. data/lib/sentry/release_detector.rb +3 -0
  34. data/lib/sentry/scope.rb +85 -6
  35. data/lib/sentry/session.rb +35 -0
  36. data/lib/sentry/session_flusher.rb +79 -0
  37. data/lib/sentry/span.rb +84 -8
  38. data/lib/sentry/transaction.rb +48 -14
  39. data/lib/sentry/transaction_event.rb +8 -0
  40. data/lib/sentry/transport/configuration.rb +3 -2
  41. data/lib/sentry/transport/dummy_transport.rb +8 -1
  42. data/lib/sentry/transport/http_transport.rb +55 -42
  43. data/lib/sentry/transport.rb +79 -37
  44. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  45. data/lib/sentry/utils/custom_inspection.rb +2 -0
  46. data/lib/sentry/utils/exception_cause_chain.rb +2 -0
  47. data/lib/sentry/utils/logging_helper.rb +6 -4
  48. data/lib/sentry/utils/real_ip.rb +2 -0
  49. data/lib/sentry/utils/request_id.rb +2 -0
  50. data/lib/sentry/version.rb +3 -1
  51. data/lib/sentry-ruby.rb +212 -41
  52. data/sentry-ruby-core.gemspec +0 -1
  53. data/sentry-ruby.gemspec +0 -1
  54. 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
- attr_reader :trace_id, :span_id, :parent_span_id, :sampled, :start_timestamp, :timestamp, :description, :op, :status, :tags, :data
22
- attr_accessor :span_recorder, :transaction
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
- def start_child(**options)
89
- options = options.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
90
- new_span = Span.new(**options)
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
- def with_child_span(**options, &block)
102
- child_span = start_child(**options)
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
@@ -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
- attr_reader :name, :parent_sampled, :hub, :configuration, :logger
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
- @logger = configuration.logger
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 configuration.tracing_enabled?
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
- configuration.traces_sample_rate
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
- unless @sampled || @parent_sampled
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, :http_adapter, :faraday_builder,
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
- require 'faraday'
2
- require 'zlib'
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
- response = conn.post @endpoint do |req|
32
- req.headers['Content-Type'] = CONTENT_TYPE
33
- req.headers['Content-Encoding'] = encoding
34
- req.headers['X-Sentry-Auth'] = generate_auth_header
35
- req.body = data
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 has_rate_limited_header?(response.headers)
39
- handle_rate_limited_response(response.headers)
40
- end
41
- rescue Faraday::Error => e
42
- error_info = e.message
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
- if e.response
45
- if e.response[:status] == 429
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: #{e.response[:body]}"
49
- error_info += " Error in headers is: #{e.response[:headers]['x-sentry-error']}" if e.response[:headers]['x-sentry-error']
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
- raise Sentry::ExternalError, error_info
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 set_conn
121
- server = @dsn.server
129
+ def conn
130
+ server = URI(@dsn.server)
122
131
 
123
- log_debug("Sentry HTTP Transport connecting to #{server}")
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
- Faraday.new(server, :ssl => ssl_configuration, :proxy => @transport_configuration.proxy) do |builder|
126
- @transport_configuration.faraday_builder&.call(builder)
127
- builder.response :raise_error
128
- builder.options.merge! faraday_opts
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
- # TODO: deprecate and replace where possible w/Faraday Builder
135
- def faraday_opts
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
- (@transport_configuration.ssl || {}).merge(
143
- :verify => @transport_configuration.ssl_verification,
144
- :ca_file => @transport_configuration.ssl_ca_file
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