Skip to content

Commit

Permalink
Merge pull request #224 from pedro/migrate-configurations
Browse files Browse the repository at this point in the history
Migrate `rails` configuration to new API
  • Loading branch information
Emanuele Palazzetti authored Nov 23, 2017
2 parents cbb1d66 + cac9773 commit 0f1780b
Show file tree
Hide file tree
Showing 31 changed files with 232 additions and 206 deletions.
38 changes: 0 additions & 38 deletions lib/ddtrace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,41 +50,3 @@ def configure
# the load order, by letting things be lazily loaded while keeping
# thread-safety.
require 'ddtrace/monkey'

# Datadog auto instrumentation for frameworks
if defined?(Rails::VERSION)
if !ENV['DISABLE_DATADOG_RAILS']
if Rails::VERSION::MAJOR.to_i >= 3
require 'ddtrace/contrib/rails/framework'
require 'ddtrace/contrib/rails/middlewares'

module Datadog
# Railtie class initializes
class Railtie < Rails::Railtie
# add instrumentation middlewares
options = {}
config.app_middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware, options)
config.app_middleware.use(Datadog::Contrib::Rails::ExceptionMiddleware)

# auto instrument Rails and third party components after
# the framework initialization
config.after_initialize do |app|
Datadog::Contrib::Rails::Framework.configure(config: app.config)
Datadog::Contrib::Rails::Framework.auto_instrument()
Datadog::Contrib::Rails::Framework.auto_instrument_redis()
Datadog::Contrib::Rails::Framework.auto_instrument_grape()

# override Rack Middleware configurations with Rails
options.update(::Rails.configuration.datadog_trace)
end
end
end
else
Datadog::Tracer.log.warn 'Detected a Rails version < 3.x.'\
'This version is not supported yet and the'\
'auto-instrumentation for core components will be disabled.'
end
else
Datadog::Tracer.log.info 'Skipping Rails auto-instrumentation, DISABLE_DATADOG_RAILS is set.'
end
end
20 changes: 10 additions & 10 deletions lib/ddtrace/contrib/rack/middlewares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ module Rack
# application. If request tags are not set by the app, they will be set using
# information available at the Rack level.
class TraceMiddleware
DEFAULT_CONFIG = {
tracer: Datadog.tracer,
default_service: 'rack',
distributed_tracing_enabled: false
}.freeze
include Base
register_as :rack

option :tracer, default: Datadog.tracer
option :default_service, default: 'rack'
option :distributed_tracing_enabled, default: false

def initialize(app, options = {})
# update options with our configuration, unless it's already available
[:tracer, :default_service, :distributed_tracing_enabled].each do |k|
options[k] ||= DEFAULT_CONFIG[k]
Datadog.configuration[:rack][k] = options[k] unless options[k].nil?
end

@app = app
@options = options
end

def configure
# ensure that the configuration is executed only once
return clean_context if @tracer && @service

# retrieve the current tracer and service
@tracer = @options.fetch(:tracer)
@service = @options.fetch(:default_service)
@distributed_tracing_enabled = @options.fetch(:distributed_tracing_enabled)
@tracer = Datadog.configuration[:rack][:tracer]
@service = Datadog.configuration[:rack][:default_service]
@distributed_tracing_enabled = Datadog.configuration[:rack][:distributed_tracing_enabled]

