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

Populate env, service, and version from tags #1008

Merged
merged 3 commits into from
Apr 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -1603,9 +1603,11 @@ By default, the trace agent (not this library, but the program running in the ba
You can configure the application to automatically tag your traces and metrics, using the following environment variables:

- `DD_ENV`: Your application environment (e.g. `production`, `staging`, etc.)
- `DD_SERVICE`: Your application's default service name (e.g. `billing-api`)
- `DD_VERSION`: Your application version (e.g. `2.5`, `202003181415`, `1.3-alpha`, etc.)
- `DD_TAGS`: Custom tags in value pairs separated by `,` (e.g. `layer:api,team:intake`)
- If `DD_ENV` or `DD_VERSION`, it will override any `env` or `version` tag defined in `DD_TAGS`.
- If `DD_ENV`, `DD_SERVICE` or `DD_VERSION` are set, it will override any respective `env`/`service`/`version` tag defined in `DD_TAGS`.
- If `DD_ENV`, `DD_SERVICE` or `DD_VERSION` are NOT set, tags defined in `DD_TAGS` will be used to populate `env`/`service`/`version` respectively.

These values can also be overridden at the tracer level:

Expand All @@ -1618,9 +1620,9 @@ Datadog.configure do |c|
end
```

This enables you to set this value on a per tracer basis, so you can have for example several applications reporting for different environments on the same host.
This enables you to set this value on a per application basis, so you can have for example several applications reporting for different environments on the same host.

Ultimately, tags can be set per span, but `env` should typically be the same for all spans belonging to a given trace.
Tags can also be set directly on individual spans, which will supersede any conflicting tags defined at the application level.

### Sampling

Expand Down Expand Up @@ -1910,6 +1912,7 @@ Datadog.tracer.trace('correlation.example') do
correlation.trace_id # => 5963550561812073440
correlation.span_id # => 2232727802607726424
correlation.env # => 'production' (derived from DD_ENV)
correlation.service # => 'billing-api' (derived from DD_SERVICE)
correlation.version # => '2.5.17' (derived from DD_VERSION)
end

Expand All @@ -1919,8 +1922,9 @@ correlation = Datadog.tracer.active_correlation
correlation = Datadog.tracer.active_correlation
correlation.trace_id # => 0
correlation.span_id # => 0
correlation.trace_id # => nil
correlation.span_id # => nil
correlation.env # => 'production' (derived from DD_ENV)
correlation.service # => 'billing-api' (derived from DD_SERVICE)
correlation.version # => '2.5.17' (derived from DD_VERSION)
```

#### For logging in Rails applications using Lograge (recommended)
Expand All @@ -1939,6 +1943,7 @@ config.lograge.custom_options = lambda do |event|
:trace_id => correlation.trace_id.to_s,
:span_id => correlation.span_id.to_s,
:env => correlation.env.to_s,
:service => correlation.service.to_s,
:version => correlation.version.to_s
},
:ddsource => ["ruby"],
Expand All @@ -1960,27 +1965,29 @@ end

# Given:
# DD_ENV = 'production' (The name of the environment your application is running in.)
# DD_SERVICE = 'billing-api' (Default service name of your application.)
# DD_VERSION = '2.5.17' (The version of your application.)

