ddtrace 0.12.1 → 0.13.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.env +11 -21
  3. data/.rubocop.yml +1 -4
  4. data/Appraisals +75 -439
  5. data/CHANGELOG.md +16 -19
  6. data/Rakefile +89 -259
  7. data/circle.yml +69 -0
  8. data/ddtrace.gemspec +6 -6
  9. data/docker-compose.yml +37 -222
  10. data/docs/GettingStarted.md +260 -19
  11. data/gemfiles/contrib.gemfile +5 -0
  12. data/gemfiles/contrib_old.gemfile +4 -1
  13. data/gemfiles/rails30_postgres.gemfile +0 -1
  14. data/gemfiles/rails30_postgres_sidekiq.gemfile +0 -1
  15. data/gemfiles/rails32_mysql2.gemfile +0 -1
  16. data/gemfiles/rails32_postgres.gemfile +0 -1
  17. data/gemfiles/rails32_postgres_redis.gemfile +0 -1
  18. data/gemfiles/rails32_postgres_sidekiq.gemfile +0 -1
  19. data/gemfiles/rails5_mysql2.gemfile +1 -1
  20. data/gemfiles/rails5_postgres.gemfile +1 -1
  21. data/gemfiles/rails5_postgres_redis.gemfile +1 -1
  22. data/gemfiles/rails5_postgres_sidekiq.gemfile +1 -1
  23. data/lib/ddtrace.rb +6 -0
  24. data/lib/ddtrace/configuration.rb +2 -2
  25. data/lib/ddtrace/contrib/active_model_serializers/event.rb +57 -0
  26. data/lib/ddtrace/contrib/active_model_serializers/events.rb +30 -0
  27. data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +32 -0
  28. data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +35 -0
  29. data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +62 -0
  30. data/lib/ddtrace/contrib/active_record/event.rb +30 -0
  31. data/lib/ddtrace/contrib/active_record/events.rb +30 -0
  32. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +51 -0
  33. data/lib/ddtrace/contrib/active_record/events/sql.rb +48 -0
  34. data/lib/ddtrace/contrib/active_record/patcher.rb +3 -73
  35. data/lib/ddtrace/contrib/active_record/utils.rb +1 -15
  36. data/lib/ddtrace/contrib/active_support/notifications/event.rb +62 -0
  37. data/lib/ddtrace/contrib/aws/instrumentation.rb +2 -2
  38. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +2 -2
  39. data/lib/ddtrace/contrib/elasticsearch/quantize.rb +8 -40
  40. data/lib/ddtrace/contrib/excon/middleware.rb +140 -0
  41. data/lib/ddtrace/contrib/excon/patcher.rb +50 -0
  42. data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +65 -0
  43. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +49 -0
  44. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +66 -0
  45. data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +49 -0
  46. data/lib/ddtrace/contrib/grpc/patcher.rb +62 -0
  47. data/lib/ddtrace/contrib/http/patcher.rb +16 -18
  48. data/lib/ddtrace/contrib/racecar/event.rb +61 -0
  49. data/lib/ddtrace/contrib/racecar/events.rb +30 -0
  50. data/lib/ddtrace/contrib/racecar/events/batch.rb +27 -0
  51. data/lib/ddtrace/contrib/racecar/events/message.rb +27 -0
  52. data/lib/ddtrace/contrib/racecar/patcher.rb +6 -52
  53. data/lib/ddtrace/contrib/rack/middlewares.rb +65 -11
  54. data/lib/ddtrace/contrib/rack/patcher.rb +16 -0
  55. data/lib/ddtrace/contrib/rack/request_queue.rb +34 -0
  56. data/lib/ddtrace/contrib/rails/action_view.rb +65 -0
  57. data/lib/ddtrace/contrib/rails/active_support.rb +8 -9
  58. data/lib/ddtrace/contrib/rails/core_extensions.rb +115 -74
  59. data/lib/ddtrace/contrib/rake/instrumentation.rb +70 -0
  60. data/lib/ddtrace/contrib/rake/patcher.rb +53 -0
  61. data/lib/ddtrace/contrib/sequel/database.rb +58 -0
  62. data/lib/ddtrace/contrib/sequel/dataset.rb +59 -0
  63. data/lib/ddtrace/contrib/sequel/patcher.rb +56 -0
  64. data/lib/ddtrace/contrib/sequel/utils.rb +28 -0
  65. data/lib/ddtrace/ext/distributed.rb +5 -0
  66. data/lib/ddtrace/ext/grpc.rb +7 -0
  67. data/lib/ddtrace/ext/http.rb +35 -5
  68. data/lib/ddtrace/propagation/grpc_propagator.rb +54 -0
  69. data/lib/ddtrace/quantization/hash.rb +89 -0
  70. data/lib/ddtrace/tracer.rb +1 -4
  71. data/lib/ddtrace/utils.rb +4 -10
  72. data/lib/ddtrace/utils/database.rb +21 -0
  73. data/lib/ddtrace/version.rb +3 -3
  74. metadata +38 -13
  75. data/.circleci/config.yml +0 -456
  76. data/.circleci/images/primary/Dockerfile-1.9.3 +0 -69
  77. data/.circleci/images/primary/Dockerfile-2.0.0 +0 -69
  78. data/.circleci/images/primary/Dockerfile-2.1.10 +0 -69
  79. data/.circleci/images/primary/Dockerfile-2.2.10 +0 -69
  80. data/.circleci/images/primary/Dockerfile-2.3.7 +0 -73
  81. data/.circleci/images/primary/Dockerfile-2.4.4 +0 -73
  82. data/lib/ddtrace/contrib/rails/action_controller_patch.rb +0 -77
