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

Update env var conventions and make consistent across language clients #1115

Merged
merged 16 commits into from
Jul 27, 2020

Conversation

ericmustin
Copy link
Contributor

@ericmustin ericmustin commented Jul 23, 2020

This PR updates the conventions of currently existing key environment variables used for configuration the tracer and it's integrations, as well as adds a few new environment variables for key configurability that are supported in some other language clients. The goal of this PR is to standardise the env var's available for configuring the tracer while still supporting older environment variables

New Env Vars

  • DD_TRACE_AGENT_URL : The URL of the Trace Agent that the tracer submits to. Takes priority over hostname (DD_AGENT_HOST) and port (DD_TRACE_AGENT_PORT), if set. currently only supports http/https.

  • DD_TRACE_DEBUG: Enables or disables debug logging.

  • DD_TRACE_<INTEGRATION>_ENABLED: Allows user to ensure instrumentation for a specific integration (eg: DD_TRACE_RAILS_ENABLED) is disabled. the standard across languages is _ENABLED but since it isn't possible to enable solely via env var at the moment, and must be done in code, this could be confusing to users. So adding _DISABLED so users still have the functionality to disable instrumentation for testing or performance purposes. Adding documentation on this restriction.

  • DD_TRACE_ENABLED: Allows user to disable the tracer. The spans are still created but will not be flushed to the agent

Updated Env Vars

  • Migration DD_<INTEGRATION>_ANALYTICS_ENABLED to DD_TRACE_<INTEGRATION>_ANALYTICS_ENABLED: Updates naming convention for enabling/disabled analyzed spans for a specific integration, such as DD_TRACE_RAILS_ANALYTICS_ENABLED. Deprecated DD_<INTEGRATION>_ANALYTICS_ENABLED is still supported.

  • Migration DD_<INTEGRATION>_ANALYTICS_SAMPLE_RATE to DD_TRACE_<INTEGRATION>_ANALYTICS_SAMPLE_RATE: Updates naming convention for enabling/disabled analyzed spans for a specific integration, such as DD_TRACE_RAILS_ANALYTICS_SAMPLE_RATE. Deprecated DD_<INTEGRATION>_ANALYTICS_SAMPLE_RATE is still supported.

Notes
  • should we scrap the DD_TRACE_INTEGRATION_DISABLED since it's off spec or move toDD_TRACE_INTEGRATION_ENABLED to stay on spec(but document that it only can be used to disable instrumentation)? i think it could provide value for users either way. updated to DD_TRACE_INTEGRATION_ENABLED with a note that only false is a valid option.

  • Not all of these env vars are clearly documented in docs, or don't have a clear place to add documentation., such as DD_TRACE_<INTEGRATION>_ANALYTICS_ENABLED, DD_TRACE_AGENT_URL, DD_TRACE_<INTEGRATION>_DISABLED. Not sure why a lot of these existing env vars haven't been documented but if we need to document them now we could add a seperate 'misc env vars` section to the docs maybe? Added to docs

  • In general, would be good to have feedback on the way the new env vars have been implemented. I tried to fit them into the existing conventions we have.

@ericmustin ericmustin requested a review from a team July 23, 2020 14:24
@@ -5,6 +5,7 @@ module ActionPack
module Ext
APP = 'action_pack'.freeze
ENV_ANALYTICS_ENABLED = 'DD_ACTION_PACK_ANALYTICS_ENABLED'.freeze
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
ENV_ANALYTICS_ENABLED = 'DD_ACTION_PACK_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_ENABLED = 'DD_TRACE_ACTION_PACK_ANALYTICS_ENABLED'.freeze

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 updated

@@ -4,7 +4,8 @@ module ActionCable
# ActionCable integration constants
module Ext
APP = 'action_cable'.freeze
ENV_ANALYTICS_ENABLED = 'DD_ACTION_CABLE_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_ENABLED = 'DD_TRACE_ACTION_CABLE_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_ENABLED_OLD = 'DD_ACTION_CABLE_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_SAMPLE_RATE = 'DD_ACTION_CABLE_ANALYTICS_SAMPLE_RATE'.freeze
Copy link
Member

Choose a reason for hiding this comment

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

These need to change as well, DD_TRACE_<INTEGRATION>_ANALYTICS_SAMPLE_RATE, sorry if the spec wasn't clear about that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

gotcha, updated

