ddtrace 0.28.0 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
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