@@ -17,6 +17,7 @@ module Datadog
17
17
 
18
18
  def self.start_trace_cache(payload)
19
19
  tracer = Datadog.configuration[:rails][:tracer]
20
+ tracing_context = payload.fetch(:tracing_context)
20
21
 
21
22
  # In most of the cases Rails ``fetch()`` and ``read()`` calls are nested.
22
23
  # This check ensures that two reads are not nested since they don't provide
@@ -24,16 +25,14 @@ module Datadog
24
25
  # NOTE: the ``finish_trace_cache()`` is fired but it already has a safe-guard
25
26
  # to avoid any kind of issue.
26
27
  current_span = tracer.active_span
27
- return if payload[:action] == 'GET'.freeze &&
28
- current_span.try(:name) == 'rails.cache'.freeze &&
29
- current_span.try(:resource) == 'GET'.freeze
30
-
31
- tracing_context = payload.fetch(:tracing_context)
28
+ return if current_span.try('name') == 'rails.cache' &&
29
+ current_span.try('resource') == 'GET' &&
30
+ payload[:action] == 'GET'
32
31
 
33
32
  # create a new ``Span`` and add it to the tracing context
34
33
  service = Datadog.configuration[:rails][:cache_service]
35
34
  type = Datadog::Ext::CACHE::TYPE
36
- span = tracer.trace('rails.cache'.freeze, service: service, span_type: type)
35
+ span = tracer.trace('rails.cache', service: service, span_type: type)
37
36
  span.resource = payload.fetch(:action)
38
37
  tracing_context[:dd_cache_span] = span
39
38
  rescue StandardError => e
@@ -49,12 +48,12 @@ module Datadog
49
48
  begin
50
49
  # discard parameters from the cache_store configuration
51
50
  store, = *Array.wrap(::Rails.configuration.cache_store).flatten
52
- span.set_tag('rails.cache.backend'.freeze, store)
51
+ span.set_tag('rails.cache.backend', store)
53
52
  cache_key = Datadog::Utils.truncate(payload.fetch(:key), Ext::CACHE::MAX_KEY_SIZE)
54
- span.set_tag('rails.cache.key'.freeze, cache_key)
53
+ span.set_tag('rails.cache.key', cache_key)
55
54
  span.set_error(payload[:exception]) if payload[:exception]
56
55
  ensure
57
- span.finish
56
+ span.finish()
58
57
  end
59
58
  rescue StandardError => e
60
59
  Datadog::Tracer.log.debug(e.message)
