ddtrace 0.28.0 → 0.29.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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +8 -0
  3. data/Appraisals +57 -2
  4. data/CHANGELOG.md +41 -12
  5. data/Rakefile +3 -3
  6. data/ddtrace.gemspec +2 -1
  7. data/docs/DevelopmentGuide.md +1 -1
  8. data/docs/GettingStarted.md +6 -6
  9. data/lib/ddtrace.rb +7 -0
  10. data/lib/ddtrace/buffer.rb +60 -1
  11. data/lib/ddtrace/configuration/base.rb +82 -0
  12. data/lib/ddtrace/configuration/option.rb +28 -5
  13. data/lib/ddtrace/configuration/option_definition.rb +100 -0
  14. data/lib/ddtrace/configuration/options.rb +28 -14
  15. data/lib/ddtrace/configuration/settings.rb +77 -64
  16. data/lib/ddtrace/contrib/action_pack/configuration/settings.rb +9 -7
  17. data/lib/ddtrace/contrib/action_view/configuration/settings.rb +8 -6
  18. data/lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb +8 -14
  19. data/lib/ddtrace/contrib/active_model_serializers/event.rb +1 -1
  20. data/lib/ddtrace/contrib/active_record/configuration/settings.rb +11 -16
  21. data/lib/ddtrace/contrib/active_record/event.rb +1 -1
  22. data/lib/ddtrace/contrib/active_support/configuration/settings.rb +8 -6
  23. data/lib/ddtrace/contrib/active_support/notifications/subscriber.rb +2 -2
  24. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +4 -1
  25. data/lib/ddtrace/contrib/aws/configuration/settings.rb +8 -6
  26. data/lib/ddtrace/contrib/configuration/settings.rb +5 -11
  27. data/lib/ddtrace/contrib/dalli/configuration/settings.rb +8 -6
  28. data/lib/ddtrace/contrib/dalli/instrumentation.rb +1 -18
  29. data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +8 -6
  30. data/lib/ddtrace/contrib/elasticsearch/configuration/settings.rb +8 -6
  31. data/lib/ddtrace/contrib/ethon/configuration/settings.rb +8 -6
  32. data/lib/ddtrace/contrib/ethon/integration.rb +0 -4
  33. data/lib/ddtrace/contrib/excon/configuration/settings.rb +9 -7
  34. data/lib/ddtrace/contrib/excon/middleware.rb +1 -1
  35. data/lib/ddtrace/contrib/faraday/configuration/settings.rb +8 -6
  36. data/lib/ddtrace/contrib/faraday/middleware.rb +1 -1
  37. data/lib/ddtrace/contrib/faraday/patcher.rb +8 -2
  38. data/lib/ddtrace/contrib/faraday/rack_builder.rb +18 -0
  39. data/lib/ddtrace/contrib/grape/configuration/settings.rb +8 -6
  40. data/lib/ddtrace/contrib/grape/instrumentation.rb +2 -42
  41. data/lib/ddtrace/contrib/graphql/configuration/settings.rb +8 -6
  42. data/lib/ddtrace/contrib/grpc/configuration/settings.rb +8 -6
  43. data/lib/ddtrace/contrib/grpc/integration.rb +1 -3
  44. data/lib/ddtrace/contrib/http/configuration/settings.rb +8 -6
  45. data/lib/ddtrace/contrib/http/instrumentation.rb +1 -23
  46. data/lib/ddtrace/contrib/mongodb/configuration/settings.rb +8 -6
  47. data/lib/ddtrace/contrib/mysql2/configuration/settings.rb +8 -6
  48. data/lib/ddtrace/contrib/mysql2/instrumentation.rb +1 -23
  49. data/lib/ddtrace/contrib/patchable.rb +1 -1
  50. data/lib/ddtrace/contrib/racecar/configuration/settings.rb +8 -14
  51. data/lib/ddtrace/contrib/racecar/event.rb +1 -1
  52. data/lib/ddtrace/contrib/rack/configuration/settings.rb +8 -6
  53. data/lib/ddtrace/contrib/rack/request_queue.rb +7 -6
  54. data/lib/ddtrace/contrib/rails/configuration/settings.rb +30 -21
  55. data/lib/ddtrace/contrib/rake/configuration/settings.rb +8 -6
  56. data/lib/ddtrace/contrib/rake/integration.rb +0 -4
  57. data/lib/ddtrace/contrib/redis/configuration/settings.rb +8 -6
  58. data/lib/ddtrace/contrib/resque/configuration/settings.rb +8 -6
  59. data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +8 -6
  60. data/lib/ddtrace/contrib/rest_client/integration.rb +0 -4
  61. data/lib/ddtrace/contrib/rest_client/request_patch.rb +1 -18
  62. data/lib/ddtrace/contrib/sequel/configuration/settings.rb +8 -6
  63. data/lib/ddtrace/contrib/sequel/integration.rb +0 -4
  64. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +8 -6
  65. data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +8 -6
  66. data/lib/ddtrace/contrib/sinatra/configuration/settings.rb +8 -6
  67. data/lib/ddtrace/contrib/sucker_punch/configuration/settings.rb +8 -6
  68. data/lib/ddtrace/diagnostics/health.rb +30 -0
  69. data/lib/ddtrace/distributed_tracing/headers/datadog.rb +1 -1
  70. data/lib/ddtrace/distributed_tracing/headers/headers.rb +2 -0
  71. data/lib/ddtrace/ext/diagnostics.rb +25 -0
  72. data/lib/ddtrace/ext/runtime.rb +1 -7
  73. data/lib/ddtrace/metrics.rb +89 -6
  74. data/lib/ddtrace/propagation/http_propagator.rb +2 -2
  75. data/lib/ddtrace/runtime/class_count.rb +3 -3
  76. data/lib/ddtrace/runtime/object_space.rb +19 -0
  77. data/lib/ddtrace/span.rb +1 -1
  78. data/lib/ddtrace/tracer.rb +5 -4
  79. data/lib/ddtrace/transport/http/client.rb +3 -4
  80. data/lib/ddtrace/transport/http/response.rb +4 -0
  81. data/lib/ddtrace/transport/http/statistics.rb +30 -0
  82. data/lib/ddtrace/transport/statistics.rb +28 -0
  83. data/lib/ddtrace/version.rb +3 -1
  84. data/lib/ddtrace/workers.rb +4 -2
  85. data/lib/ddtrace/writer.rb +3 -3
  86. metadata +74 -54
