Skip to content

Commit

Permalink
Refactored: Rails to use Datadog::Contrib::Integration. (#540)
Browse files Browse the repository at this point in the history
  • Loading branch information
delner committed Sep 21, 2018
1 parent edd3d55 commit 6bc79b4
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 79 deletions.
2 changes: 1 addition & 1 deletion lib/ddtrace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def configure(target = configuration, opts = {})
require 'ddtrace/contrib/mysql2/patcher'
require 'ddtrace/contrib/racecar/patcher'
require 'ddtrace/contrib/rack/patcher'
require 'ddtrace/contrib/rails/patcher'
require 'ddtrace/contrib/rails/integration'
require 'ddtrace/contrib/rake/patcher'
require 'ddtrace/contrib/redis/patcher'
require 'ddtrace/contrib/resque/patcher'
Expand Down
26 changes: 26 additions & 0 deletions lib/ddtrace/contrib/rails/configuration/settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require 'ddtrace/contrib/configuration/settings'

module Datadog
module Contrib
module Rails
module Configuration
# Custom options for Rails configuration
class Settings < Contrib::Configuration::Settings
option :controller_service
option :cache_service
option :database_service, depends_on: [:service_name] do |value|
value.tap do
# Update ActiveRecord service name too
Datadog.configuration[:active_record][:service_name] = value
end
end
option :middleware, default: true
option :middleware_names, default: false
option :distributed_tracing, default: false
option :template_base_path, default: 'views/'
option :exception_controller, default: nil
end
end
end
end
end
39 changes: 39 additions & 0 deletions lib/ddtrace/contrib/rails/integration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/rails/configuration/settings'
require 'ddtrace/contrib/rails/patcher'

module Datadog
module Contrib
module Rails
# Metadata of Rails integration
class Integration
include Contrib::Integration

APP = 'sequel'.freeze

register_as :rails, auto_patch: false

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

def self.present?
defined?(::Rails)
end

def self.compatible?
return false if ENV['DISABLE_DATADOG_RAILS']
super && defined?(::Rails::VERSION) && ::Rails::VERSION::MAJOR.to_i >= 3
end

def default_configuration
Configuration::Settings.new
end

def patcher
Patcher
end
end
end
end
end
119 changes: 56 additions & 63 deletions lib/ddtrace/contrib/rails/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,82 +6,75 @@
module Datadog
module Contrib
module Rails
# Patcher
# Patcher for Rails
module Patcher
include Base
register_as :rails, auto_patch: true
include Contrib::Patcher

option :service_name
option :controller_service
option :cache_service
option :database_service, depends_on: [:service_name] do |value|
value.tap do
# Update ActiveRecord service name too
Datadog.configuration[:active_record][:service_name] = value
end
end
option :middleware, default: true
option :middleware_names, default: false
option :distributed_tracing, default: false
option :template_base_path, default: 'views/'
option :exception_controller, default: nil
option :tracer, default: Datadog.tracer
module_function

@patched = false
def patched?
done?(:rails)
end

class << self
def patch
return @patched if patched? || !compatible?
def patch
do_once(:rails) do
patch_before_intialize
patch_after_intialize
end
rescue => e
Datadog::Tracer.log.error("Unable to apply Rails integration: #{e}")
end

# Add a callback hook to add the trace middleware before the application initializes.
# Otherwise the middleware stack will be frozen.
do_once(:rails_before_initialize_hook) do
::ActiveSupport.on_load(:before_initialize) do
# Sometimes we don't want to activate middleware e.g. OpenTracing, etc.
if Datadog.configuration[:rails][:middleware]
# Add trace middleware
config.middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware)
def patch_before_intialize
::ActiveSupport.on_load(:before_initialize) do
Datadog::Contrib::Rails::Patcher.before_intialize(self)
end
end

# Insert right after Rails exception handling middleware, because if it's before,
# it catches and swallows the error. If it's too far after, custom middleware can find itself
# between, and raise exceptions that don't end up getting tagged on the request properly.
# e.g lost stack trace.
config.middleware.insert_after(
ActionDispatch::ShowExceptions,
Datadog::Contrib::Rails::ExceptionMiddleware
)
end
end
end
def before_intialize(app)
# Middleware must be added before the application is initialized.
# Otherwise the middleware stack will be frozen.
# Sometimes we don't want to activate middleware e.g. OpenTracing, etc.
add_middleware(app) if Datadog.configuration[:rails][:middleware]
end

# Add a callback hook to finish configuring the tracer after the application is initialized.
# We need to wait for some things, like application name, middleware stack, etc.
do_once(:rails_after_initialize_hook) do
::ActiveSupport.on_load(:after_initialize) do
Datadog::Contrib::Rails::Framework.setup
def add_middleware(app)
# Add trace middleware
app.middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware)