@@ -6,11 +6,6 @@ module Datadog
6
6
  module RailsRendererPatcher
7
7
  include Datadog::Patcher
8
8
 
9
- SPAN_NAME_RENDER_PARTIAL = 'rails.render_partial'.freeze
10
- SPAN_NAME_RENDER_TEMPLATE = 'rails.render_template'.freeze
11
- TAG_LAYOUT = 'rails.layout'.freeze
12
- TAG_TEMPLATE_NAME = 'rails.template_name'.freeze
13
-
14
9
  module_function
15
10
 
16
11
  def patch_renderer
@@ -29,22 +24,25 @@ module Datadog
29
24
  end
30
25
 
31
26
  def patch_template_renderer(klass)
32
- # rubocop:disable Metrics/BlockLength
33
27
  do_once(:patch_template_renderer) do
34
28
  klass.class_eval do
35
29
  def render_with_datadog(*args, &block)
36
- # NOTE: This check exists purely for Rails 3.0 compatibility.
37
- # The 'if' part can be removed when support for Rails 3.0 is removed.
38
- if active_datadog_span
39
- render_without_datadog(*args, &block)
40
- else
41
- datadog_tracer.trace(
42
- Datadog::RailsRendererPatcher::SPAN_NAME_RENDER_TEMPLATE,
43
- span_type: Datadog::Ext::HTTP::TEMPLATE
44
- ) do |span|
45
- with_datadog_span(span) { render_without_datadog(*args, &block) }
46
- end
30
+ # create a tracing context and start the rendering span
31
+ # NOTE: Rails < 3.1 compatibility: preserve the tracing
32
+ # context when a partial is rendered
33
+ @tracing_context ||= {}
34
+ if @tracing_context.empty?
35
+ Datadog::Contrib::Rails::ActionView.start_render_template(tracing_context: @tracing_context)
47
36
  end
37
+
38
+ render_without_datadog(*args, &block)
39
+ rescue Exception => e
40
+ # attach the exception to the tracing context if any
41
+ @tracing_context[:exception] = e
42
+ raise e
43
+ ensure
44
+ # ensure that the template `Span` is finished even during exceptions
45
+ Datadog::Contrib::Rails::ActionView.finish_render_template(tracing_context: @tracing_context)
48
46
  end
49
47
 
50
48
  def render_template_with_datadog(*args)
@@ -62,19 +60,8 @@ module Datadog
62
60
  else
63
61
  layout_name.try(:[], 'virtual_path')
64
62
  end
65
- if template_name
66
- active_datadog_span.set_tag(
67
- Datadog::RailsRendererPatcher::TAG_TEMPLATE_NAME,
68
- template_name
69
- )
70
- end
71
-
72
- if layout
73
- active_datadog_span.set_tag(
74
- Datadog::RailsRendererPatcher::TAG_LAYOUT,
75
- layout
76
- )
77
- end
63
+ @tracing_context[:template_name] = template_name
64
+ @tracing_context[:layout] = layout
78
65
  rescue StandardError => e
79
66
  Datadog::Tracer.log.debug(e.message)
80
67
  end
@@ -83,21 +70,6 @@ module Datadog
83
70
  render_template_without_datadog(*args)
84
71
  end
85
72
 
86
- private
87
-
88
- attr_accessor :active_datadog_span
89
-
90
- def datadog_tracer
91
- Datadog.configuration[:rails][:tracer]
92
- end
93
-
94
- def with_datadog_span(span)
95
- self.active_datadog_span = span
96
- yield
97
- ensure
98
- self.active_datadog_span = nil
99
- end
100
-
101
73
  # method aliasing to patch the class
102
74
  alias_method :render_without_datadog, :render
103
75
  alias_method :render, :render_with_datadog
@@ -118,23 +90,30 @@ module Datadog
118
90
  do_once(:patch_partial_renderer) do
119
91
  klass.class_eval do
120
92
  def render_with_datadog(*args, &block)
