diff --git a/integration/apps/rails-seven/app/controllers/di_controller.rb b/integration/apps/rails-seven/app/controllers/di_controller.rb new file mode 100644 index 00000000000..beabc41dd06 --- /dev/null +++ b/integration/apps/rails-seven/app/controllers/di_controller.rb @@ -0,0 +1,6 @@ +class DiController < ApplicationController + def ar_serializer + test = Test.create! + render json: Datadog::DI.component.serializer.serialize_value(test) + end +end diff --git a/integration/apps/rails-seven/config/initializers/datadog.rb b/integration/apps/rails-seven/config/initializers/datadog.rb index 89e276870ea..920cc4268b5 100644 --- a/integration/apps/rails-seven/config/initializers/datadog.rb +++ b/integration/apps/rails-seven/config/initializers/datadog.rb @@ -1,6 +1,5 @@ require 'datadog/statsd' require 'datadog' -require 'datadog/appsec' Datadog.configure do |c| c.env = 'integration' @@ -26,4 +25,8 @@ # Reconfigure transport to write pprof to file c.profiling.exporter.transport = Datadog::DemoEnv.profiler_file_transport end + + c.remote.enabled = true + c.dynamic_instrumentation.enabled = true + c.dynamic_instrumentation.internal.development = true end diff --git a/integration/apps/rails-seven/config/routes.rb b/integration/apps/rails-seven/config/routes.rb index 4f012b42a9d..06a88068d6d 100644 --- a/integration/apps/rails-seven/config/routes.rb +++ b/integration/apps/rails-seven/config/routes.rb @@ -10,6 +10,8 @@ get 'basic/fibonacci', to: 'basic#fibonacci' get 'basic/boom', to: 'basic#boom' + get 'di/ar_serializer', to: 'di#ar_serializer' + # Job test scenarios post 'jobs', to: 'jobs#create' end diff --git a/integration/apps/rails-seven/spec/integration/di_spec.rb b/integration/apps/rails-seven/spec/integration/di_spec.rb new file mode 100644 index 00000000000..0f45870bae1 --- /dev/null +++ b/integration/apps/rails-seven/spec/integration/di_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'json' + +RSpec.describe 'Dynamic Instrumentation' do + include_context 'integration test' + + describe 'ActiveRecord integration' do + subject { JSON.parse(get('di/ar_serializer').body) } + + it 'is loaded' do + # If AR integration is loaded, this output will be the result of + # the custom serializer. + # If AR integration is not loaded, the output here will have a bunch of + # internal AR fields but not the attributes themselves. + expect(subject).to match( + {"type"=>"Test", + "entries"=> + [[{"type"=>"Symbol", "value"=>"attributes"}, + {"type"=>"Hash", + "entries"=> + [[{"type"=>"String", "value"=>"id"}, {"type"=>"Integer", "value"=>String}], + [{"type"=>"String", "value"=>"version"}, {"type"=>"NilClass", "isNull"=>true}], + [{"type"=>"String", "value"=>"data"}, {"type"=>"NilClass", "isNull"=>true}], + [{"type"=>"String", "value"=>"created_at"}, + {"type"=>"ActiveSupport::TimeWithZone", "value"=>String}], + [{"type"=>"String", "value"=>"updated_at"}, + {"type"=>"ActiveSupport::TimeWithZone", "value"=>String}]]}], + [{"type"=>"Symbol", "value"=>"new_record"}, {"type"=>"FalseClass", "value"=>"false"}]]} + ) + end + end +end diff --git a/lib/datadog/di.rb b/lib/datadog/di.rb index 221c32864f6..ff185b09318 100644 --- a/lib/datadog/di.rb +++ b/lib/datadog/di.rb @@ -18,21 +18,6 @@ require_relative 'di/transport' require_relative 'di/utils' -if defined?(ActiveRecord::Base) - # The third-party library integrations need to be loaded after the - # third-party libraries are loaded. Tracing and appsec use Railtie - # to delay integrations until all of the application's dependencies - # are loaded, when running under Rails. We should do the same here in - # principle, however DI currently only has an ActiveRecord integration - # and AR should be loaded before any application code is loaded, being - # part of Rails, therefore for now we should be OK to just require the - # AR integration from here. - # - # TODO this require might need to be delayed via Rails post-initialization - # logic? - require_relative 'di/contrib/active_record' -end - module Datadog # Namespace for Datadog dynamic instrumentation. # @@ -75,3 +60,7 @@ def component # for line probes to work) activate tracking in an initializer. Datadog::DI.activate_tracking end + +require_relative 'di/contrib' + +Datadog::DI::Contrib.load_now_or_later diff --git a/lib/datadog/di/contrib.rb b/lib/datadog/di/contrib.rb new file mode 100644 index 00000000000..df6183b1d76 --- /dev/null +++ b/lib/datadog/di/contrib.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require_relative '../core/contrib/rails/utils' + +module Datadog + module DI + module Contrib + module_function def load_now_or_later + if Datadog::Core::Contrib::Rails::Utils.railtie_supported? + require_relative 'contrib/railtie' + else + load_now + end + end + + module_function def load_now + if defined?(ActiveRecord::Base) + require_relative 'contrib/active_record' + end + end + end + end +end diff --git a/lib/datadog/di/contrib/railtie.rb b/lib/datadog/di/contrib/railtie.rb new file mode 100644 index 00000000000..afe119cdc05 --- /dev/null +++ b/lib/datadog/di/contrib/railtie.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Datadog + module DI + module Contrib + # Railtie class initializes + class Railtie < Rails::Railtie + initializer 'datadog.dynamic_instrumentation.initialize' do |app| + Contrib.load_now + end + end + end + end +end