data/Rakefile CHANGED
@@ -54,7 +54,7 @@ namespace :spec do
54
54
 
55
55
  RSpec::Core::RakeTask.new(:contrib) do |t, args|
56
56
  # rubocop:disable Metrics/LineLength
57
- t.pattern = 'spec/**/contrib/{analytics,configurable,integration,patchable,patcher,registerable,registry,configuration/*}_spec.rb'
57
+ t.pattern = 'spec/**/contrib/{analytics,configurable,extensions,integration,patchable,patcher,registerable,registry,configuration/*}_spec.rb'
58
58
  t.rspec_opts = args.to_a.join(' ')
59
59
  end
60
60
 
@@ -189,8 +189,8 @@ end
189
189
 
190
190
  desc 'CI task; it runs all tests for current version of Ruby'
191
191
  task :ci do
192
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')
193
- raise NotImplementedError, 'Ruby versions < 2.0.0 are not supported!'
192
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new(Datadog::VERSION::MINIMUM_RUBY_VERSION)
193
+ raise NotImplementedError, "Ruby versions < #{Datadog::VERSION::MINIMUM_RUBY_VERSION} are not supported!"
194
194
  elsif Gem::Version.new('2.0.0') <= Gem::Version.new(RUBY_VERSION) \
195
195
  && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.1.0')
196
196
  # Main library
@@ -7,7 +7,7 @@ require 'ddtrace/version'
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'ddtrace'
9
9
  spec.version = Datadog::VERSION::STRING
