Skip to content

Commit

Permalink
Add standalone Rails ActiveJob integration
Browse files Browse the repository at this point in the history
  • Loading branch information
bensheldon committed Aug 11, 2021
1 parent bad39d4 commit f16f4b9
Show file tree
Hide file tree
Showing 16 changed files with 550 additions and 47 deletions.
23 changes: 23 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ To contribute, check out the [contribution guidelines][contribution docs] and [d
- [Action View](#action-view)
- [Active Model Serializers](#active-model-serializers)
- [Action Pack](#action-pack)
- [Active Job](#active-job)
- [Active Record](#active-record)
- [Active Support](#active-support)
- [AWS](#aws)
Expand Down Expand Up @@ -391,6 +392,7 @@ For a list of available integrations, and their configuration options, please re
| Action View | `action_view` | `>= 3.0` | `>= 3.0` | *[Link](#action-view)* | *[Link](https://github.com/rails/rails/tree/master/actionview)* |
| Active Model Serializers | `active_model_serializers` | `>= 0.9` | `>= 0.9` | *[Link](#active-model-serializers)* | *[Link](https://github.com/rails-api/active_model_serializers)* |
| Action Pack | `action_pack` | `>= 3.0` | `>= 3.0` | *[Link](#action-pack)* | *[Link](https://github.com/rails/rails/tree/master/actionpack)* |
| Active Job | `active_job` | `>= 4.2` | `>= 4.2` | *[Link](#active-job)* | *[Link](https://github.com/rails/rails/tree/master/activejob)* |
| Active Record | `active_record` | `>= 3.0` | `>= 3.0` | *[Link](#active-record)* | *[Link](https://github.com/rails/rails/tree/master/activerecord)* |
| Active Support | `active_support` | `>= 3.0` | `>= 3.0` | *[Link](#active-support)* | *[Link](https://github.com/rails/rails/tree/master/activesupport)* |
| AWS | `aws` | `>= 2.0` | `>= 2.0` | *[Link](#aws)* | *[Link](https://github.com/aws/aws-sdk-ruby)* |
Expand Down Expand Up @@ -510,6 +512,27 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| ---| --- | --- |
| `service_name` | Service name used for rendering instrumentation. | `action_pack` |

### Active Job

Most of the time, Active Job is set up as part of Rails, but it can be activated separately:

```ruby
require 'activejob'
require 'ddtrace'
Datadog.configure do |c|
c.use :active_job, options
end
ExampleJob.perform_later
```

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

| Key | Description | Default |
| --- | ----------- | ------- |
| `service_name` | Service name used for `active_job` instrumentation | `'active_job'` |

### Active Record

Most of the time, Active Record is set up as part of a web framework (Rails, Sinatra...) however, it can be set up alone:
Expand Down
1 change: 1 addition & 0 deletions lib/datadog/contrib.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module Contrib
require 'ddtrace/contrib/action_pack/integration'
require 'ddtrace/contrib/action_view/integration'
require 'ddtrace/contrib/active_model_serializers/integration'
require 'ddtrace/contrib/active_job/integration'
require 'ddtrace/contrib/active_record/integration'
require 'ddtrace/contrib/active_support/integration'
require 'ddtrace/contrib/aws/integration'
Expand Down
32 changes: 32 additions & 0 deletions lib/ddtrace/contrib/active_job/configuration/settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# typed: false
require 'ddtrace/contrib/configuration/settings'
require 'ddtrace/contrib/active_job/ext'

module Datadog
module Contrib
module ActiveJob
module Configuration
# Custom settings for the DelayedJob integration
class Settings < Contrib::Configuration::Settings
option :enabled do |o|
o.default { env_to_bool(Ext::ENV_ENABLED, true) }
o.lazy
end

option :analytics_enabled do |o|
o.default { env_to_bool([Ext::ENV_ANALYTICS_ENABLED, Ext::ENV_ANALYTICS_ENABLED_OLD], false) }
o.lazy
end

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

option :service_name, default: Ext::SERVICE_NAME
option :error_handler, default: Datadog::Tracer::DEFAULT_ON_ERROR
end
end
end
end
end
31 changes: 31 additions & 0 deletions lib/ddtrace/contrib/active_job/event.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# typed: true
require 'ddtrace/contrib/active_support/notifications/event'

module Datadog
module Contrib
module ActiveJob
# Defines basic behaviors for an ActiveJob event.
module Event
def self.included(base)
base.include(ActiveSupport::Notifications::Event)
base.extend(ClassMethods)
end

# Class methods for ActiveJob events.
module ClassMethods
def span_options
{ service: configuration[:service_name] }
end

def tracer
-> { configuration[:tracer] }
end

def configuration
Datadog.configuration[:active_job]
end
end
end
end
end
end
31 changes: 31 additions & 0 deletions lib/ddtrace/contrib/active_job/events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# typed: false
require 'ddtrace/contrib/active_job/events/enqueue'
require 'ddtrace/contrib/active_job/events/perform'

module Datadog
module Contrib
module ActiveJob
# Defines collection of instrumented ActiveJob events
module Events
ALL = [
Events::Enqueue,
Events::Perform,
].freeze

module_function

def all
self::ALL
end

def subscriptions
all.collect(&:subscriptions).collect(&:to_a).flatten
end

def subscribe!
all.each(&:subscribe!)
end
end
end
end
end
55 changes: 55 additions & 0 deletions lib/ddtrace/contrib/active_job/events/enqueue.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# typed: false
require 'ddtrace/ext/integration'
require 'ddtrace/contrib/analytics'
require 'ddtrace/contrib/active_job/ext'
require 'ddtrace/contrib/active_job/event'

module Datadog
module Contrib
module ActiveJob
module Events
# Defines instrumentation for enqueue.active_job event
module Enqueue
include ActiveJob::Event

EVENT_NAME = 'enqueue.active_job'.freeze

module_function

def event_name
self::EVENT_NAME
end

def span_name
Ext::SPAN_ENQUEUE
end

def process(span, event, _id, payload)
span.name = span_name
span.service = configuration[:service_name]
span.resource = payload[:job].class.name

adapter_name = if payload[:adapter].is_a?(Class)
payload[:adapter].name
else
payload[:adapter].class.name
end
span.set_tag(Ext::TAG_ADAPTER, adapter_name)

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

span.set_tag(Ext::TAG_JOB_ID, payload[:job].job_id)
span.set_tag(Ext::TAG_JOB_QUEUE, payload[:job].queue_name)

span.set_tag(Ext::TAG_JOB_PRIORITY, payload[:job].priority) if payload[:job].respond_to?(:priority)
rescue StandardError => e
Datadog.logger.debug(e.message)
end
end
end
end
end
end
55 changes: 55 additions & 0 deletions lib/ddtrace/contrib/active_job/events/perform.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# typed: false
require 'ddtrace/ext/integration'
require 'ddtrace/contrib/analytics'
require 'ddtrace/contrib/active_job/ext'
require 'ddtrace/contrib/active_job/event'

module Datadog
module Contrib
module ActiveJob
module Events
# Defines instrumentation for perform.active_job event
module Perform
include ActiveJob::Event

EVENT_NAME = 'perform.active_job'.freeze

module_function

def event_name
self::EVENT_NAME
end

def span_name
Ext::SPAN_PERFORM
end

def process(span, event, _id, payload)
span.name = span_name
span.service = configuration[:service_name]
span.resource = payload[:job].class.name

adapter_name = if payload[:adapter].is_a?(Class)
payload[:adapter].name
else
payload[:adapter].class.name
end
span.set_tag(Ext::TAG_ADAPTER, adapter_name)

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

span.set_tag(Ext::TAG_JOB_ID, payload[:job].job_id)
span.set_tag(Ext::TAG_JOB_QUEUE, payload[:job].queue_name)

span.set_tag(Ext::TAG_JOB_PRIORITY, payload[:job].priority) if payload[:job].respond_to?(:priority)
rescue StandardError => e
Datadog.logger.debug(e.message)
end
end
end
end
end
end
25 changes: 25 additions & 0 deletions lib/ddtrace/contrib/active_job/ext.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# typed: true
module Datadog
module Contrib
module ActiveJob
module Ext
APP = 'active_job'.freeze
SERVICE_NAME = 'active_job'.freeze

ENV_ENABLED = 'DD_TRACE_ACTIVE_JOB_ENABLED'.freeze
ENV_ANALYTICS_ENABLED = 'DD_TRACE_ACTIVE_JOB_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_ENABLED_OLD = 'DD_ACTIVE_JOB_ANALYTICS_ENABLED'.freeze
ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_ACTIVE_JOB_ANALYTICS_SAMPLE_RATE'.freeze
ENV_ANALYTICS_SAMPLE_RATE_OLD = 'DD_ACTIVE_JOB_ANALYTICS_SAMPLE_RATE'.freeze

SPAN_PERFORM = 'active_job.perform'.freeze
SPAN_ENQUEUE = 'active_job.enqueue'.freeze

TAG_ADAPTER = 'active_job.adapter'.freeze
TAG_JOB_ID = 'active_job.job.id'.freeze
TAG_JOB_QUEUE = 'active_job.job.queue'.freeze
TAG_JOB_PRIORITY = 'active_job.job.priority'.freeze
end
end
end
end
46 changes: 46 additions & 0 deletions lib/ddtrace/contrib/active_job/integration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# typed: false
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/active_job/configuration/settings'
require 'ddtrace/contrib/active_job/patcher'
require 'ddtrace/contrib/rails/utils'

module Datadog
module Contrib
module ActiveJob
# Describes the ActiveJob integration
class Integration
include Contrib::Integration

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

register_as :active_job, auto_patch: false

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

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

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

# enabled by rails integration so should only auto instrument
# if detected that it is being used without rails
def auto_instrument?
!Datadog::Contrib::Rails::Utils.railtie_supported?
end

def default_configuration
Configuration::Settings.new
end

def patcher
ActiveJob::Patcher
end
end
end
end
end
25 changes: 25 additions & 0 deletions lib/ddtrace/contrib/active_job/patcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# typed: true
require 'ddtrace/contrib/patcher'
require 'ddtrace/contrib/active_job/ext'
require 'ddtrace/contrib/active_job/events'

module Datadog
module Contrib
module ActiveJob
# Patcher enables patching of 'active_job' module.
module Patcher
include Contrib::Patcher

module_function

def target_version
Integration.version
end

def patch
Events.subscribe!
end
end
end
end
end
10 changes: 10 additions & 0 deletions lib/ddtrace/contrib/rails/framework.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def self.setup
activate_active_support!(datadog_config, rails_config)
activate_action_pack!(datadog_config, rails_config)
activate_action_view!(datadog_config, rails_config)
activate_active_job!(datadog_config, rails_config)
activate_active_record!(datadog_config, rails_config)
activate_lograge!(datadog_config, rails_config)
activate_semantic_logger!(datadog_config, rails_config)
Expand Down Expand Up @@ -115,6 +116,15 @@ def self.activate_action_view!(datadog_config, rails_config)
)
end

def self.activate_active_job!(datadog_config, rails_config)
return unless defined?(::ActiveJob)

datadog_config.use(
:active_job,
service_name: "#{rails_config[:service_name]}-#{Contrib::ActiveJob::Ext::SERVICE_NAME}"
)
end

def self.activate_active_record!(datadog_config, rails_config)
return unless defined?(::ActiveRecord)

Expand Down
Loading

0 comments on commit f16f4b9

Please sign in to comment.