Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration configuration settings #450

Merged
merged 6 commits into from
Jun 29, 2018

Conversation

delner
Copy link
Contributor

@delner delner commented Jun 11, 2018

In order to encourage more flexible configuration design in our integrations, this pull request introduces a common core for integration configuration settings. This allows us to improve on several things:

Allow the use of block syntax:

Datadog.configure do |c|
  c.use :active_record do |active_record|
    active_record.service_name = 'default-db'
  end
end

Introduce configuration multiplexing

Some integrations must trace multiple endpoints through the same code path, and require additional configuration for each endpoint to do so. Multiplexing allows you to define an arbitrary key that can be associated to specific trace settings, then recalled when needed.

Datadog.configure do |c|
  # Describes tracer settings for a specific context.
  # In this example, these are settings for the 'backup' database.
  c.use :active_record, describes: :backup do |active_record|
    active_record.service_name = 'backup-db'
  end
end

Support for composite configurations

Some integrations activate additional integrations in order to perform tracing. However, those additional integrations are not configurable via the parent integration, and require users to configure them separately.

By implementing object-based configuration with custom methods, it's possible to passthrough configuration settings to underlying integrations without coupling the parent integration to the configuration details of the additional integration.

Rails is a good example of this, which activates rack and active_record by default.

Datadog.configure do |c|
  c.use :rails do |rails|
    rails.service_name = 'my-app'
    
    # Settings for Rack tracing
    rails.rack do |rack|
      rack.headers request: ['Accept-Encoding'], response: ['Content-Encoding']
    end

    # Settings for ActiveRecord tracing
    rails.active_record do |active_record|
      active_record.service_name = 'my-database'
    end
  end
end

Additional remarks

By implementing this configuration core, we also gain additional benefits of DRYing up configuration code, and reducing coupling. These changes are backwards compatible, and can be implemented on an integration-to-integration basis, which would grant us flexibility in their implementation.

See examples of integrations that implement this configuration core here:

@delner delner self-assigned this Jun 11, 2018
@delner delner added core Involves Datadog core libraries feature Involves a product feature labels Jun 11, 2018
@delner delner added the integrations Involves tracing integrations label Jun 11, 2018
@delner delner force-pushed the feature/integration_configuration_settings branch from 887e679 to afe57f3 Compare June 11, 2018 21:47
@palazzem
Copy link
Contributor

@delner quick question before proceeding with the review. The previous Configuration API works exactly as before so no changes are required in users code, right?

@delner
Copy link
Contributor Author

delner commented Jun 12, 2018

@palazzem Yup, its completely backwards compatible with users applications. They should not require any updates to their configurations in order to be compatible.

@delner delner added this to the 0.14.0 milestone Jun 15, 2018
@pawelchcki pawelchcki changed the base branch from 0.13-dev to 0.14-dev June 21, 2018 10:43
Copy link
Contributor

@pawelchcki pawelchcki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small comments.
Other than that it looks really good!

if integration.class <= Datadog::Contrib::Integration
integration.configuration(configuration_name)
else
Proxy.new(integration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

caching of the proxy object would need to be ported back.

But it looks to me like integration.configuration(cfg_name) already avoids temporary object creation 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh, yes, good point. Would save some memory.

module ClassMethods
def register_as(name, options = {})
registry = options.fetch(:registry, Datadog.registry)
auto_patch = options.fetch(:auto_patch, false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autopatch seems to not be used anymore. Is this only for backwards compatibility ? If so I think we can just not support it in the new configuration approach anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backwards compatibility, yeah. I'm not sure whether we can remove this, since there are a lot of users who upgrade from really old versions (< 0.10.0) and leave auto_patch in their configuration. Let me look deeper into this, but this is a great point for consideration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pawelchcki @delner no breaking changes must be introduced that way. If there is a risk to break something at bootstrap time, we need to add a deprecation warning and decide when we're going to remove that field. Probably we can remove most of the things once we're heading to 1.0 release.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@palazzem agreed.

However this shouldn't affect integrations that do not explicitly include new Registerable module. Also the user still would be able to call the same method signature register_as :name, auto_patch: true. Now auto_patch will be ignored a bit earlier.

It doesn't look like breaking change to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@palazzem @palazzem Well, it seems like since we have to deprecate and remove auto_patch from the Registry anyways, why not leave this in for now, and deprecate/remove at the same time when we do it for the registry? Would be just as easy, and consistent.

@delner delner force-pushed the feature/integration_configuration_settings branch from afe57f3 to c412d1c Compare June 25, 2018 18:01
@delner
Copy link
Contributor Author

delner commented Jun 25, 2018

Just looking over this, I realized this needs more test coverage for the new components. I will implement some basic specs, then resubmit this for review.

@delner
Copy link
Contributor Author

delner commented Jun 26, 2018

@pawelchcki @palazzem Added more test coverage; this should be good for another review.

@pawelchcki
Copy link
Contributor

Thanks! @delner looks good!

@delner delner merged commit 878a821 into 0.14-dev Jun 29, 2018
@delner delner deleted the feature/integration_configuration_settings branch August 14, 2018 17:43
@delner delner mentioned this pull request Oct 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Involves Datadog core libraries feature Involves a product feature integrations Involves tracing integrations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants