ddtrace 0.12.1 → 0.13.0.beta1

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 (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