# Web requests will produce:
# [dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206 dd.env=production dd.version=2.5.17] Started GET "/articles" for 172.22.0.1 at 2019-01-16 18:50:57 +0000
# [dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206 dd.env=production dd.version=2.5.17] Processing by ArticlesController#index as */*
# [dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206 dd.env=production dd.version=2.5.17] Article Load (0.5ms) SELECT "articles".* FROM "articles"
# [dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206 dd.env=production dd.version=2.5.17] Completed 200 OK in 7ms (Views: 5.5ms | ActiveRecord: 0.5ms)
# [dd.env=production dd.service=billing-api dd.version=2.5.17 dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206] Started GET "/articles" for 172.22.0.1 at 2019-01-16 18:50:57 +0000
# [dd.env=production dd.service=billing-api dd.version=2.5.17 dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206] Processing by ArticlesController#index as */*
# [dd.env=production dd.service=billing-api dd.version=2.5.17 dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206] Article Load (0.5ms) SELECT "articles".* FROM "articles"
# [dd.env=production dd.service=billing-api dd.version=2.5.17 dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206] Completed 200 OK in 7ms (Views: 5.5ms | ActiveRecord: 0.5ms)
```

#### For logging in Ruby applications

To add correlation IDs to your logger, add a log formatter which retrieves the correlation IDs with `Datadog.tracer.active_correlation`, then add them to the message.

To properly correlate with Datadog logging, be sure the following is present in the log message:
To properly correlate with Datadog logging, be sure the following is present in the log message, in order as they appear:

- `dd.env=<ENV>`: Where `<ENV>` is equal to `Datadog.tracer.active_correlation.env`. Omit if no environment is configured.
- `dd.service=<SERVICE>`: Where `<SERVICE>` is equal to `Datadog.tracer.active_correlation.service`. Omit if no default service name is configured.
- `dd.version=<VERSION>`: Where `<VERSION>` is equal to `Datadog.tracer.active_correlation.version`. Omit if no application version is configured.
- `dd.trace_id=<TRACE_ID>`: Where `<TRACE_ID>` is equal to `Datadog.tracer.active_correlation.trace_id` or `0` if no trace is active during logging.
- `dd.span_id=<SPAN_ID>`: Where `<SPAN_ID>` is equal to `Datadog.tracer.active_correlation.span_id` or `0` if no trace is active during logging.
- `dd.env=<ENV>`: Where `<ENV>` is equal to `Datadog.tracer.active_correlation.env` or empty string (no quotes) if no environment name is configured.
- `dd.version=<SPAN_ID>`: Where `<SPAN_ID>` is equal to `Datadog.tracer.active_correlation.version` or empty string (no quotes) if no application version is configured.

By default, `Datadog::Correlation::Identifier#to_s` will return `dd.trace_id=<TRACE_ID> dd.span_id=<SPAN_ID> dd.env=<ENV> dd.version=<VERSION>`.
By default, `Datadog::Correlation::Identifier#to_s` will return `dd.env=<ENV> dd.service=<SERVICE> dd.version=<VERSION> dd.trace_id=<TRACE_ID> dd.span_id=<SPAN_ID>`.

If a trace is not active and the application environment & version is not configured, it will return `dd.trace_id=0 dd.span_id=0 dd.env= dd.version=`.

Expand All @@ -1991,6 +1998,7 @@ require 'ddtrace'
require 'logger'

ENV['DD_ENV'] = 'production'
ENV['DD_SERVICE'] = 'billing-api'
ENV['DD_VERSION'] = '2.5.17'

logger = Logger.new(STDOUT)
Expand All @@ -2001,11 +2009,11 @@ end

# When no trace is active
logger.warn('This is an untraced operation.')
# [2019-01-16 18:38:41 +0000][my_app][WARN][dd.trace_id=0 dd.span_id=0 dd.env=production dd.version=2.5.17] This is an untraced operation.
# [2019-01-16 18:38:41 +0000][my_app][WARN][dd.env=production dd.service=billing-api dd.version=2.5.17 dd.trace_id=0 dd.span_id=0] This is an untraced operation.

