Skip to content

Commit

Permalink
Merge pull request #1237 from sco11morgan/instrument-qless
Browse files Browse the repository at this point in the history
  • Loading branch information
marcotc authored Nov 26, 2020
2 parents 4aa11d6 + 42b8197 commit 82a79f1
Show file tree
Hide file tree
Showing 14 changed files with 564 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ elsif Gem::Version.new('2.2.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'http'
gem 'mongo', '>= 2.8.0'
gem 'mysql2', '< 0.5', platform: :ruby
gem 'qless'
gem 'racecar', '>= 0.3.5'
gem 'rack', '< 2.1.0' # Locked due to grape incompatibility: https://github.com/ruby-grape/grape/issues/1980
gem 'rack-test'
Expand Down Expand Up @@ -584,6 +585,7 @@ elsif Gem::Version.new('2.3.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'mysql2', '< 0.5', platform: :ruby
gem 'pg', platform: :ruby
gem 'presto-client', '>= 0.5.14'
gem 'qless'
gem 'racecar', '>= 0.3.5'
gem 'rack', '< 2.1.0' # Locked due to grape incompatibility: https://github.com/ruby-grape/grape/issues/1980
gem 'rack-test'
Expand Down Expand Up @@ -687,6 +689,7 @@ elsif Gem::Version.new('2.4.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'mysql2', '< 0.5', platform: :ruby
gem 'pg', platform: :ruby
gem 'presto-client', '>= 0.5.14'
gem 'qless'
gem 'racecar', '>= 0.3.5'
gem 'rack'
gem 'rack-test'
Expand Down Expand Up @@ -839,6 +842,7 @@ elsif Gem::Version.new('2.5.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'pg', platform: :ruby
gem 'activerecord-jdbcpostgresql-adapter', platform: :jruby
gem 'presto-client', '>= 0.5.14'
gem 'qless'
gem 'racecar', '>= 0.3.5'
gem 'rack'
gem 'rack-test'
Expand Down Expand Up @@ -979,6 +983,7 @@ elsif Gem::Version.new('2.6.0') <= Gem::Version.new(RUBY_VERSION) \
gem 'mysql2', '< 0.5', platform: :ruby
gem 'pg', platform: :ruby
gem 'presto-client', '>= 0.5.14'
gem 'qless'
gem 'racecar', '>= 0.3.5'
gem 'rack'
gem 'rack-test'
Expand Down Expand Up @@ -1122,6 +1127,7 @@ elsif Gem::Version.new('2.7.0') <= Gem::Version.new(RUBY_VERSION)
gem 'mysql2', '< 0.5', platform: :ruby
gem 'pg', platform: :ruby
gem 'presto-client', '>= 0.5.14'
gem 'qless'
gem 'racecar', '>= 0.3.5'
gem 'rack'
gem 'rack-test'
Expand Down
7 changes: 7 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ namespace :spec do
:mongodb,
:mysql2,
:presto,
:qless,
:que,
:racecar,
:rack,
Expand Down Expand Up @@ -355,6 +356,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:mongodb'
declare 'bundle exec appraisal contrib rake spec:mysql2'
declare 'bundle exec appraisal contrib rake spec:presto'
declare 'bundle exec appraisal contrib rake spec:qless'
declare 'bundle exec appraisal contrib rake spec:que'
declare 'bundle exec appraisal contrib rake spec:racecar'
declare 'bundle exec appraisal contrib rake spec:rack'
Expand Down Expand Up @@ -582,6 +584,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:mongodb'
declare 'bundle exec appraisal contrib rake spec:mysql2' if RUBY_PLATFORM != 'java' # built-in jdbc is used instead
declare 'bundle exec appraisal contrib rake spec:presto'
declare 'bundle exec appraisal contrib rake spec:qless'
declare 'bundle exec appraisal contrib rake spec:que'
declare 'bundle exec appraisal contrib rake spec:racecar'
declare 'bundle exec appraisal contrib rake spec:rack'
Expand Down Expand Up @@ -664,6 +667,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:mongodb'
declare 'bundle exec appraisal contrib rake spec:mysql2'
declare 'bundle exec appraisal contrib rake spec:presto'
declare 'bundle exec appraisal contrib rake spec:qless'
declare 'bundle exec appraisal contrib rake spec:que'
declare 'bundle exec appraisal contrib rake spec:racecar'
declare 'bundle exec appraisal contrib rake spec:rack'
Expand All @@ -679,6 +683,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:sneakers'
declare 'bundle exec appraisal contrib rake spec:sucker_punch'
declare 'bundle exec appraisal contrib rake spec:suite'

# Contrib specs with old gem versions
declare 'bundle exec appraisal contrib-old rake spec:faraday'
# Rails minitests
Expand Down Expand Up @@ -746,6 +751,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:mongodb'
declare 'bundle exec appraisal contrib rake spec:mysql2'
declare 'bundle exec appraisal contrib rake spec:presto'
declare 'bundle exec appraisal contrib rake spec:qless'
declare 'bundle exec appraisal contrib rake spec:que'
declare 'bundle exec appraisal contrib rake spec:racecar'
declare 'bundle exec appraisal contrib rake spec:rack'
Expand All @@ -761,6 +767,7 @@ task :ci do
declare 'bundle exec appraisal contrib rake spec:sneakers'
declare 'bundle exec appraisal contrib rake spec:sucker_punch'
declare 'bundle exec appraisal contrib rake spec:suite'

# Contrib specs with old gem versions
declare 'bundle exec appraisal contrib-old rake spec:faraday'
# Rails minitests
Expand Down
25 changes: 25 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ To contribute, check out the [contribution guidelines][contribution docs] and [d
- [MySQL2](#mysql2)
- [Net/HTTP](#net-http)
- [Presto](#presto)
- [Qless](#qless)
- [Que](#que)
- [Racecar](#racecar)
- [Rack](#rack)
Expand Down Expand Up @@ -356,6 +357,7 @@ For a list of available integrations, and their configuration options, please re
| MySQL2 | `mysql2` | `>= 0.3.21` | *gem not available* | *[Link](#mysql2)* | *[Link](https://github.com/brianmario/mysql2)* |
| Net/HTTP | `http` | *(Any supported Ruby)* | *(Any supported Ruby)* | *[Link](#nethttp)* | *[Link](https://ruby-doc.org/stdlib-2.4.0/libdoc/net/http/rdoc/Net/HTTP.html)* |
| Presto | `presto` | `>= 0.5.14` | `>= 0.5.14` | *[Link](#presto)* | *[Link](https://github.com/treasure-data/presto-client-ruby)* |
| Qless | `qless` | `>= 0.10.0` | `>= 0.10.0` | *[Link](#qless)* | *[Link](https://github.com/seomoz/qless)* |
| Que | `que` | `>= 1.0.0.beta2` | `>= 1.0.0.beta2` | *[Link](#que)* | *[Link](https://github.com/que-rb/que)* |
| Racecar | `racecar` | `>= 0.3.5` | `>= 0.3.5` | *[Link](#racecar)* | *[Link](https://github.com/zendesk/racecar)* |
| Rack | `rack` | `>= 1.1` | `>= 1.1` | *[Link](#rack)* | *[Link](https://github.com/rack/rack)* |
Expand Down Expand Up @@ -1155,6 +1157,29 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| `analytics_enabled` | Enable analytics for spans produced by this integration. `true` for on, `nil` to defer to global setting, `false` for off. | `false` |
| `service_name` | Service name used for `presto` instrumentation | `'presto'` |

### Qless

The Qless integration uses lifecycle hooks to trace job executions.

To add tracing to a Qless job:

```ruby
require 'ddtrace'
Datadog.configure do |c|
c.use :qless, options
end
```

Where `options` is an optional `Hash` that accepts the following parameters:

| Key | Description | Default |
| --- | ----------- | ------- |
| `analytics_enabled` | Enable analytics for spans produced by this integration. `true` for on, `nil` to defer to the global setting, `false` for off. | `false` |
| `service_name` | Service name used for `qless` instrumentation | `'qless'` |
| `tag_job_data` | Enable tagging with job arguments. true for on, false for off. | `false` |
| `tag_job_tags` | Enable tagging with job tags. true for on, false for off. | `false` |

### Que

The Que integration is a middleware which will trace job executions.
Expand Down
1 change: 1 addition & 0 deletions lib/ddtrace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ module Datadog
require 'ddtrace/contrib/que/integration'
require 'ddtrace/contrib/mysql2/integration'
require 'ddtrace/contrib/mongodb/integration'
require 'ddtrace/contrib/qless/integration'
require 'ddtrace/contrib/racecar/integration'
require 'ddtrace/contrib/rack/integration'
require 'ddtrace/contrib/rails/integration'
Expand Down
35 changes: 35 additions & 0 deletions lib/ddtrace/contrib/qless/configuration/settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'ddtrace/contrib/configuration/settings'
require 'ddtrace/contrib/qless/ext'

module Datadog
module Contrib
module Qless
module Configuration
# Custom settings for the Qless integration
class Settings < Contrib::Configuration::Settings
option :analytics_enabled do |o|
o.default { env_to_bool(Ext::ENV_ANALYTICS_ENABLED, false) }
o.lazy
end

option :analytics_sample_rate do |o|
o.default { env_to_float(Ext::ENV_ANALYTICS_SAMPLE_RATE, 1.0) }
o.lazy
end

option :tag_job_data do |o|
o.default { env_to_bool(Ext::ENV_TAG_JOB_DATA, false) }
o.lazy
end

option :tag_job_tags do |o|
o.default { env_to_bool(Ext::ENV_TAG_JOB_TAGS, false) }
o.lazy
end

option :service_name, default: Ext::SERVICE_NAME
end
end
end
end
end
20 changes: 20 additions & 0 deletions lib/ddtrace/contrib/qless/ext.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Datadog
module Contrib
module Qless
# Qless integration constants
module Ext
APP = 'qless'.freeze
ENV_ANALYTICS_ENABLED = 'DD_QLESS_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_SAMPLE_RATE = 'DD_QLESS_ANALYTICS_SAMPLE_RATE'.freeze
ENV_TAG_JOB_DATA = 'DD_QLESS_TAG_JOB_DATA'.freeze
ENV_TAG_JOB_TAGS = 'DD_QLESS_TAG_JOB_TAGS'.freeze
SERVICE_NAME = 'qless'.freeze
SPAN_JOB = 'qless.job'.freeze
TAG_JOB_ID = 'qless.job.id'.freeze
TAG_JOB_DATA = 'qless.job.data'.freeze
TAG_JOB_QUEUE = 'qless.job.queue'.freeze
TAG_JOB_TAGS = 'qless.job.tags'.freeze
end
end
end
end
38 changes: 38 additions & 0 deletions lib/ddtrace/contrib/qless/integration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/qless/configuration/settings'
require 'ddtrace/contrib/qless/patcher'

module Datadog
module Contrib
module Qless
# Description of Qless integration
class Integration
include Contrib::Integration

MINIMUM_VERSION = Gem::Version.new('0.10.0')

register_as :qless, auto_patch: true

def self.version
Gem.loaded_specs['qless'] && Gem.loaded_specs['qless'].version
end

def self.loaded?
!defined?(::Qless).nil?
end

def self.compatible?
super && version >= MINIMUM_VERSION
end

def default_configuration
Configuration::Settings.new
end

def patcher
Patcher
end
end
end
end
end
35 changes: 35 additions & 0 deletions lib/ddtrace/contrib/qless/patcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'ddtrace/contrib/patcher'
require 'ddtrace/ext/app_types'

module Datadog
module Contrib
module Qless
# Patcher enables patching of 'qless' module.
module Patcher
include Contrib::Patcher

module_function

def target_version
Integration.version
end

def patch
require_relative 'qless_job'
require_relative 'tracer_cleaner'

# Instrument all Qless Workers
::Qless::Workers::BaseWorker.class_eval do
# These are executed in inverse order of listing here
include QlessJob
include TracerCleaner
end
end

def get_option(option)
Datadog.configuration[:qless].get_option(option)
end
end
end
end
end
72 changes: 72 additions & 0 deletions lib/ddtrace/contrib/qless/qless_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
require 'ddtrace/ext/app_types'
require 'ddtrace/contrib/analytics'
require 'qless'

module Datadog
module Contrib
module Qless
# Uses Qless job hooks to create traces
module QlessJob
def around_perform(job)
return super unless datadog_configuration && tracer
tracer.trace(Ext::SPAN_JOB, span_options) do |span|
span.resource = job.klass_name
span.span_type = Datadog::Ext::AppTypes::WORKER
span.set_tag(Ext::TAG_JOB_ID, job.jid)
span.set_tag(Ext::TAG_JOB_QUEUE, job.queue_name)

tag_job_tags = datadog_configuration[:tag_job_tags]
span.set_tag(Ext::TAG_JOB_TAGS, job.tags) if tag_job_tags

tag_job_data = datadog_configuration[:tag_job_data]
if tag_job_data && !job.data.empty?
job_data = job.data.with_indifferent_access
formatted_data = job_data.except(:tags).map do |key, value|
"#{key}:#{value}".underscore
end

span.set_tag(Ext::TAG_JOB_DATA, formatted_data)
end

# Set analytics sample rate
if Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
Contrib::Analytics.set_sample_rate(span, datadog_configuration[:analytics_sample_rate])
end

# Measure service stats
Contrib::Analytics.set_measured(span)

super
end
end

def after_fork
configuration = Datadog.configuration[:qless]
return if configuration.nil?

# Add a pin, marking the job as forked.
# Used to trigger shutdown in forks for performance reasons.
# Cleanup happens in the TracerCleaner class
Datadog::Pin.new(
configuration[:service_name],
config: { forked: true }
).onto(::Qless)
end

private

def span_options
{ service: datadog_configuration[:service_name] }
end

def tracer
datadog_configuration.tracer
end

def datadog_configuration
Datadog.configuration[:qless]
end
end
end
end
end
32 changes: 32 additions & 0 deletions lib/ddtrace/contrib/qless/tracer_cleaner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module Datadog
module Contrib
module Qless
# Shutdown Tracer in forks for performance reasons
module TracerCleaner
def around_perform(job)
return super unless datadog_configuration && tracer

super.tap do
tracer.shutdown! if forked?
end
end

private

def forked?
pin = Datadog::Pin.get_from(::Qless)
return false unless pin
pin.config[:forked] == true
end

def tracer
datadog_configuration.tracer
end

def datadog_configuration
Datadog.configuration[:qless]
end
end
end
end
end
Loading

0 comments on commit 82a79f1

Please sign in to comment.