Skip to content

Commit

Permalink
Merge pull request #680 from DataDog/0.19-dev
Browse files Browse the repository at this point in the history
0.19.0 to stable
  • Loading branch information
delner authored Jan 22, 2019
2 parents 0a12fb3 + c0478a5 commit e3f2c70
Show file tree
Hide file tree
Showing 72 changed files with 767 additions and 315 deletions.
20 changes: 18 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@

## [Unreleased (beta)]

## [0.19.0] - 2019-01-22

Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.19.0

Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.18.3...v0.19.0

### Added

- Tracer#active_correlation for adding correlation IDs to logs. (#660, #664, #673)
- Opt-in support for `event_sample_rate` tag for some integrations. (#665, #666)

### Changed

- Priority sampling enabled by default. (#654)

## [0.18.3] - 2019-01-17

Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.18.3
Expand Down Expand Up @@ -627,8 +642,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1

Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1

[Unreleased (stable)]: https://github.com/DataDog/dd-trace-rb/compare/v0.18.3...master
[Unreleased (beta)]: https://github.com/DataDog/dd-trace-rb/compare/v0.18.3...0.19-dev
[Unreleased (stable)]: https://github.com/DataDog/dd-trace-rb/compare/v0.19.0...master
[Unreleased (beta)]: https://github.com/DataDog/dd-trace-rb/compare/v0.19.0...0.20-dev
[0.19.0]: https://github.com/DataDog/dd-trace-rb/compare/v0.18.3...v0.19.0
[0.18.3]: https://github.com/DataDog/dd-trace-rb/compare/v0.18.2...v0.18.3
[0.18.2]: https://github.com/DataDog/dd-trace-rb/compare/v0.18.1...v0.18.2
[0.18.1]: https://github.com/DataDog/dd-trace-rb/compare/v0.18.0...v0.18.1
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ namespace :spec do
end

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

[
Expand Down
90 changes: 81 additions & 9 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ For descriptions of terminology used in APM, take a look at the [official docume
- [Processing pipeline](#processing-pipeline)
- [Filtering](#filtering)
- [Processing](#processing)
- [Trace correlation](#trace-correlation)
- [OpenTracing](#opentracing)

## Compatibility
Expand Down Expand Up @@ -517,6 +518,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:

| Key | Description | Default |
| --- | ----------- | ------- |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `service_name` | Service name used for `DelayedJob` instrumentation | `'delayed_job'` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |
Expand Down Expand Up @@ -865,6 +867,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| Key | Description | Default |
| --- | ----------- | ------- |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `service_name` | Service name used for `racecar` instrumentation | `'racecar'` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |

Expand Down Expand Up @@ -897,6 +900,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| --- | ----------- | ------- |
| `application` | Your Rack application. Required for `middleware_names`. | `nil` |
| `distributed_tracing` | Enables [distributed tracing](#distributed-tracing) so that this service trace is connected with a trace of another service if tracing headers are received | `false` |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `headers` | Hash of HTTP request or response headers to add as tags to the `rack.request`. Accepts `request` and `response` keys with Array values e.g. `['Last-Modified']`. Adds `http.request.headers.*` and `http.response.headers.*` tags respectively. | `{ response: ['Content-Type', 'X-Request-ID'] }` |
| `middleware_names` | Enable this if you want to use the middleware classes as the resource names for `rack` spans. Requires `application` option to use. | `false` |
| `quantize` | Hash containing options for quantization. May include `:query` or `:fragment`. | `{}` |
Expand Down Expand Up @@ -1006,6 +1010,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| Key | Description | Default |
| --- | ----------- | ------- |
| `enabled` | Defines whether Rake tasks should be traced. Useful for temporarily disabling tracing. `true` or `false` | `true` |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `quantize` | Hash containing options for quantization of task arguments. See below for more details and examples. | `{}` |
| `service_name` | Service name used for `rake` instrumentation | `'rake'` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |
Expand Down Expand Up @@ -1107,6 +1112,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| Key | Description | Default |
| --- | ----------- | ------- |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `service_name` | Service name used for `resque` instrumentation | `'resque'` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |
| `workers` | An array including all worker classes you want to trace (eg `[MyJob]`) | `[]` |
Expand Down Expand Up @@ -1198,6 +1204,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:

| Key | Description | Default |
| --- | ----------- | ------- |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `service_name` | Service name used for `shoryuken` instrumentation | `'shoryuken'` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |
Expand All @@ -1220,6 +1227,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| Key | Description | Default |
| --- | ----------- | ------- |
| `client_service_name` | Service name used for client-side `sidekiq` instrumentation | `'sidekiq-client'` |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `service_name` | Service name used for server-side `sidekiq` instrumentation | `'sidekiq'` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |

Expand Down Expand Up @@ -1271,6 +1279,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| Key | Description | Default |
| --- | ----------- | ------- |
| `event_sample_rate` | Rate which spans should be sampled for search and analytics. | `nil` |
| `service_name` | Service name used for `sucker_punch` instrumentation | `'sucker_punch'` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |

Expand Down Expand Up @@ -1356,15 +1365,7 @@ The sampler can set the priority to the following values:
- `Datadog::Ext::Priority::AUTO_REJECT`: the sampler automatically decided to reject the trace.
- `Datadog::Ext::Priority::AUTO_KEEP`: the sampler automatically decided to keep the trace.

For now, priority sampling is disabled by default. Enabling it ensures that your sampled distributed traces will be complete. To enable the priority sampling:

```ruby
Datadog.configure do |c|
c.tracer priority_sampling: true
end
```

Once enabled, the sampler will automatically assign a priority of 0 or 1 to traces, depending on their service and volume.
Priority sampling is enabled by default. Enabling it ensures that your sampled distributed traces will be complete. Once enabled, the sampler will automatically assign a priority of 0 or 1 to traces, depending on their service and volume.

You can also set this priority manually to either drop a non-interesting trace or to keep an important one. For that, set the `context#sampling_priority` to:

Expand Down Expand Up @@ -1613,6 +1614,77 @@ Datadog::Pipeline.before_flush(
)
```

### Trace correlation

In many cases, such as logging, it may be useful to correlate trace IDs to other events or data streams, for easier cross referencing. The tracer can produce a correlation identifier for the currently active trace via `active_correlation`, which can be used to decorate these other data sources.

```ruby
# When a trace is active...
Datadog.tracer.trace('correlation.example') do
# Returns #<Datadog::Correlation::Identifier>
correlation = Datadog.tracer.active_correlation
correlation.trace_id # => 5963550561812073440
correlation.span_id # => 2232727802607726424
end

# When a trace isn't active...
correlation = Datadog.tracer.active_correlation
# Returns #<Datadog::Correlation::Identifier>
correlation = Datadog.tracer.active_correlation
correlation.trace_id # => 0
correlation.span_id # => 0
```

#### 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:

- `dd.trace_id=<TRACE_ID>`: Where `<TRACE_ID>` is equal to `Datadog.tracer.active_correlation.trace_id` or `0` if no trace is active.
- `dd.span_id=<SPAN_ID>`: Where `<SPAN_ID>` is equal to `Datadog.tracer.active_correlation.span_id` or `0` if no trace is active.

By default, `Datadog::Correlation::Identifier#to_s` will return `dd.trace_id=<TRACE_ID> dd.span_id=<SPAN_ID>`.

An example of this in practice:

```ruby
require 'ddtrace'
require 'logger'

logger = Logger.new(STDOUT)
logger.progname = 'my_app'
logger.formatter = proc do |severity, datetime, progname, msg|
"[#{datetime}][#{progname}][#{severity}][#{Datadog.tracer.active_correlation}] #{msg}\n"
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] 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] This is a traced operation.
```

#### For logging in Rails applications

Rails applications which are configured with a `ActiveSupport::TaggedLogging` logger can append correlation IDs as tags to log output. The default Rails logger implements this tagged logging, making it easier to add correlation tags.

In your Rails environment configuration file, add the following:

```ruby
Rails.application.configure do
config.log_tags = [proc { Datadog.tracer.active_correlation.to_s }]
end

# Web requests will produce:
# [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.trace_id=7110975754844687674 dd.span_id=7518426836986654206] Processing by ArticlesController#index as */*
# [dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206] Article Load (0.5ms) SELECT "articles".* FROM "articles"
# [dd.trace_id=7110975754844687674 dd.span_id=7518426836986654206] Completed 200 OK in 7ms (Views: 5.5ms | ActiveRecord: 0.5ms)
```

### OpenTracing

For setting up Datadog with OpenTracing, see out [Quickstart for OpenTracing](#quickstart-for-opentracing) section for details.
Expand Down
1 change: 1 addition & 0 deletions lib/ddtrace/contrib/configuration/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Settings

option :service_name
option :tracer, default: Datadog.tracer
option :event_sample_rate

def initialize(options = {})
configure(options)
Expand Down
2 changes: 2 additions & 0 deletions lib/ddtrace/contrib/delayed_job/plugin.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'delayed/plugin'
require 'ddtrace/contrib/sampling'
require 'ddtrace/contrib/delayed_job/ext'

module Datadog
Expand All @@ -18,6 +19,7 @@ def self.instrument(job, &block)
end

tracer.trace(Ext::SPAN_JOB, service: configuration[:service_name], resource: job_name) do |span|
Contrib::Sampling.set_event_sample_rate(span, configuration[:event_sample_rate])
span.set_tag(Ext::TAG_ID, job.id)
span.set_tag(Ext::TAG_QUEUE, job.queue) if job.queue
span.set_tag(Ext::TAG_PRIORITY, job.priority)
Expand Down
2 changes: 2 additions & 0 deletions lib/ddtrace/contrib/racecar/event.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'ddtrace/contrib/sampling'
require 'ddtrace/contrib/active_support/notifications/event'
require 'ddtrace/contrib/racecar/ext'

Expand Down Expand Up @@ -36,6 +37,7 @@ def process(span, event, _id, payload)
span.service = configuration[:service_name]
span.resource = payload[:consumer_class]

Contrib::Sampling.set_event_sample_rate(span, configuration[:event_sample_rate])
span.set_tag(Ext::TAG_TOPIC, payload[:topic])
span.set_tag(Ext::TAG_CONSUMER, payload[:consumer_class])
span.set_tag(Ext::TAG_PARTITION, payload[:partition])
Expand Down
30 changes: 21 additions & 9 deletions lib/ddtrace/contrib/rack/middlewares.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'ddtrace/ext/app_types'
require 'ddtrace/ext/http'
require 'ddtrace/propagation/http_propagator'
require 'ddtrace/contrib/sampling'
require 'ddtrace/contrib/rack/ext'
require 'ddtrace/contrib/rack/request_queue'

Expand All @@ -25,7 +26,7 @@ def initialize(app)
end

def compute_queue_time(env, tracer)
return unless Datadog.configuration[:rack][:request_queuing]
return unless configuration[:request_queuing]

# parse the request queue time
request_start = Datadog::Contrib::Rack::QueueTime.get_request_start(env)
Expand All @@ -34,25 +35,25 @@ def compute_queue_time(env, tracer)
tracer.trace(
Ext::SPAN_HTTP_SERVER_QUEUE,
start_time: request_start,
service: Datadog.configuration[:rack][:web_service_name]
service: configuration[:web_service_name]
)
end

def call(env)
# retrieve integration settings
tracer = Datadog.configuration[:rack][:tracer]
tracer = configuration[:tracer]

# [experimental] create a root Span to keep track of frontend web servers
# (i.e. Apache, nginx) if the header is properly set
frontend_span = compute_queue_time(env, tracer)

trace_options = {
service: Datadog.configuration[:rack][:service_name],
service: configuration[:service_name],
resource: nil,
span_type: Datadog::Ext::HTTP::TYPE
}

if Datadog.configuration[:rack][:distributed_tracing]
if configuration[:distributed_tracing]
context = HTTPPropagator.extract(env)
tracer.provider.context = context if context.trace_id
end
Expand Down Expand Up @@ -114,7 +115,7 @@ def call(env)
end

def resource_name_for(env, status)
if Datadog.configuration[:rack][:middleware_names] && env['RESPONSE_MIDDLEWARE']
if configuration[:middleware_names] && env['RESPONSE_MIDDLEWARE']
"#{env['RESPONSE_MIDDLEWARE']}##{env['REQUEST_METHOD']}"
else
"#{env['REQUEST_METHOD']} #{status}".strip
Expand All @@ -138,13 +139,19 @@ def set_request_tags!(request_span, env, status, headers, response, original_env
response_headers = parse_response_headers(headers || {})

request_span.resource ||= resource_name_for(env, status)

# Set event sample rate, if available.
Contrib::Sampling.set_event_sample_rate(request_span, configuration[:event_sample_rate])

if request_span.get_tag(Datadog::Ext::HTTP::METHOD).nil?
request_span.set_tag(Datadog::Ext::HTTP::METHOD, env['REQUEST_METHOD'])
end

if request_span.get_tag(Datadog::Ext::HTTP::URL).nil?
options = Datadog.configuration[:rack][:quantize]
options = configuration[:quantize]
request_span.set_tag(Datadog::Ext::HTTP::URL, Datadog::Quantization::HTTP.url(url, options))
end

if request_span.get_tag(Datadog::Ext::HTTP::BASE_URL).nil?
request_obj = ::Rack::Request.new(env)

Expand All @@ -157,6 +164,7 @@ def set_request_tags!(request_span, env, status, headers, response, original_env

request_span.set_tag(Datadog::Ext::HTTP::BASE_URL, base_url)
end

if request_span.get_tag(Datadog::Ext::HTTP::STATUS_CODE).nil? && status
request_span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, status)
end
Expand Down Expand Up @@ -186,6 +194,10 @@ def set_request_tags!(request_span, env, status, headers, response, original_env
If you need the Rack request span, try using `Datadog.tracer.active_span`.
This key will be removed in version 1.0).freeze

def configuration
Datadog.configuration[:rack]
end

def add_deprecation_warnings(env)
env.instance_eval do
unless instance_variable_defined?(:@patched_with_datadog_warnings)
Expand Down Expand Up @@ -225,7 +237,7 @@ def without_datadog_warnings

def parse_request_headers(env)
{}.tap do |result|
whitelist = Datadog.configuration[:rack][:headers][:request] || []
whitelist = configuration[:headers][:request] || []
whitelist.each do |header|
rack_header = header_to_rack_header(header)
if env.key?(rack_header)
Expand All @@ -237,7 +249,7 @@ def parse_request_headers(env)

def parse_response_headers(headers)
{}.tap do |result|
whitelist = Datadog.configuration[:rack][:headers][:response] || []
whitelist = configuration[:headers][:response] || []
whitelist.each do |header|
if headers.key?(header)
result[Datadog::Ext::HTTP::ResponseHeaders.to_tag(header)] = headers[header]
Expand Down
2 changes: 2 additions & 0 deletions lib/ddtrace/contrib/rake/instrumentation.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'ddtrace/contrib/sampling'
require 'ddtrace/contrib/rake/ext'

module Datadog
Expand Down Expand Up @@ -41,6 +42,7 @@ def shutdown_tracer!

def annotate_invoke!(span, args)
span.resource = name
Contrib::Sampling.set_event_sample_rate(span, configuration[:event_sample_rate])
span.set_tag(Ext::TAG_TASK_ARG_NAMES, arg_names)
span.set_tag(Ext::TAG_INVOKE_ARGS, quantize_args(args)) unless args.nil?
rescue StandardError => e
Expand Down
10 changes: 0 additions & 10 deletions lib/ddtrace/contrib/resque/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,13 @@ def patch
do_once(:resque) do
begin
require_relative 'resque_job'
add_pin
get_option(:workers).each { |worker| worker.extend(ResqueJob) }
rescue StandardError => e
Datadog::Tracer.log.error("Unable to apply Resque integration: #{e}")
end
end
end

def add_pin
Pin.new(
get_option(:service_name),
app: Ext::APP,
app_type: Datadog::Ext::AppTypes::WORKER,
tracer: get_option(:tracer)
).onto(::Resque)
end

def get_option(option)
Datadog.configuration[:resque].get_option(option)
end
Expand Down
Loading

0 comments on commit e3f2c70

Please sign in to comment.