10
- spec.required_ruby_version = '>= 2.0.0'
10
+ spec.required_ruby_version = ">= #{Datadog::VERSION::MINIMUM_RUBY_VERSION}"
11
11
  spec.authors = ['Datadog, Inc.']
12
12
  spec.email = ['dev@datadoghq.com']
13
13
 
@@ -58,4 +58,5 @@ Gem::Specification.new do |spec|
58
58
  spec.add_development_dependency 'redcarpet', '~> 3.4' if RUBY_PLATFORM != 'java'
59
59
  spec.add_development_dependency 'pry', '~> 0.10.4'
60
60
  spec.add_development_dependency 'pry-stack_explorer', '~> 0.4.9.2'
61
+ spec.add_development_dependency 'warning' if RUBY_VERSION >= '2.5.0'
61
62
  end
@@ -19,7 +19,7 @@ This guide covers some of the common how-tos and technical reference material fo
19
19
 
20
20
  The trace library uses Docker Compose to create a Ruby environment to develop and test within, as well as containers for any dependencies that might be necessary for certain kinds of tests.
21
21
 
22
- To start a development environment, choose a target Ruby version (e.g. between `1.9` and `2.4`) then run the following:
22
+ To start a development environment, choose a target Ruby version then run the following:
23
23
 
24
24
  ```
25
25
  # In the root directory of the project...
@@ -324,11 +324,11 @@ For a list of available integrations, and their configuration options, please re
324
324
 
325
325
  | Name | Key | Versions Supported | How to configure | Gem source |
326
326
  | ------------------------ | -------------------------- | ------------------------ | ----------------------------------- | ------------------------------------------------------------------------------ |
327
- | Action View | `action_view` | `>= 3.2` | *[Link](#action-view)* | *[Link](https://github.com/rails/rails/tree/master/actionview)* |
327
+ | Action View | `action_view` | `>= 3.2` | *[Link](#action-view)* | *[Link](https://github.com/rails/rails/tree/master/actionview)* |
328
328
  | Active Model Serializers | `active_model_serializers` | `>= 0.9` | *[Link](#active-model-serializers)* | *[Link](https://github.com/rails-api/active_model_serializers)* |
329
- | Action Pack | `action_pack` | `>= 3.2` | *[Link](#action-pack)* | *[Link](https://github.com/rails/rails/tree/master/actionpack)* |
330
- | Active Record | `active_record` | `>= 3.2` | *[Link](#active-record)* | *[Link](https://github.com/rails/rails/tree/master/activerecord)* |
331
- | Active Support | `active_support` | `>= 3.2` | *[Link](#active-support)* | *[Link](https://github.com/rails/rails/tree/master/activesupport)* |
329
+ | Action Pack | `action_pack` | `>= 3.2` | *[Link](#action-pack)* | *[Link](https://github.com/rails/rails/tree/master/actionpack)* |
330
+ | Active Record | `active_record` | `>= 3.2` | *[Link](#active-record)* | *[Link](https://github.com/rails/rails/tree/master/activerecord)* |
331
+ | Active Support | `active_support` | `>= 3.2` | *[Link](#active-support)* | *[Link](https://github.com/rails/rails/tree/master/activesupport)* |
332
332
  | AWS | `aws` | `>= 2.0` | *[Link](#aws)* | *[Link](https://github.com/aws/aws-sdk-ruby)* |
333
333
  | Concurrent Ruby | `concurrent_ruby` | `>= 0.9` | *[Link](#concurrent-ruby)* | *[Link](https://github.com/ruby-concurrency/concurrent-ruby)* |
334
334
  | Dalli | `dalli` | `>= 2.7` | *[Link](#dalli)* | *[Link](https://github.com/petergoldstein/dalli)* |
@@ -345,9 +345,9 @@ For a list of available integrations, and their configuration options, please re
345
345
  | Net/HTTP | `http` | *(Any supported Ruby)* | *[Link](#nethttp)* | *[Link](https://ruby-doc.org/stdlib-2.4.0/libdoc/net/http/rdoc/Net/HTTP.html)* |
346
346
  | Racecar | `racecar` | `>= 0.3.5` | *[Link](#racecar)* | *[Link](https://github.com/zendesk/racecar)* |
347
347
  | Rack | `rack` | `>= 1.4.7` | *[Link](#rack)* | *[Link](https://github.com/rack/rack)* |
348
- | Rails | `rails` | `>= 3.2` | *[Link](#rails)* | *[Link](https://github.com/rails/rails)* |
348
+ | Rails | `rails` | `>= 3.2` | *[Link](#rails)* | *[Link](https://github.com/rails/rails)* |
349
349
  | Rake | `rake` | `>= 12.0` | *[Link](#rake)* | *[Link](https://github.com/ruby/rake)* |
350
- | Redis | `redis` | `>= 3.2, < 4.0` | *[Link](#redis)* | *[Link](https://github.com/redis/redis-rb)* |
350
+ | Redis | `redis` | `>= 3.2` | *[Link](#redis)* | *[Link](https://github.com/redis/redis-rb)* |
351
351
  | Resque | `resque` | `>= 1.0, < 2.0` | *[Link](#resque)* | *[Link](https://github.com/resque/resque)* |
352
352
  | Rest Client | `rest-client` | `>= 1.8` | *[Link](#rest-client)* | *[Link](https://github.com/rest-client/rest-client)* |
353
353
  | Sequel | `sequel` | `>= 3.41` | *[Link](#sequel)* | *[Link](https://github.com/jeremyevans/sequel)* |
@@ -1,5 +1,12 @@
1
1
  require 'thread'
2
2
 
3
+ # During development, we load `ddtrace` by through `ddtrace.gemspec`,
4
+ # which in turn eager loads 'ddtrace/version'.
5
+ #
6
+ # Users load this gem by requiring this file.
7
+ # We need to ensure that any files loaded in our gemspec are also loaded here.
8
+ require 'ddtrace/version'
9
+
3
10
  require 'ddtrace/pin'
4
11
  require 'ddtrace/tracer'
5
12
  require 'ddtrace/error'
@@ -1,4 +1,6 @@
1
1
  require 'thread'
2
+ require 'ddtrace/diagnostics/health'
3
+ require 'ddtrace/runtime/object_space'
2
4
 
3
5
  module Datadog
4
6
  # Trace buffer that stores application traces. The buffer has a maximum size and when
@@ -11,6 +13,12 @@ module Datadog
11
13
  @mutex = Mutex.new()
12
14
  @traces = []
13
15
  @closed = false
16
+
17
+ # Initialize metric values
18
+ @buffer_accepted = 0
19
+ @buffer_accepted_lengths = 0
20
+ @buffer_dropped = 0
21
+ @buffer_spans = 0
14
22
  end
15
23
 
16
24
  # Add a new ``trace`` in the local queue. This method doesn't block the execution
@@ -23,8 +31,13 @@ module Datadog
23
31
  @traces << trace
24
32
  else
25
33
  # we should replace a random trace with the new one
26
- @traces[rand(len)] = trace
34
+ replace_index = rand(len)
35
+ replaced_trace = @traces[replace_index]
36
+ @traces[replace_index] = trace
37
+ measure_drop(replaced_trace)
27
38
  end
39
+
40
+ measure_accept(trace)
28
41
  end
29
42
  end
30
43
 
@@ -47,6 +60,9 @@ module Datadog
47
60
  @mutex.synchronize do
48
61
  traces = @traces
49
62
  @traces = []
63
+
64
+ measure_pop(traces)
65
+
50
66
  return traces
51
67
  end
52
68
  end
@@ -56,5 +72,48 @@ module Datadog
56
72
  @closed = true
57
73
  end
58
74
  end
75
+
76
+ # Aggregate metrics:
77
+ # They reflect buffer activity since last #pop.
78
+ # These may not be as accurate or as granular, but they
79
+ # don't use as much network traffic as live stats.
80
+
81
+ def measure_accept(trace)
82
+ @buffer_spans += trace.length
83
+ @buffer_accepted += 1
84
+ @buffer_accepted_lengths += trace.length
85
+ rescue StandardError => e
86
+ Datadog::Tracer.log.debug("Failed to measure queue accept. Cause: #{e.message} Source: #{e.backtrace.first}")
87
+ end
88
+
89
+ def measure_drop(trace)
90
+ @buffer_dropped += 1
91
+ @buffer_spans -= trace.length
92
+ @buffer_accepted_lengths -= trace.length
93
+ rescue StandardError => e
94
+ Datadog::Tracer.log.debug("Failed to measure queue drop. Cause: #{e.message} Source: #{e.backtrace.first}")
95
+ end
96
+
97
+ def measure_pop(traces)
98
+ # Accepted
99
+ Diagnostics::Health.metrics.queue_accepted(@buffer_accepted)
100
+ Diagnostics::Health.metrics.queue_accepted_lengths(@buffer_accepted_lengths)
101
+
102
+ # Dropped
103
+ Diagnostics::Health.metrics.queue_dropped(@buffer_dropped)
104
+
105
+ # Queue gauges
106
+ Diagnostics::Health.metrics.queue_max_length(@max_size)
107
+ Diagnostics::Health.metrics.queue_spans(@buffer_spans)
108
+ Diagnostics::Health.metrics.queue_length(traces.length)
109
+
110
+ # Reset aggregated metrics
111
+ @buffer_accepted = 0
112
+ @buffer_accepted_lengths = 0
113
+ @buffer_dropped = 0
114
+ @buffer_spans = 0
115
+ rescue StandardError => e
116
+ Datadog::Tracer.log.debug("Failed to measure queue. Cause: #{e.message} Source: #{e.backtrace.first}")
117
+ end
59
118
  end
60
119
  end
@@ -0,0 +1,82 @@
1
+ require 'ddtrace/environment'
2
+ require 'ddtrace/configuration/options'
3
+
4
+ module Datadog
5
+ module Configuration
6
+ # Basic configuration behavior
7
+ module Base
8
+ def self.included(base)
9
+ base.send(:extend, Datadog::Environment::Helpers)
10
+ base.send(:include, Options)
11
+
12
+ base.send(:extend, ClassMethods)
13
+ base.send(:include, InstanceMethods)
14
+ end
15
+
16
+ # Class methods for configuration
17
+ module ClassMethods
18
+ protected
19
+
20
+ # Allows subgroupings of settings to be defined.
21
+ # e.g. `settings :foo { option :bar }` --> `config.foo.bar`
22
+ def settings(name, &block)
23
+ settings_class = new_settings_class(&block)
24
+
25
+ option(name) do |o|
26
+ o.default settings_class.new
27
+ o.resetter do |value|
28
+ value.reset! if value.respond_to?(:reset!)
29
+ value
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def new_settings_class(&block)
37
+ Class.new { include Datadog::Configuration::Base }.tap do |klass|
38
+ klass.instance_eval(&block) if block_given?
39
+ end
40
+ end
41
+ end
42
+
43
+ # Instance methods for configuration
44
+ module InstanceMethods
45
+ def initialize(options = {})
46
+ configure(options)
47
+ end
48
+
49
+ def configure(opts = {})
50
+ # Sort the options in preference of dependency order first
51
+ ordering = self.class.options.dependency_order
52
+ sorted_opts = opts.sort_by do |name, _value|
53
+ ordering.index(name) || (ordering.length + 1)
54
+ end
55
+
56
+ # Ruby 2.0 doesn't support Array#to_h
57
+ sorted_opts = Hash[*sorted_opts.flatten]
58
+
59
+ # Apply options in sort order
60
+ sorted_opts.each do |name, value|
61
+ if respond_to?("#{name}=")
62
+ send("#{name}=", value)
63
+ elsif option_defined?(name)
64
+ set_option(name, value)
65
+ end
66
+ end
67
+
68
+ # Apply any additional settings from block
69
+ yield(self) if block_given?
70
+ end
71
+
72
+ def to_h
73
+ options_hash
74
+ end
75
+
76
+ def reset!
77
+ reset_options!
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -13,19 +13,42 @@ module Datadog
13
13
  end
14
14
 
15
15
  def set(value)
16
- @value = @context.instance_exec(value, &definition.setter).tap do
16
+ (@value = context_exec(value, &definition.setter)).tap do |v|
17
17
  @is_set = true
18
+ context_exec(v, &definition.on_set) if definition.on_set
18
19
  end
19
20
  end
20
21
 
21
22
  def get
22
- return definition.default_value unless @is_set
23
- @value
23
+ if @is_set
24
+ @value
25
+ elsif definition.delegate_to
26
+ context_eval(&definition.delegate_to)
27
+ else
28
+ set(definition.default_value)
29
+ end
24
30
  end
25
31
 
26
32
  def reset
27
- @is_set = false
28
- @value = nil
33
+ @value = if definition.resetter
34
+ # Don't change @is_set to false; custom resetters are
35
+ # responsible for changing @value back to a good state.
36
+ # Setting @is_set = false would cause a default to be applied.
37
+ context_exec(@value, &definition.resetter)
38
+ else
39
+ @is_set = false
40
+ nil
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def context_exec(*args, &block)
47
+ @context.instance_exec(*args, &block)
48
+ end
49
+
50
+ def context_eval(&block)
51
+ @context.instance_eval(&block)
29
52
  end
30
53
  end
31
54
  end
@@ -1,3 +1,5 @@
1
+ require 'ddtrace/configuration/option'
2
+
1
3
  module Datadog
2
4
  module Configuration
3
5
  # Represents a definition for an integration configuration option
@@ -6,22 +8,120 @@ module Datadog
6
8
 
7
9
  attr_reader \
8
10
  :default,
11
+ :delegate_to,
9
12
  :depends_on,
10
13
  :lazy,
11
14
  :name,
15
+ :on_set,
16
+ :resetter,
12
17
  :setter
13
18
 
14
19
  def initialize(name, meta = {}, &block)
15
20
  @default = meta[:default]
21
+ @delegate_to = meta[:delegate_to]
16
22
  @depends_on = meta[:depends_on] || []
17
23
  @lazy = meta[:lazy] || false
18
24
  @name = name.to_sym
25
+ @on_set = meta[:on_set]
26
+ @resetter = meta[:resetter]
19
27
  @setter = meta[:setter] || block || IDENTITY
20
28
  end
21
29
 
22
30
  def default_value
23
31
  lazy ? @default.call : @default
24
32
  end
33
+
34
+ # Creates a new Option, bound to the context provided.
35
+ def build(context)
36
+ Option.new(self, context)
37
+ end
38
+
39
+ # Acts as DSL for building OptionDefinitions
40
+ class Builder
41
+ attr_reader \
42
+ :helpers
43
+
44
+ def initialize(name, options = {})
45
+ @default = nil
46
+ @delegate_to = nil
47
+ @depends_on = []
48
+ @helpers = {}
49
+ @lazy = false
50
+ @name = name.to_sym
51
+ @on_set = nil
52
+ @resetter = nil
53
+ @setter = OptionDefinition::IDENTITY
54
+
55
+ # If options were supplied, apply them.
56
+ apply_options!(options)
57
+
58
+ # Apply block if given.
59
+ yield(self) if block_given?
60
+ end
61
+
62
+ def depends_on(*values)
63
+ @depends_on = values.flatten
64
+ end
65
+
66
+ def default(value = nil, &block)
67
+ @default = block_given? ? block : value
68
+ end
69
+
70
+ def delegate_to(&block)
71
+ @delegate_to = block
72
+ end
73
+
74
+ def helper(name, *_args, &block)
75
+ @helpers[name] = block
76
+ end
77
+
78
+ # rubocop:disable Style/TrivialAccessors
79
+ # (Rubocop erroneously thinks #lazy == #lazy= )
80
+ def lazy(value = true)
81
+ @lazy = value
82
+ end
83
+
84
+ def on_set(&block)
85
+ @on_set = block
86
+ end
87
+
88
+ def resetter(&block)
89
+ @resetter = block
90
+ end
91
+
92
+ def setter(&block)
93
+ @setter = block
94
+ end
95
+
96
+ # For applying options for OptionDefinition
97
+ def apply_options!(options = {})
98
+ return if options.nil? || options.empty?
99
+
100
+ default(options[:default]) if options.key?(:default)
101
+ delegate_to(&options[:delegate_to]) if options.key?(:delegate_to)
102
+ depends_on(*options[:depends_on]) if options.key?(:depends_on)
103
+ lazy(options[:lazy]) if options.key?(:lazy)
104
+ on_set(&options[:on_set]) if options.key?(:on_set)
105
+ resetter(&options[:resetter]) if options.key?(:resetter)
106
+ setter(&options[:setter]) if options.key?(:setter)
107
+ end
108
+
109
+ def to_definition
110
+ OptionDefinition.new(@name, meta)
111
+ end
112
+
113
+ def meta
114
+ {
115
+ default: @default,
116
+ delegate_to: @delegate_to,
117
+ depends_on: @depends_on,
118
+ lazy: @lazy,
119
+ on_set: @on_set,
120
+ resetter: @resetter,
121
+ setter: @setter
122
+ }
123
+ end
124
+ end
25
125
  end
26
126
  end
27
127
  end
@@ -1,4 +1,3 @@
1
- require 'ddtrace/configuration/option'
2
1
  require 'ddtrace/configuration/option_set'
3
2
  require 'ddtrace/configuration/option_definition'
4
3
  require 'ddtrace/configuration/option_definition_set'
@@ -24,22 +23,33 @@ module Datadog
24
23
  protected
25
24
 
26
25
  def option(name, meta = {}, &block)
27
- options[name] = OptionDefinition.new(name, meta, &block).tap do
28
- define_option_accessors(name)
26
+ builder = OptionDefinition::Builder.new(name, meta, &block)
27
+ options[name] = builder.to_definition.tap do
28
+ # Resolve and define helper functions
29
+ helpers = default_helpers(name).merge(builder.helpers)
30
+ define_helpers(helpers)
29
31
  end
30
32
  end
31
33
 
32
34
  private
33
35
 
34
- def define_option_accessors(name)
35
- option_name = name
36
-
37
- define_method(option_name) do
38
- get_option(option_name)
39
- end
36
+ def default_helpers(name)
37
+ option_name = name.to_sym
38
+
39
+ {
40
+ option_name.to_sym => proc do
41
+ get_option(option_name)
42
+ end,
43
+ "#{option_name}=".to_sym => proc do |value|
44
+ set_option(option_name, value)
45
+ end
46
+ }
47
+ end
40
48
 
41
- define_method("#{option_name}=") do |value|
42
- set_option(option_name, value)
49
+ def define_helpers(helpers)
50
+ helpers.each do |name, block|
51
+ next unless block.is_a?(Proc)
52
+ define_method(name, &block)
43
53
  end
44
54
  end
45
55
  end
@@ -60,7 +70,11 @@ module Datadog
60
70
  options[name].get
61
71
  end
62
72
 
63
- def to_h
73
+ def option_defined?(name)
74
+ self.class.options.key?(name)
75
+ end
76
+
77
+ def options_hash
64
78
  options.each_with_object({}) do |(key, _), hash|
65
79
  hash[key] = get_option(key)
66
80
  end
@@ -75,13 +89,13 @@ module Datadog
75
89
  def add_option(name)
76
90
  assert_valid_option!(name)
77
91
  definition = self.class.options[name]
78
- Option.new(definition, self).tap do |option|
92
+ definition.build(self).tap do |option|
79
93
  options[name] = option
80
94
  end
81
95
  end
82
96
 
83
97
  def assert_valid_option!(name)
84
- unless self.class.options.key?(name)
98
+ unless option_defined?(name)
85
99
  raise(InvalidOptionError, "#{self.class.name} doesn't define the option: #{name}")
86
100
  end
87
101
  end