# configure the Rack service
@tracer.set_service_info(
Expand Down
4 changes: 2 additions & 2 deletions lib/ddtrace/contrib/rails/action_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ def self.instrument

def self.start_processing(payload)
# trace the execution
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
service = ::Rails.configuration.datadog_trace.fetch(:default_controller_service)
tracer = Datadog.configuration[:rails][:tracer]
service = Datadog.configuration[:rails][:default_controller_service]
type = Datadog::Ext::HTTP::TYPE
span = tracer.trace('rails.action_controller', service: service, span_type: type)

Expand Down
4 changes: 2 additions & 2 deletions lib/ddtrace/contrib/rails/action_view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def self.start_render_template(payload)
tracing_context = payload.fetch(:tracing_context)

# create a new Span and add it to the tracing context
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
tracer = Datadog.configuration[:rails][:tracer]
span = tracer.trace('rails.render_template', span_type: Datadog::Ext::HTTP::TEMPLATE)
tracing_context[:dd_rails_template_span] = span
rescue StandardError => e
Expand Down Expand Up @@ -48,7 +48,7 @@ def self.start_render_partial(payload)
# retrieve the tracing context
tracing_context = payload.fetch(:tracing_context)

tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
tracer = Datadog.configuration[:rails][:tracer]
span = tracer.trace('rails.render_partial', span_type: Datadog::Ext::HTTP::TEMPLATE)
tracing_context[:dd_rails_partial_span] = span
rescue StandardError => e
Expand Down
4 changes: 2 additions & 2 deletions lib/ddtrace/contrib/rails/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ def self.instrument
end

def self.sql(_name, start, finish, _id, payload)
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
database_service = ::Rails.configuration.datadog_trace.fetch(:default_database_service)
tracer = Datadog.configuration[:rails][:tracer]
database_service = Datadog.configuration[:rails][:default_database_service]
adapter_name = ::ActiveRecord::Base.connection_config[:adapter]
adapter_name = Datadog::Contrib::Rails::Utils.normalize_vendor(adapter_name)
span_type = Datadog::Ext::SQL::TYPE
Expand Down
4 changes: 2 additions & 2 deletions lib/ddtrace/contrib/rails/active_support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def self.instrument
end

def self.start_trace_cache(payload)
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
tracer = Datadog.configuration[:rails][:tracer]
tracing_context = payload.fetch(:tracing_context)

# In most of the cases Rails ``fetch()`` and ``read()`` calls are nested.
Expand All @@ -26,7 +26,7 @@ def self.start_trace_cache(payload)
payload[:action] == 'GET'

# create a new ``Span`` and add it to the tracing context
service = ::Rails.configuration.datadog_trace.fetch(:default_cache_service)
service = Datadog.configuration[:rails][:default_cache_service]
type = Datadog::Ext::CACHE::TYPE
span = tracer.trace('rails.cache', service: service, span_type: type)
span.resource = payload.fetch(:action)
Expand Down
93 changes: 35 additions & 58 deletions lib/ddtrace/contrib/rails/framework.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,82 +30,59 @@ module Rails
# - handle configuration entries which are specific to Datadog tracing
# - instrument parts of the framework when needed
module Framework
# default configurations for the Rails integration; by default
# the Datadog.tracer is enabled, while the Rails auto instrumentation
# is kept disabled.
DEFAULT_CONFIG = {
enabled: true,
auto_instrument: false,
auto_instrument_redis: false,
auto_instrument_grape: false,
default_service: 'rails-app',
default_controller_service: 'rails-controller',
default_cache_service: 'rails-cache',
default_grape_service: 'grape',
template_base_path: 'views/',
tracer: Datadog.tracer,
debug: false,
trace_agent_hostname: Datadog::Writer::HOSTNAME,
trace_agent_port: Datadog::Writer::PORT,
env: nil,
tags: {}
}.freeze

# configure Datadog settings
# rubocop:disable Metrics/MethodLength
def self.configure(config)
# tracer defaults
# merge default configurations with users settings
user_config = config[:config].datadog_trace rescue {}
datadog_config = DEFAULT_CONFIG.merge(user_config)
datadog_config[:tracer].enabled = datadog_config[:enabled]

# set debug logging
Datadog::Tracer.debug_logging = datadog_config[:debug]

# set the address of the trace agent
datadog_config[:tracer].configure(
hostname: datadog_config[:trace_agent_hostname],
port: datadog_config[:trace_agent_port]
# rubocop:disable Metrics/AbcSize
def self.configure(rails_config)
user_config = rails_config[:config].datadog_trace rescue {}
Datadog.configuration.use(:rails, user_config)
tracer = Datadog.configuration[:rails][:tracer]

tracer.enabled = Datadog.configuration[:rails][:enabled]
tracer.class.debug_logging = Datadog.configuration[:rails][:debug]

tracer.configure(
hostname: Datadog.configuration[:rails][:trace_agent_hostname],
port: Datadog.configuration[:rails][:trace_agent_port]
)

# set default tracer tags
datadog_config[:tracer].set_tags(datadog_config[:tags])

datadog_config[:tracer].set_tags('env' => datadog_config[:env]) if datadog_config[:env]
tracer.set_tags(Datadog.configuration[:rails][:tags])
tracer.set_tags('env' => Datadog.configuration[:rails][:env]) if Datadog.configuration[:rails][:env]

# set default service details
datadog_config[:tracer].set_service_info(
datadog_config[:default_service],
tracer.set_service_info(
Datadog.configuration[:rails][:default_service],
'rack',
Datadog::Ext::AppTypes::WEB
)

datadog_config[:tracer].set_service_info(
datadog_config[:default_controller_service],
tracer.set_service_info(
Datadog.configuration[:rails][:default_controller_service],
'rails',
Datadog::Ext::AppTypes::WEB
)

datadog_config[:tracer].set_service_info(
datadog_config[:default_cache_service],
tracer.set_service_info(
Datadog.configuration[:rails][:default_cache_service],
'rails',
Datadog::Ext::AppTypes::CACHE
)

# By default, default service would be guessed from the script
# being executed, but here we know better, get it from Rails config.
datadog_config[:tracer].default_service = datadog_config[:default_service]
tracer.default_service = Datadog.configuration[:rails][:default_service]

Datadog.configuration[:rack][:tracer] = tracer
Datadog.configuration[:rack][:default_service] = Datadog.configuration[:rails][:default_service]
Datadog.configuration[:rack][:distributed_tracing_enabled] = \
Datadog.configuration[:rails][:distributed_tracing_enabled]

if defined?(::ActiveRecord)
begin
# set default database service details and store it in the configuration
conn_cfg = ::ActiveRecord::Base.connection_config()
adapter_name = Datadog::Contrib::Rails::Utils.normalize_vendor(conn_cfg[:adapter])
database_service = datadog_config.fetch(:default_database_service, adapter_name)
datadog_config[:default_database_service] = database_service
datadog_config[:tracer].set_service_info(
database_service,
Datadog.configuration[:rails][:default_database_service] ||= adapter_name
tracer.set_service_info(
Datadog.configuration[:rails][:default_database_service],
adapter_name,
Datadog::Ext::AppTypes::DB
)
Expand All @@ -115,11 +92,11 @@ def self.configure(config)
end

# update global configurations
::Rails.configuration.datadog_trace = datadog_config
::Rails.configuration.datadog_trace = Datadog.registry[:rails].to_h
end

def self.auto_instrument_redis
return unless ::Rails.configuration.datadog_trace[:auto_instrument_redis]
return unless Datadog.configuration[:rails][:auto_instrument_redis]
Datadog::Tracer.log.debug('Enabling auto-instrumentation for Redis client')

# patch the Redis library and reload the CacheStore if it was using Redis
Expand All @@ -142,21 +119,21 @@ def self.auto_instrument_redis
end

def self.auto_instrument_grape
return unless ::Rails.configuration.datadog_trace[:auto_instrument_grape]
return unless Datadog.configuration[:rails][:auto_instrument_grape]

# patch the Grape library so that endpoints are traced
Datadog::Monkey.patch_module(:grape)

# update the Grape pin object
pin = Datadog::Pin.get_from(::Grape)
return unless pin && pin.enabled?
pin.tracer = ::Rails.configuration.datadog_trace[:tracer]
pin.service = ::Rails.configuration.datadog_trace[:default_grape_service]
pin.tracer = Datadog.configuration[:rails][:tracer]
pin.service = Datadog.configuration[:rails][:default_grape_service]
end

# automatically instrument all Rails component
def self.auto_instrument
return unless ::Rails.configuration.datadog_trace[:auto_instrument]
return unless Datadog.configuration[:rails][:auto_instrument]
Datadog::Tracer.log.debug('Enabling auto-instrumentation for core components')

# instrumenting Rails framework
Expand Down
2 changes: 1 addition & 1 deletion lib/ddtrace/contrib/rails/middlewares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def call(env)
# It's not a problem since we re-raise it afterwards so for example a
# SignalException::Interrupt would still bubble up.
rescue Exception => e
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
tracer = Datadog.configuration[:rails][:tracer]
span = tracer.active_span()
span.set_error(e) unless span.nil?
raise e
Expand Down
55 changes: 55 additions & 0 deletions lib/ddtrace/contrib/rails/patcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module Datadog
module Contrib
module Rails
# Patcher
module Patcher
include Base
register_as :rails, auto_patch: true

option :enabled, default: true
option :auto_instrument, default: false
option :auto_instrument_redis, default: false
option :auto_instrument_grape, default: false
option :default_service, default: 'rails-app'
option :default_controller_service, default: 'rails-controller'
option :default_cache_service, default: 'rails-cache'
option :default_grape_service, default: 'grape'
option :default_database_service
option :distributed_tracing_enabled, default: false
option :template_base_path, default: 'views/'
option :tracer, default: Datadog.tracer
option :debug, default: false
option :trace_agent_hostname, default: Datadog::Writer::HOSTNAME
option :trace_agent_port, default: Datadog::Writer::PORT
option :env, default: nil
option :tags, default: {}
option :sidekiq_service, default: 'sidekiq'

@patched = false

class << self
def patch
return @patched if patched? || !compatible?
require_relative 'framework'
@patched = true
rescue => e
Datadog::Tracer.log.error("Unable to apply Rails integration: #{e}")
@patched
end

def patched?
@patched
end

def compatible?
return if ENV['DISABLE_DATADOG_RAILS']

defined?(::Rails::VERSION) && ::Rails::VERSION::MAJOR.to_i >= 3
end
end
end
end
end
end

require 'ddtrace/contrib/rails/railtie' if Datadog.registry[:rails].compatible?
18 changes: 18 additions & 0 deletions lib/ddtrace/contrib/rails/railtie.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'ddtrace/contrib/rails/framework'
require 'ddtrace/contrib/rails/middlewares'
require 'ddtrace/contrib/rack/middlewares'

module Datadog
# Railtie class initializes
class Railtie < Rails::Railtie
config.app_middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware)
config.app_middleware.use(Datadog::Contrib::Rails::ExceptionMiddleware)

config.after_initialize do |app|
Datadog::Contrib::Rails::Framework.configure(config: app.config)
Datadog::Contrib::Rails::Framework.auto_instrument
Datadog::Contrib::Rails::Framework.auto_instrument_redis
Datadog::Contrib::Rails::Framework.auto_instrument_grape
end
end
end
2 changes: 1 addition & 1 deletion lib/ddtrace/contrib/rails/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module Utils
def self.normalize_template_name(name)
return if name.nil?

base_path = ::Rails.configuration.datadog_trace.fetch(:template_base_path, 'views/')
base_path = Datadog.configuration[:rails][:template_base_path]
sections_view = name.split(base_path)

if sections_view.length == 1
Expand Down
3 changes: 1 addition & 2 deletions lib/ddtrace/contrib/sidekiq/tracer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ class Tracer
def initialize(options = {})
# check if Rails configuration is available and use it to override
# Sidekiq defaults
rails_config = ::Rails.configuration.datadog_trace rescue {}
base_config = Datadog.configuration[:sidekiq].merge(rails_config)
base_config = Datadog.configuration[:sidekiq].merge(Datadog.configuration[:rails])
user_config = base_config.merge(options)
@tracer = user_config[:tracer]
@sidekiq_service = user_config[:sidekiq_service]
Expand Down
Loading

0 comments on commit 0f1780b

Please sign in to comment.