# Add instrumentation to Rails components
Datadog::Contrib::Rails::ActionController.instrument
Datadog::Contrib::Rails::ActionView.instrument
Datadog::Contrib::Rails::ActiveSupport.instrument
end
end
# Insert right after Rails exception handling middleware, because if it's before,
# it catches and swallows the error. If it's too far after, custom middleware can find itself
# between, and raise exceptions that don't end up getting tagged on the request properly.
# e.g lost stack trace.
app.middleware.insert_after(
ActionDispatch::ShowExceptions,
Datadog::Contrib::Rails::ExceptionMiddleware
)
end

@patched = true
rescue => e
Datadog::Tracer.log.error("Unable to apply Rails integration: #{e}")
@patched
def patch_after_intialize
::ActiveSupport.on_load(:after_initialize) do
Datadog::Contrib::Rails::Patcher.after_intialize(self)
end
end

def patched?
@patched
end
def after_intialize(app)
# Finish configuring the tracer after the application is initialized.
# We need to wait for some things, like application name, middleware stack, etc.
setup_tracer
instrument_rails
end

def compatible?
return if ENV['DISABLE_DATADOG_RAILS']
# Configure Rails tracing with settings
def setup_tracer
Datadog::Contrib::Rails::Framework.setup
end

defined?(::Rails::VERSION) && ::Rails::VERSION::MAJOR.to_i >= 3
end
# Add instrumentation to Rails components
def instrument_rails
Datadog::Contrib::Rails::ActionController.instrument
Datadog::Contrib::Rails::ActionView.instrument
Datadog::Contrib::Rails::ActiveSupport.instrument
end
end
end
Expand Down
13 changes: 3 additions & 10 deletions lib/ddtrace/contrib/rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,12 @@ module Datadog
# Railtie class initializes
class Railtie < Rails::Railtie
# Add the trace middleware to the application stack
initializer 'datadog.add_middleware' do |app|
app.middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware)
# Insert right after Rails exception handling middleware, because if it's before,
# it catches and swallows the error. If it's too far after, custom middleware can find itself
# between, and raise exceptions that don't end up getting tagged on the request properly (e.g lost stack trace.)
app.middleware.insert_after(ActionDispatch::ShowExceptions, Datadog::Contrib::Rails::ExceptionMiddleware)
initializer 'datadog.before_intialize' do |app|
Datadog::Contrib::Rails::Patcher.before_intialize(app)
end

config.after_initialize do
Datadog::Contrib::Rails::Framework.setup
Datadog::Contrib::Rails::ActionController.instrument
Datadog::Contrib::Rails::ActionView.instrument
Datadog::Contrib::Rails::ActiveSupport.instrument
Datadog::Contrib::Rails::Patcher.after_intialize(app)
end
end
end
2 changes: 1 addition & 1 deletion lib/ddtrace/contrib/redis/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def patch

patch_redis_client
@patched = true
RailsCachePatcher.reload_cache_store if Datadog.registry[:rails].patched?
RailsCachePatcher.reload_cache_store if Datadog.registry[:rails].patcher.patched?
rescue StandardError => e
Datadog::Tracer.log.error("Unable to apply Redis integration: #{e}")
end
Expand Down
1 change: 0 additions & 1 deletion spec/ddtrace/contrib/rails/railtie_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ def index
end

before(:each) do
Datadog.registry[:rails].instance_variable_set(:@patched, false)
Datadog.configure do |c|
c.tracer hostname: ENV.fetch('TEST_DDAGENT_HOST', 'localhost')
c.use :rails, rails_options if use_rails
Expand Down
1 change: 0 additions & 1 deletion spec/ddtrace/contrib/rails/support/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
include_context 'Rails base application'

before do
Datadog.registry[:rails].instance_variable_set(:@patched, false)
reset_rails_configuration!
end

Expand Down
2 changes: 1 addition & 1 deletion test/contrib/rails/rack_middleware_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class FullStackTest < ActionDispatch::IntegrationTest
# this prevents the overhead to reinitialize the Rails application
# and the Rack stack
@tracer = get_test_tracer
Datadog.registry[:rails].reset_options!
Datadog.configuration[:rails].reset_options!
Datadog.configuration[:rails][:tracer] = @tracer
Datadog.configuration[:rails][:database_service] = get_adapter_name
Datadog::Contrib::Rails::Framework.setup
Expand Down
2 changes: 1 addition & 1 deletion test/contrib/rails/tracer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class TracerTest < ActionDispatch::IntegrationTest
# don't pollute the global tracer
@tracer = get_test_tracer
@config = Datadog.configuration[:rails]
Datadog.registry[:rails].reset_options!
Datadog.configuration[:rails].reset_options!
@config[:tracer] = @tracer
end

Expand Down

0 comments on commit 6bc79b4

Please sign in to comment.