# When a trace is active
Datadog.tracer.trace('my.operation') { logger.warn('This is a traced operation.') }
# [2019-01-16 18:38:41 +0000][my_app][WARN][dd.trace_id=8545847825299552251 dd.span_id=3711755234730770098 dd.env=production dd.version=2.5.17] This is a traced operation.
# [2019-01-16 18:38:41 +0000][my_app][WARN][dd.env=production dd.service=billing-api dd.version=2.5.17 dd.trace_id=8545847825299552251 dd.span_id=3711755234730770098] This is a traced operation.
```

### Configuring the transport layer
Expand Down
13 changes: 13 additions & 0 deletions lib/ddtrace/configuration/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,19 @@ def runtime_metrics(options = nil)
# Coerce keys to strings
string_tags = Hash[new_value.collect { |k, v| [k.to_s, v] }]

# Cross-populate tag values with other settings
if env.nil? && string_tags.key?(Ext::Environment::TAG_ENV)
self.env = string_tags[Ext::Environment::TAG_ENV]
end

if version.nil? && string_tags.key?(Ext::Environment::TAG_VERSION)
self.version = string_tags[Ext::Environment::TAG_VERSION]
end

if service.nil? && string_tags.key?(Ext::Environment::TAG_SERVICE)
self.service = string_tags[Ext::Environment::TAG_SERVICE]
end

# Merge with previous tags
(old_value || {}).merge(string_tags)
end
Expand Down
15 changes: 9 additions & 6 deletions lib/ddtrace/correlation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@ module Datadog
# e.g. Retrieve a correlation to the current trace for logging, etc.
module Correlation
# Struct representing correlation
Identifier = Struct.new(:trace_id, :span_id, :env, :version) do
Identifier = Struct.new(:trace_id, :span_id, :env, :service, :version) do
def initialize(*args)
super
self.trace_id = trace_id || 0
self.span_id = span_id || 0
self.env = env || Datadog.configuration.env
self.service = service || Datadog.configuration.service
self.version = version || Datadog.configuration.version
end

def to_s
str = "#{Ext::Correlation::ATTR_TRACE_ID}=#{trace_id}"
str += " #{Ext::Correlation::ATTR_SPAN_ID}=#{span_id}"
str += " #{Ext::Correlation::ATTR_ENV}=#{env}"
str += " #{Ext::Correlation::ATTR_VERSION}=#{version}"
str
attributes = []
attributes << "#{Ext::Correlation::ATTR_ENV}=#{env}" unless env.nil?
attributes << "#{Ext::Correlation::ATTR_SERVICE}=#{service}" unless service.nil?
attributes << "#{Ext::Correlation::ATTR_VERSION}=#{version}" unless version.nil?
attributes << "#{Ext::Correlation::ATTR_TRACE_ID}=#{trace_id}"
attributes << "#{Ext::Correlation::ATTR_SPAN_ID}=#{span_id}"
attributes.join(' ')
end
end.freeze

Expand Down
1 change: 1 addition & 0 deletions lib/ddtrace/ext/correlation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Datadog
module Ext
module Correlation
ATTR_ENV = 'dd.env'.freeze
ATTR_SERVICE = 'dd.service'.freeze
ATTR_SPAN_ID = 'dd.span_id'.freeze
ATTR_TRACE_ID = 'dd.trace_id'.freeze
ATTR_VERSION = 'dd.version'.freeze
Expand Down
1 change: 1 addition & 0 deletions lib/ddtrace/ext/environment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Environment
ENV_VERSION = 'DD_VERSION'.freeze

TAG_ENV = 'env'.freeze
TAG_SERVICE = 'service'.freeze
TAG_VERSION = 'version'.freeze
end
end
Expand Down
36 changes: 36 additions & 0 deletions spec/ddtrace/configuration/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,18 @@
end
end

context 'defines :env with missing #env' do
let(:env_tags) { "env:#{tag_env_value}" }
let(:tag_env_value) { 'tag-env-value' }

it 'populates #env from the tag' do
expect { tags }
.to change { settings.env }
.from(nil)
.to(tag_env_value)
end
end

context 'conflicts with #env' do
let(:env_tags) { "env:#{tag_env_value}" }
let(:tag_env_value) { 'tag-env-value' }
Expand All @@ -554,6 +566,18 @@
it { is_expected.to include('env' => env_value) }
end

context 'defines :service with missing #service' do
let(:env_tags) { "service:#{tag_service_value}" }
let(:tag_service_value) { 'tag-service-value' }

it 'populates #service from the tag' do
expect { tags }
.to change { settings.service }
.from(nil)
.to(tag_service_value)
end
end

context 'conflicts with #version' do
let(:env_tags) { "env:#{tag_version_value}" }
let(:tag_version_value) { 'tag-version-value' }
Expand All @@ -563,6 +587,18 @@

it { is_expected.to include('version' => version_value) }
end

context 'defines :version with missing #version' do
let(:env_tags) { "version:#{tag_version_value}" }
let(:tag_version_value) { 'tag-version-value' }

it 'populates #version from the tag' do
expect { tags }
.to change { settings.version }
.from(nil)
.to(tag_version_value)
end
end
end
end

Expand Down
Loading