121
- datadog_tracer.trace(
122
- Datadog::RailsRendererPatcher::SPAN_NAME_RENDER_PARTIAL,
123
- span_type: Datadog::Ext::HTTP::TEMPLATE
124
- ) do |span|
125
- with_datadog_span(span) { render_without_datadog(*args) }
126
- end
93
+ # Create a tracing context and start the rendering span
94
+ tracing_context = {}
95
+ Datadog::Contrib::Rails::ActionView.start_render_partial(tracing_context: tracing_context)
96
+ tracing_contexts[current_span_id] = tracing_context
97
+
98
+ render_without_datadog(*args)
99
+ rescue Exception => e
100
+ # attach the exception to the tracing context if any
101
+ tracing_contexts[current_span_id][:exception] = e
102
+ raise e
103
+ ensure
104
+ # Ensure that the template `Span` is finished even during exceptions
105
+ # Remove the existing tracing context (to avoid leaks)
106
+ tracing_contexts.delete(current_span_id)
107
+
108
+ # Then finish the span associated with the context
109
+ Datadog::Contrib::Rails::ActionView.finish_render_partial(tracing_context: tracing_context)
127
110
  end
128
111
 
129
112
  def render_partial_with_datadog(*args)
130
113
  begin
114
+ # update the tracing context with computed values before the rendering
131
115
  template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(@template.try('identifier'))
132
- if template_name
133
- active_datadog_span.set_tag(
134
- Datadog::RailsRendererPatcher::TAG_TEMPLATE_NAME,
135
- template_name
136
- )
137
- end
116
+ tracing_contexts[current_span_id][:template_name] = template_name
138
117
  rescue StandardError => e
139
118
  Datadog::Tracer.log.debug(e.message)
140
119
  end
@@ -143,19 +122,15 @@ module Datadog
143
122
  render_partial_without_datadog(*args)
144
123
  end
145
124
 
146
- private
147
-
148
- attr_accessor :active_datadog_span
149
-
150
- def datadog_tracer
151
- Datadog.configuration[:rails][:tracer]
125
+ # Table of tracing contexts, one per partial/span, keyed by span_id
126
+ # because there will be multiple concurrent contexts, depending on how
127
+ # many partials are nested within one another.
128
+ def tracing_contexts
129
+ @tracing_contexts ||= {}
152
130
  end
153
131
 
154
- def with_datadog_span(span)
155
- self.active_datadog_span = span
156
- yield
157
- ensure
158
- self.active_datadog_span = nil
132
+ def current_span_id
133
+ Datadog.configuration[:rails][:tracer].call_context.current_span.span_id
159
134
  end
160
135
 
161
136
  # method aliasing to patch the class
@@ -182,9 +157,79 @@ module Datadog
182
157
 
183
158
  def patch_process_action
184
159
  do_once(:patch_process_action) do
185
- require 'ddtrace/contrib/rails/action_controller_patch'
160
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0.0')
161
+ # Patch Rails controller base class
162
+ ::ActionController::Metal.send(:prepend, ActionControllerPatch)
163
+ else
164
+ # Rewrite module that gets composed into the Rails controller base class
165
+ ::ActionController::Instrumentation.class_eval do
166
+ def process_action_with_datadog(*args)
167
+ # mutable payload with a tracing context that is used in two different
168
+ # signals; it propagates the request span so that it can be finished
169
+ # no matter what
170
+ payload = {
171
+ controller: self.class,
172
+ action: action_name,
173
+ headers: {
174
+ # The exception this controller was given in the request,
175
+ # which is typical if the controller is configured to handle exceptions.
176
+ request_exception: request.headers['action_dispatch.exception']
177
+ },
178
+ tracing_context: {}
179
+ }
180
+
181
+ begin
182
+ # process and catch request exceptions
183
+ Datadog::Contrib::Rails::ActionController.start_processing(payload)
184
+ result = process_action_without_datadog(*args)
185
+ payload[:status] = response.status
186
+ result
187
+ rescue Exception => e
188
+ payload[:exception] = [e.class.name, e.message]
189
+ payload[:exception_object] = e
190
+ raise e
191
+ end
192
+ ensure
193
+ Datadog::Contrib::Rails::ActionController.finish_processing(payload)
194
+ end
186
195
 