def integration_disabled?(name)
env_to_bool(
"#{ENV_INTEGRATION_DISABLED_PREFIX}_"\
"#{name.to_s.sub(':', '').upcase}"\
Copy link
Member

Choose a reason for hiding this comment

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

will this always match the same name used in DD_TRACE_<NAME>_ANALYTICS_ENABLED that you set above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup, it's the key being passed into c.use which are all either one word or snake case. I think this is just a convention though and not enforced anywhere afaik, so should probably add a test to prevent a regression at some point.

@@ -6,7 +6,12 @@ module Environment
# Defines helper methods for environment
module Helpers
def env_to_bool(var, default = nil)
ENV.key?(var) ? ENV[var].to_s.strip.downcase == 'true' : default
if var.is_a?(Array)
Copy link
Member

Choose a reason for hiding this comment

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

could do:

var = [var] unless var.is_a?(Array)
env_match = var.find { |env_var| ENV.key?(env_var) }
env_match ? ENV[env_match].to_s.strip.downcase == 'true' : default

or:

if var.is_a?(Array)
  env_match = var.find { |env_var| ENV.key?(env_var) }
else
  env_match = ENV.key?(var)
end

env_match ? ENV[env_match].to_s.strip.downcase == 'true' : default

Either could simplify/DRY this a little bit

Copy link
Member

Choose a reason for hiding this comment

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

(just a suggestion, not a requirement)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated to be a bit dry'er

@@ -2,7 +2,8 @@ module Datadog
module Ext
module Diagnostics
DD_TRACE_STARTUP_LOGS = 'DD_TRACE_STARTUP_LOGS'.freeze

DD_TRACE_DEBUG_LOGS = 'DD_TRACE_DEBUG'.freeze
Copy link
Member

Choose a reason for hiding this comment

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

s/_LOGS//?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

makes sense, updated

ENV.fetch(Datadog::Ext::Transport::HTTP::ENV_DEFAULT_PORT, Datadog::Ext::Transport::HTTP::DEFAULT_PORT).to_i
end

def default_url
Copy link
Member

Choose a reason for hiding this comment

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

what we've done in other languages is use DD_AGENT_HOST and DD_TRACE_AGENT_PORT to build the url, that way once the app loads/is configured, then we only have a url we are working with.

https://github.com/DataDog/dd-trace-py/blob/2dff53f643f71fc4b9f414a5d85961ab130d99a1/ddtrace/tracer.py#L74-L79

Not sure exactly how that translates here, since I am guessing default_hostname/default_port are what are used to create the connection?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think a bit lower down hostname and port get coerced into a url, but it's a bit tricky since we're resolving the priority of host / port in code > url env var > host/port env vars here, before the url gets formed. which is why there's this roundabout "extract the hostname/port from the url being set via env var", to avoid having to re-structure the other parts of transport too much. @marcotc may have a cleaner solution/idea here.

Copy link
Member

Choose a reason for hiding this comment

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

I think this is ok for now, but I agree that supporting only url input is a better way forward.
It requires more changes to the transport that it would be comfortable for this PR, though.

if url_env
uri_parsed = URI.parse(url_env)

uri_parsed if %w[http https].include?(uri_parsed.scheme)
Copy link
Member

Choose a reason for hiding this comment

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

is https honored anywhere? if I set https://127.0.0.1:8106/ will that actually use TLS?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ...don't think so? mainly I just wanted to avoid a malformed url being passed in

else
ENV.key?(var) ? ENV[var].to_s.strip.downcase == 'true' : default
end
var = var.find { |env_var| ENV.key?(env_var) } if var.is_a?(Array)
Copy link
Member

Choose a reason for hiding this comment

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

👍

Copy link
Member

@marcotc marcotc left a comment

Choose a reason for hiding this comment

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

Looks pretty good overall, great stuff!
I left a few suggestions in the review.

docs/GettingStarted.md Outdated Show resolved Hide resolved
docs/GettingStarted.md Outdated Show resolved Hide resolved
docs/GettingStarted.md Outdated Show resolved Hide resolved
docs/GettingStarted.md Outdated Show resolved Hide resolved
@@ -56,7 +58,7 @@ def [](integration_name, configuration_name = :default)
def instrument(integration_name, options = {}, &block)
integration = fetch_integration(integration_name)

unless integration.nil?
unless integration.nil? || !integration_enabled?(integration_name)
Copy link
Member

Choose a reason for hiding this comment

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

I think this can be more cleanly implemented by checking !integration.default_configuration.enabled.
All integrations already have a default_configuration method, but they don't all have enabled defined.

You would define enabled in this shared class: https://github.com/DataDog/dd-trace-rb/blob/master/lib/ddtrace/contrib/configuration/settings.rb
An integration-specific overwrite would still need to be created to support environment variable configuration, like we do for analytics_enabled today.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

makes sense, i went ahead and took this approach and defined enabled in the shared class as well as each Contrib's setting's, and added the relevant Env var constants the respective ext files.

  • One thing is that it required me to modify some of the fixtures in the extensions_spec, and that i added a very small test in the configurable_spec to test the shared class. I found this pretty difficult to easily test at the individual contrib level, and i've punted on it in this PR for now. I think it will take some work done ala the analytics_examples / analytics_spec that abstracts everything out into shared helpers but the scope of that work could take a bit and didn't want it to be a blocker for this PR.

lib/ddtrace/environment.rb Outdated Show resolved Hide resolved
lib/ddtrace/environment.rb Show resolved Hide resolved
ENV.fetch(Datadog::Ext::Transport::HTTP::ENV_DEFAULT_PORT, Datadog::Ext::Transport::HTTP::DEFAULT_PORT).to_i
end

def default_url
Copy link
Member

Choose a reason for hiding this comment

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

I think this is ok for now, but I agree that supporting only url input is a better way forward.
It requires more changes to the transport that it would be comfortable for this PR, though.

@ericmustin ericmustin requested a review from marcotc July 27, 2020 08:41
@ericmustin
Copy link
Contributor Author

@marcotc tried to address all the feedback here, i've re-requested a review when you have time. had one note on testing the env_enabled integration environment variable that I could your opinion on.

@marcotc marcotc dismissed their stale review July 27, 2020 14:20

Requested changes were addressed

Copy link
Member

@marcotc marcotc left a comment

Choose a reason for hiding this comment

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

🔥

@marcotc marcotc added this to Merged & awaiting release in Active work Jul 28, 2020
@marcotc marcotc linked an issue Aug 4, 2020 that may be closed by this pull request
@delner delner moved this from Merged & awaiting release to Released in Active work Apr 15, 2021
@ivoanjo ivoanjo deleted the update_env_var_conventions branch July 16, 2021 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Active work
  
Released
Development

Successfully merging this pull request may close these issues.

gem doesn't honor DISABLE_DATADOG_AGENT env var
3 participants