Skip to content

Commit

Permalink
Merge pull request #450 from DataDog/feature/integration_configuratio…
Browse files Browse the repository at this point in the history
…n_settings

Integration configuration settings
  • Loading branch information
delner committed Jun 29, 2018
2 parents a87126e + 2635bf2 commit 878a821
Show file tree
Hide file tree
Showing 31 changed files with 1,171 additions and 10 deletions.
10 changes: 10 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ namespace :spec do
t.pattern = 'spec/ddtrace/contrib/rails/**/*disable_env*_spec.rb'
end

RSpec::Core::RakeTask.new(:contrib) do |t|
t.pattern = 'spec/**/contrib/{configurable,integration,patchable,patcher,registerable,configuration/*}_spec.rb'
end

[
:active_model_serializers,
:active_record,
Expand Down Expand Up @@ -208,6 +212,7 @@ task :ci do
# Main library
sh 'bundle exec rake test:main'
sh 'bundle exec rake spec:main'
sh 'bundle exec rake spec:contrib'

if RUBY_PLATFORM != 'java'
# Contrib minitests
Expand Down Expand Up @@ -249,6 +254,7 @@ task :ci do
# Main library
sh 'bundle exec rake test:main'
sh 'bundle exec rake spec:main'
sh 'bundle exec rake spec:contrib'

if RUBY_PLATFORM != 'java'
# Contrib minitests
Expand Down Expand Up @@ -293,6 +299,7 @@ task :ci do
# Main library
sh 'bundle exec rake test:main'
sh 'bundle exec rake spec:main'
sh 'bundle exec rake spec:contrib'

if RUBY_PLATFORM != 'java'
# Contrib minitests
Expand Down Expand Up @@ -343,6 +350,7 @@ task :ci do
# Main library
sh 'bundle exec rake test:main'
sh 'bundle exec rake spec:main'
sh 'bundle exec rake spec:contrib'

if RUBY_PLATFORM != 'java'
# Contrib minitests
Expand Down Expand Up @@ -404,6 +412,7 @@ task :ci do
# Main library
sh 'bundle exec rake test:main'
sh 'bundle exec rake spec:main'
sh 'bundle exec rake spec:contrib'

if RUBY_PLATFORM != 'java'
# Contrib minitests
Expand Down Expand Up @@ -464,6 +473,7 @@ task :ci do
# Main library
sh 'bundle exec rake test:main'
sh 'bundle exec rake spec:main'
sh 'bundle exec rake spec:contrib'

if RUBY_PLATFORM != 'java'
# Contrib minitests
Expand Down
1 change: 1 addition & 0 deletions lib/ddtrace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def configure(target = configuration, opts = {})
end

require 'ddtrace/contrib/base'
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/rack/patcher'
require 'ddtrace/contrib/rails/patcher'
require 'ddtrace/contrib/active_model_serializers/patcher'
Expand Down
24 changes: 18 additions & 6 deletions lib/ddtrace/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,28 @@ def initialize(options = {})
@wrapped_registry = {}
end

def [](integration_name)
@wrapped_registry[integration_name] ||= Proxy.new(fetch_integration(integration_name))
def [](integration_name, configuration_name = :default)
integration = fetch_integration(integration_name)

if integration.class <= Datadog::Contrib::Integration
integration.configuration(configuration_name)
else
@wrapped_registry[integration_name] ||= Proxy.new(integration)
end
end

def use(integration_name, options = {})
def use(integration_name, options = {}, &block)
integration = fetch_integration(integration_name)
settings = Proxy.new(integration)

integration.sorted_options.each do |name|
settings[name] = options.fetch(name, settings[name])
if integration.class <= Datadog::Contrib::Integration
configuration_name = options[:describes] || :default
filtered_options = options.reject { |k, _v| k == :describes }
integration.configure(configuration_name, filtered_options, &block)
else
settings = Proxy.new(integration)
integration.sorted_options.each do |name|
settings[name] = options.fetch(name, settings[name])
end
end

integration.patch if integration.respond_to?(:patch)
Expand Down
7 changes: 4 additions & 3 deletions lib/ddtrace/contrib/base.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
require 'ddtrace/registry'
require 'ddtrace/configurable'
require 'ddtrace/patcher'
require 'ddtrace/registry/registerable'

module Datadog
module Contrib
# Base provides features that are shared across all integrations
module Base
def self.included(base)
base.send(:include, Registry::Registerable)
base.send(:include, Configurable)
base.send(:include, Patcher)
base.send(:include, Datadog::Configurable)
base.send(:include, Datadog::Patcher)
end
end
end
Expand Down
55 changes: 55 additions & 0 deletions lib/ddtrace/contrib/configurable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require 'ddtrace/contrib/configuration/resolver'
require 'ddtrace/contrib/configuration/settings'

module Datadog
module Contrib
# Defines configurable behavior for integrations
module Configurable
def self.included(base)
base.send(:include, InstanceMethods)
end

# Configurable instance behavior for integrations
module InstanceMethods
def default_configuration
Configuration::Settings.new
end

def reset_configuration!
@configurations = nil
@resolver = nil
end

def configuration(name = :default)
name = :default if name.nil?
name = resolver.resolve(name)
return nil unless configurations.key?(name)
configurations[name]
end

def configurations
@configurations ||= Hash.new { default_configuration }.tap do |configs|
configs[:default] = default_configuration
end
end

def configure(name, options = {}, &block)
name = resolver.resolve(name || :default)

configurations[name].tap do |settings|
settings.configure(options, &block)
configurations[name] = settings
end
end

protected

attr_writer :resolver

def resolver
@resolver ||= Configuration::Resolver.new
end
end
end
end
end
33 changes: 33 additions & 0 deletions lib/ddtrace/contrib/configuration/option.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Datadog
module Contrib
module Configuration
# Represents an instance of an integration configuration option
class Option
attr_reader \
:definition

def initialize(definition, context)
@definition = definition
@context = context
@value = nil
@is_set = false
end

def set(value)
@value = @context.instance_exec(value, &definition.setter).tap do
@is_set = true
end
end

def get
return definition.default_value unless @is_set
@value
end

def reset
set(definition.default_value)
end
end
end
end
end
29 changes: 29 additions & 0 deletions lib/ddtrace/contrib/configuration/option_definition.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Datadog
module Contrib
module Configuration
# Represents a definition for an integration configuration option
class OptionDefinition
IDENTITY = ->(x) { x }

attr_reader \
:default,
:depends_on,
:lazy,
:name,
:setter

def initialize(name, meta = {}, &block)
@default = meta[:default]
@depends_on = meta[:depends_on] || []
@lazy = meta[:lazy] || false
@name = name.to_sym
@setter = meta[:setter] || block || IDENTITY
end

def default_value
lazy ? @default.call : @default
end
end
end
end
end
20 changes: 20 additions & 0 deletions lib/ddtrace/contrib/configuration/option_definition_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'ddtrace/configuration/resolver'

module Datadog
module Contrib
module Configuration
# Represents a set of configuration option definitions for an integration
class OptionDefinitionSet < Hash
def dependency_order
Datadog::Configuration::Resolver.new(dependency_graph).call
end

def dependency_graph
each_with_object({}) do |(name, option), graph|
graph[name] = option.depends_on
end
end
end
end
end
end
8 changes: 8 additions & 0 deletions lib/ddtrace/contrib/configuration/option_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Datadog
module Contrib
module Configuration
class OptionSet < Hash
end
end
end
end
95 changes: 95 additions & 0 deletions lib/ddtrace/contrib/configuration/options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
require 'ddtrace/contrib/configuration/option'
require 'ddtrace/contrib/configuration/option_set'
require 'ddtrace/contrib/configuration/option_definition'
require 'ddtrace/contrib/configuration/option_definition_set'

module Datadog
module Contrib
module Configuration
# Behavior for a configuration object that has options
module Options
def self.included(base)
base.send(:extend, ClassMethods)
base.send(:include, InstanceMethods)
end

# Class behavior for a configuration object with options
module ClassMethods
def options
@options ||= begin
# Allows for class inheritance of option definitions
superclass <= Options ? superclass.options.dup : OptionDefinitionSet.new
end
end

protected

def option(name, meta = {}, &block)
options[name] = OptionDefinition.new(name, meta, &block).tap do
define_option_accessors(name)
end
end

private

def define_option_accessors(name)
option_name = name

define_method(option_name) do
get_option(option_name)
end

define_method("#{option_name}=") do |value|
set_option(option_name, value)
end
end
end

# Instance behavior for a configuration object with options
module InstanceMethods
def options
@options ||= OptionSet.new
end

def set_option(name, value)
add_option(name) unless options.key?(name)
options[name].set(value)
end

def get_option(name)
add_option(name) unless options.key?(name)
options[name].get
end

def to_h
options.each_with_object({}) do |(key, _), hash|
hash[key] = get_option(key)
end
end

def reset_options!
options.values.each(&:reset)
end

private

def add_option(name)
assert_valid_option!(name)
definition = self.class.options[name]
Option.new(definition, self).tap do |option|
options[name] = option
end
end

def assert_valid_option!(name)
unless self.class.options.key?(name)
raise(InvalidOptionError, "#{self.class.name} doesn't define the option: #{name}")
end
end
end

InvalidOptionError = Class.new(StandardError)
end
end
end
end
12 changes: 12 additions & 0 deletions lib/ddtrace/contrib/configuration/resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Datadog
module Contrib
module Configuration
# Resolves a value to a configuration key
class Resolver
def resolve(name)
name
end
end
end
end
end
Loading

0 comments on commit 878a821

Please sign in to comment.