187
- ::ActionController::Metal.send(:include, Datadog::Contrib::Rails::ActionControllerPatch)
196
+ alias_method :process_action_without_datadog, :process_action
197
+ alias_method :process_action, :process_action_with_datadog
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ # ActionController patch for Ruby 2.0+
204
+ module ActionControllerPatch
205
+ def process_action(*args)
206
+ # mutable payload with a tracing context that is used in two different
207
+ # signals; it propagates the request span so that it can be finished
208
+ # no matter what
209
+ payload = {
210
+ controller: self.class,
211
+ action: action_name,
212
+ headers: {
213
+ # The exception this controller was given in the request,
214
+ # which is typical if the controller is configured to handle exceptions.
215
+ request_exception: request.headers['action_dispatch.exception']
216
+ },
217
+ tracing_context: {}
218
+ }
219
+
220
+ begin
221
+ # process and catch request exceptions
222
+ Datadog::Contrib::Rails::ActionController.start_processing(payload)
223
+ result = super(*args)
224
+ payload[:status] = response.status
225
+ result
226
+ rescue Exception => e
227
+ payload[:exception] = [e.class.name, e.message]
228
+ payload[:exception_object] = e
229
+ raise e
230
+ end
231
+ ensure
232
+ Datadog::Contrib::Rails::ActionController.finish_processing(payload)
188
233
  end
189
234
  end
190
235
  end
@@ -225,7 +270,6 @@ module Datadog
225
270
  do_once(:patch_cache_store_read) do
226
271
  cache_store_class(:read).class_eval do
227
272
  alias_method :read_without_datadog, :read
228
-
229
273
  def read(*args, &block)
230
274
  payload = {
231
275
  action: 'GET',
@@ -253,7 +297,6 @@ module Datadog
253
297
  do_once(:patch_cache_store_fetch) do
254
298
  cache_store_class(:fetch).class_eval do
255
299
  alias_method :fetch_without_datadog, :fetch
256
-
257
300
  def fetch(*args, &block)
258
301
  payload = {
259
302
  action: 'GET',
@@ -281,7 +324,6 @@ module Datadog
281
324
  do_once(:patch_cache_store_write) do
282
325
  cache_store_class(:write).class_eval do
283
326
  alias_method :write_without_datadog, :write
284
-
285
327
  def write(*args, &block)
286
328
  payload = {
287
329
  action: 'SET',
@@ -309,7 +351,6 @@ module Datadog
309
351
  do_once(:patch_cache_store_delete) do
310
352
  cache_store_class(:delete).class_eval do
311
353
  alias_method :delete_without_datadog, :delete
312
-
313
354
  def delete(*args, &block)
314
355
  payload = {
315
356
  action: 'DELETE',
@@ -0,0 +1,70 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Rake
4
+ # Instrumentation for Rake tasks
5
+ module Instrumentation
6
+ SPAN_NAME_INVOKE = 'rake.invoke'.freeze
7
+ SPAN_NAME_EXECUTE = 'rake.execute'.freeze
8
+
9
+ def self.included(base)
10
+ base.send(:prepend, InstanceMethods)
11
+ end
12
+
13
+ # Instance methods for Rake instrumentation
14
+ module InstanceMethods
15
+ def invoke(*args)
16
+ return super unless enabled?
17
+
18
+ tracer.trace(SPAN_NAME_INVOKE) do |span|
19
+ super
20
+ annotate_invoke!(span, args)
21
+ end
22
+ end
23
+
24
+ def execute(args = nil)
25
+ return super unless enabled?
26
+
27
+ tracer.trace(SPAN_NAME_EXECUTE) do |span|
28
+ super
29
+ annotate_execute!(span, args)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def annotate_invoke!(span, args)
36
+ span.resource = name
37
+ span.set_tag('rake.task.arg_names', arg_names)
38
+ span.set_tag('rake.invoke.args', quantize_args(args)) unless args.nil?
39
+ rescue StandardError => e
40
+ Datadog::Tracer.log.debug("Error while tracing Rake invoke: #{e.message}")
41
+ end
42
+
43
+ def annotate_execute!(span, args)
44
+ span.resource = name
45
+ span.set_tag('rake.execute.args', quantize_args(args.to_hash)) unless args.nil?
46
+ rescue StandardError => e
47
+ Datadog::Tracer.log.debug("Error while tracing Rake execute: #{e.message}")
48
+ end
49
+
50
+ def quantize_args(args)
51
+ quantize_options = Datadog.configuration[:rake][:quantize][:args]
52
+ Datadog::Quantization::Hash.format(args, quantize_options)
53
+ end
54
+
55
+ def enabled?
56
+ configuration[:enabled] == true
57
+ end
58
+
59
+ def tracer
60
+ configuration[:tracer]
61
+ end
62
+
63
+ def configuration
64
+ Datadog.configuration[:rake]
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,53 @@
1
+ require 'ddtrace/ext/app_types'
2
+ require 'ddtrace/contrib/rake/instrumentation'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ module Rake
7
+ # Patcher for Rake instrumentation
8
+ module Patcher
9
+ include Base
10
+
11
+ register_as :rake
12
+ option :service_name, default: 'rake'
13
+ option :tracer, default: Datadog.tracer
14
+ option :enabled, default: true
15
+ option :quantize, default: {}
16
+
17
+ module_function
18
+
19
+ def patch
20
+ return patched? if patched? || !compatible?
21
+
22
+ patch_rake
23
+
24
+ # Set service info
25
+ configuration[:tracer].set_service_info(
26
+ configuration[:service_name],
27
+ 'rake',
28
+ Ext::AppTypes::WORKER
29
+ )
30
+
31
+ @patched = true
32
+ end
33
+
34
+ def patched?
35
+ return @patched if defined?(@patched)
36
+ @patched = false
37
+ end
38
+
39
+ def patch_rake
40
+ ::Rake::Task.send(:include, Instrumentation)
41
+ end
42
+
43
+ def compatible?
44
+ RUBY_VERSION >= '2.0.0' && defined?(::Rake)
45
+ end
46
+
47
+ def configuration
48
+ Datadog.configuration[:rake]
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,58 @@
1
+ require 'ddtrace/ext/sql'
2
+ require 'ddtrace/ext/app_types'
3
+ require 'ddtrace/contrib/sequel/utils'
4
+
5
+ module Datadog
6
+ module Contrib
7
+ module Sequel
8
+ # Adds instrumentation to Sequel::Database
9
+ module Database
10
+ def self.included(base)
11
+ base.send(:prepend, InstanceMethods)
12
+ end
13
+
14
+ # Instance methods for instrumenting Sequel::Database
15
+ module InstanceMethods
16
+ def run(sql, options = ::Sequel::OPTS)
17
+ opts = parse_opts(sql, options)
18
+
19
+ response = nil
20
+
21
+ datadog_pin.tracer.trace('sequel.query') do |span|
22
+ span.service = datadog_pin.service
23
+ span.resource = opts[:query]
24
+ span.span_type = Datadog::Ext::SQL::TYPE
25
+ span.set_tag('sequel.db.vendor', adapter_name)
26
+ response = super(sql, options)
27
+ end
28
+ response
29
+ end
30
+
31
+ def datadog_pin
32
+ @pin ||= Datadog::Pin.new(
33
+ Datadog.configuration[:sequel][:service_name] || adapter_name,
34
+ app: Patcher::APP,
35
+ app_type: Datadog::Ext::AppTypes::DB,
36
+ tracer: Datadog.configuration[:sequel][:tracer] || Datadog.tracer
37
+ )
38
+ end
39
+
40
+ private
41
+
42
+ def adapter_name
43
+ Utils.adapter_name(self)
44
+ end
45
+
46
+ def parse_opts(sql, opts)
47
+ db_opts = if ::Sequel::VERSION < '3.41.0' && self.class.to_s !~ /Dataset$/
48
+ @opts
49
+ elsif instance_variable_defined?(:@pool) && @pool
50
+ @pool.db.opts
51
+ end
52
+ Utils.parse_opts(sql, opts, db_opts)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end