From e57ce763efbd908c4e6461a18734b302282b0584 Mon Sep 17 00:00:00 2001 From: David Elner Date: Thu, 12 Apr 2018 11:39:16 -0400 Subject: [PATCH 1/3] Added: ActiveSupport::Notifications::Event helper. --- .../active_support/notifications/event.rb | 62 +++++++++ .../notifications/event_spec.rb | 118 ++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 lib/ddtrace/contrib/active_support/notifications/event.rb create mode 100644 spec/ddtrace/contrib/active_support/notifications/event_spec.rb diff --git a/lib/ddtrace/contrib/active_support/notifications/event.rb b/lib/ddtrace/contrib/active_support/notifications/event.rb new file mode 100644 index 00000000000..bfcda011ae8 --- /dev/null +++ b/lib/ddtrace/contrib/active_support/notifications/event.rb @@ -0,0 +1,62 @@ +require 'ddtrace/contrib/active_support/notifications/subscriber' + +module Datadog + module Contrib + module ActiveSupport + module Notifications + # Defines behaviors for an ActiveSupport::Notifications event. + # Compose this into a module or class, then define + # #event_name, #span_name, and #process. You can then + # invoke Event.subscribe! to more easily subscribe to an event. + module Event + def self.included(base) + base.send(:include, Subscriber) + base.send(:extend, ClassMethods) + base.send(:on_subscribe) { base.subscribe } + end + + # Redefines some class behaviors for a Subscriber to make + # it a bit simpler for an Event. + module ClassMethods + def subscribe! + super + end + + def subscription(span_name = nil, options = nil, tracer = nil) + super( + span_name || self.span_name, + options || span_options, + tracer || self.tracer, + &method(:process) + ) + end + + def subscribe(pattern = nil, span_name = nil, options = nil, tracer = nil) + if supported? + super( + pattern || event_name, + span_name || self.span_name, + options || span_options, + tracer || self.tracer, + &method(:process) + ) + end + end + + def supported? + true + end + + def span_options + {} + end + + def tracer + Datadog.tracer + end + end + end + end + end + end +end diff --git a/spec/ddtrace/contrib/active_support/notifications/event_spec.rb b/spec/ddtrace/contrib/active_support/notifications/event_spec.rb new file mode 100644 index 00000000000..1610d056070 --- /dev/null +++ b/spec/ddtrace/contrib/active_support/notifications/event_spec.rb @@ -0,0 +1,118 @@ +require 'spec_helper' +require 'ddtrace' + +require 'active_support/notifications' +require 'ddtrace/contrib/active_support/notifications/event' + +RSpec.describe Datadog::Contrib::ActiveSupport::Notifications::Event do + describe 'implemented' do + subject(:test_class) do + test_event_name = event_name + test_span_name = span_name + + Class.new.tap do |klass| + klass.send(:include, described_class) + klass.send(:define_singleton_method, :event_name) { test_event_name } + klass.send(:define_singleton_method, :span_name) { test_span_name } + klass.send(:define_singleton_method, :process, &process_block) + end + end + + let(:event_name) { double('event_name') } + let(:span_name) { double('span_name') } + let(:process_block) { Proc.new { spy.call } } + let(:spy) { double(:spy) } + + describe 'class' do + describe 'behavior' do + describe '#subscribe!' do + subject(:result) { test_class.subscribe! } + + it do + expect(ActiveSupport::Notifications).to receive(:subscribe) + .with(event_name, be_a_kind_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription)) + is_expected.to be true + end + + context 'is called a second time' do + before(:each) do + allow(ActiveSupport::Notifications).to receive(:subscribe) + .with(event_name, be_a_kind_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription)) + test_class.subscribe! + end + + it do + expect(ActiveSupport::Notifications).to_not receive(:subscribe) + is_expected.to be true + end + end + end + + describe '#subscribe' do + before(:each) do + expect(Datadog::Contrib::ActiveSupport::Notifications::Subscription).to receive(:new) + .with(test_class.tracer, test_class.span_name, test_class.span_options) + .and_call_original + end + + context 'when given no pattern' do + subject(:subscription) { test_class.subscribe } + + before(:each) do + expect_any_instance_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription).to receive(:subscribe) + .with(event_name) + end + + it { is_expected.to be_a_kind_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription) } + it { expect(test_class.subscriptions).to contain_exactly(subscription) } + end + + context 'when given a pattern' do + subject(:subscription) { test_class.subscribe(pattern) } + let(:pattern) { double('pattern') } + + before(:each) do + expect_any_instance_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription).to receive(:subscribe) + .with(pattern) + end + + it { is_expected.to be_a_kind_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription) } + it { expect(test_class.subscriptions).to contain_exactly(subscription) } + end + end + + describe '#subscription' do + context 'when given no options' do + subject(:subscription) { test_class.subscription } + + before(:each) do + expect(Datadog::Contrib::ActiveSupport::Notifications::Subscription).to receive(:new) + .with(test_class.tracer, test_class.span_name, test_class.span_options) + .and_call_original + end + + it { is_expected.to be_a_kind_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription) } + it { expect(test_class.subscriptions).to contain_exactly(subscription) } + end + + context 'when given options' do + subject(:subscription) { test_class.subscription(span_name, options, tracer) } + + let(:span_name) { double('span name') } + let(:options) { double('options') } + let(:tracer) { double('tracer') } + + before(:each) do + expect(Datadog::Contrib::ActiveSupport::Notifications::Subscription).to receive(:new) + .with(tracer, span_name, options) + .and_call_original + end + + it { is_expected.to be_a_kind_of(Datadog::Contrib::ActiveSupport::Notifications::Subscription) } + it { expect(test_class.subscriptions).to contain_exactly(subscription) } + end + end + end + end + end +end From 7ce2159ff0001c59cd241726529f2c93be1b9b0e Mon Sep 17 00:00:00 2001 From: David Elner Date: Thu, 12 Apr 2018 11:41:01 -0400 Subject: [PATCH 2/3] Refactored: Racecar to use ActiveSupport::Notifications::Event. --- lib/ddtrace/contrib/racecar/event.rb | 61 +++++++++++++++++++ lib/ddtrace/contrib/racecar/events.rb | 30 +++++++++ lib/ddtrace/contrib/racecar/events/batch.rb | 27 ++++++++ lib/ddtrace/contrib/racecar/events/message.rb | 27 ++++++++ lib/ddtrace/contrib/racecar/patcher.rb | 58 ++---------------- spec/ddtrace/contrib/racecar/patcher_spec.rb | 12 +--- 6 files changed, 153 insertions(+), 62 deletions(-) create mode 100644 lib/ddtrace/contrib/racecar/event.rb create mode 100644 lib/ddtrace/contrib/racecar/events.rb create mode 100644 lib/ddtrace/contrib/racecar/events/batch.rb create mode 100644 lib/ddtrace/contrib/racecar/events/message.rb diff --git a/lib/ddtrace/contrib/racecar/event.rb b/lib/ddtrace/contrib/racecar/event.rb new file mode 100644 index 00000000000..d167e9391ed --- /dev/null +++ b/lib/ddtrace/contrib/racecar/event.rb @@ -0,0 +1,61 @@ +require 'ddtrace/contrib/active_support/notifications/event' + +module Datadog + module Contrib + module Racecar + # Defines basic behaviors for an ActiveRecord event. + module Event + def self.included(base) + base.send(:include, ActiveSupport::Notifications::Event) + base.send(:extend, ClassMethods) + end + + # Class methods for Racecar events. + # Note, they share the same process method and before_trace method. + module ClassMethods + def subscription(*args) + super.tap do |subscription| + subscription.before_trace { ensure_clean_context! } + end + end + + def span_options + { service: configuration[:service_name] } + end + + def tracer + configuration[:tracer] + end + + def configuration + Datadog.configuration[:racecar] + end + + def process(span, event, _id, payload) + span.service = configuration[:service_name] + span.resource = payload[:consumer_class] + + span.set_tag('kafka.topic', payload[:topic]) + span.set_tag('kafka.consumer', payload[:consumer_class]) + span.set_tag('kafka.partition', payload[:partition]) + span.set_tag('kafka.offset', payload[:offset]) if payload.key?(:offset) + span.set_tag('kafka.first_offset', payload[:first_offset]) if payload.key?(:first_offset) + span.set_tag('kafka.message_count', payload[:message_count]) if payload.key?(:message_count) + span.set_error(payload[:exception_object]) if payload[:exception_object] + end + + private + + # Context objects are thread-bound. + # If Racecar re-uses threads, context from a previous trace + # could leak into the new trace. This "cleans" current context, + # preventing such a leak. + def ensure_clean_context! + return unless configuration[:tracer].call_context.current_span + configuration[:tracer].provider.context = Context.new + end + end + end + end + end +end diff --git a/lib/ddtrace/contrib/racecar/events.rb b/lib/ddtrace/contrib/racecar/events.rb new file mode 100644 index 00000000000..f9abc604d31 --- /dev/null +++ b/lib/ddtrace/contrib/racecar/events.rb @@ -0,0 +1,30 @@ +require 'ddtrace/contrib/racecar/events/batch' +require 'ddtrace/contrib/racecar/events/message' + +module Datadog + module Contrib + module Racecar + # Defines collection of instrumented Racecar events + module Events + ALL = [ + Events::Batch, + Events::Message + ].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 diff --git a/lib/ddtrace/contrib/racecar/events/batch.rb b/lib/ddtrace/contrib/racecar/events/batch.rb new file mode 100644 index 00000000000..96b6a276d42 --- /dev/null +++ b/lib/ddtrace/contrib/racecar/events/batch.rb @@ -0,0 +1,27 @@ +require 'ddtrace/contrib/racecar/event' + +module Datadog + module Contrib + module Racecar + module Events + # Defines instrumentation for process_batch.racecar event + module Batch + include Racecar::Event + + EVENT_NAME = 'process_batch.racecar'.freeze + SPAN_NAME = 'racecar.batch'.freeze + + module_function + + def event_name + self::EVENT_NAME + end + + def span_name + self::SPAN_NAME + end + end + end + end + end +end diff --git a/lib/ddtrace/contrib/racecar/events/message.rb b/lib/ddtrace/contrib/racecar/events/message.rb new file mode 100644 index 00000000000..85901b7242f --- /dev/null +++ b/lib/ddtrace/contrib/racecar/events/message.rb @@ -0,0 +1,27 @@ +require 'ddtrace/contrib/racecar/event' + +module Datadog + module Contrib + module Racecar + module Events + # Defines instrumentation for process_message.racecar event + module Message + include Racecar::Event + + EVENT_NAME = 'process_message.racecar'.freeze + SPAN_NAME = 'racecar.message'.freeze + + module_function + + def event_name + self::EVENT_NAME + end + + def span_name + self::SPAN_NAME + end + end + end + end + end +end diff --git a/lib/ddtrace/contrib/racecar/patcher.rb b/lib/ddtrace/contrib/racecar/patcher.rb index 71df0968bdf..fd190cfa4ab 100644 --- a/lib/ddtrace/contrib/racecar/patcher.rb +++ b/lib/ddtrace/contrib/racecar/patcher.rb @@ -1,5 +1,5 @@ require 'ddtrace/ext/app_types' -require 'ddtrace/contrib/active_support/notifications/subscriber' +require 'ddtrace/contrib/racecar/events' module Datadog module Contrib @@ -7,50 +7,26 @@ module Racecar # Provides instrumentation for `racecar` through ActiveSupport instrumentation signals module Patcher include Base - include ActiveSupport::Notifications::Subscriber - NAME_MESSAGE = 'racecar.message'.freeze - NAME_BATCH = 'racecar.batch'.freeze register_as :racecar option :service_name, default: 'racecar' option :tracer, default: Datadog.tracer do |value| (value || Datadog.tracer).tap do |v| # Make sure to update tracers of all subscriptions - subscriptions.each do |subscription| + Events.subscriptions.each do |subscription| subscription.tracer = v end end end - on_subscribe do - # Subscribe to single messages - subscription( - self::NAME_MESSAGE, - { service: configuration[:service_name] }, - configuration[:tracer], - &method(:process) - ).tap do |subscription| - subscription.before_trace { ensure_clean_context! } - subscription.subscribe('process_message.racecar') - end - - # Subscribe to batch messages - subscription( - self::NAME_BATCH, - { service: configuration[:service_name] }, - configuration[:tracer], - &method(:process) - ).tap do |subscription| - subscription.before_trace { ensure_clean_context! } - subscription.subscribe('process_batch.racecar') - end - end - class << self def patch return patched? if patched? || !compatible? - subscribe! + # Subscribe to Racecar events + Events.subscribe! + + # Set service info configuration[:tracer].set_service_info( configuration[:service_name], 'racecar', @@ -65,19 +41,6 @@ def patched? @patched = false end - def process(span, event, _, payload) - span.service = configuration[:service_name] - span.resource = payload[:consumer_class] - - span.set_tag('kafka.topic', payload[:topic]) - span.set_tag('kafka.consumer', payload[:consumer_class]) - span.set_tag('kafka.partition', payload[:partition]) - span.set_tag('kafka.offset', payload[:offset]) if payload.key?(:offset) - span.set_tag('kafka.first_offset', payload[:first_offset]) if payload.key?(:first_offset) - span.set_tag('kafka.message_count', payload[:message_count]) if payload.key?(:message_count) - span.set_error(payload[:exception_object]) if payload[:exception_object] - end - private def configuration @@ -87,15 +50,6 @@ def configuration def compatible? defined?(::Racecar) && defined?(::ActiveSupport::Notifications) end - - # Context objects are thread-bound. - # If Racecar re-uses threads, context from a previous trace - # could leak into the new trace. This "cleans" current context, - # preventing such a leak. - def ensure_clean_context! - return unless configuration[:tracer].call_context.current_span - configuration[:tracer].provider.context = Context.new - end end end end diff --git a/spec/ddtrace/contrib/racecar/patcher_spec.rb b/spec/ddtrace/contrib/racecar/patcher_spec.rb index 7e219836f9f..3e7d23680e8 100644 --- a/spec/ddtrace/contrib/racecar/patcher_spec.rb +++ b/spec/ddtrace/contrib/racecar/patcher_spec.rb @@ -17,14 +17,6 @@ def all_spans Datadog.configure do |c| c.use :racecar, tracer: tracer end - - # Make sure to update the subscription tracer, - # so we aren't writing to a stale tracer. - if Datadog::Contrib::Racecar::Patcher.patched? - Datadog::Contrib::Racecar::Patcher.subscriptions.each do |subscription| - allow(subscription).to receive(:tracer).and_return(tracer) - end - end end describe 'for single message processing' do @@ -42,7 +34,7 @@ def all_spans end let(:racecar_span) do - all_spans.select { |s| s.name == Datadog::Contrib::Racecar::Patcher::NAME_MESSAGE }.first + all_spans.select { |s| s.name == Datadog::Contrib::Racecar::Events::Message::SPAN_NAME }.first end context 'that doesn\'t raise an error' do @@ -110,7 +102,7 @@ def all_spans end let(:racecar_span) do - all_spans.select { |s| s.name == Datadog::Contrib::Racecar::Patcher::NAME_BATCH }.first + all_spans.select { |s| s.name == Datadog::Contrib::Racecar::Events::Batch::SPAN_NAME }.first end context 'that doesn\'t raise an error' do From 24f4db9d4d2c0e6c47d9e8e879f3d9f50c1c41f4 Mon Sep 17 00:00:00 2001 From: David Elner Date: Thu, 12 Apr 2018 11:41:27 -0400 Subject: [PATCH 3/3] Refactored: ActiveRecord to use ActiveSupport::Notifications::Event. --- lib/ddtrace/contrib/active_record/event.rb | 30 ++++++++ lib/ddtrace/contrib/active_record/events.rb | 30 ++++++++ .../active_record/events/instantiation.rb | 51 +++++++++++++ .../contrib/active_record/events/sql.rb | 48 ++++++++++++ lib/ddtrace/contrib/active_record/patcher.rb | 76 +------------------ test/contrib/rails/controller_test.rb | 2 +- test/contrib/rails/database_test.rb | 4 +- test/contrib/rails/rack_middleware_test.rb | 4 +- .../sinatra/tracer_activerecord_test.rb | 2 +- 9 files changed, 168 insertions(+), 79 deletions(-) create mode 100644 lib/ddtrace/contrib/active_record/event.rb create mode 100644 lib/ddtrace/contrib/active_record/events.rb create mode 100644 lib/ddtrace/contrib/active_record/events/instantiation.rb create mode 100644 lib/ddtrace/contrib/active_record/events/sql.rb diff --git a/lib/ddtrace/contrib/active_record/event.rb b/lib/ddtrace/contrib/active_record/event.rb new file mode 100644 index 00000000000..83704cc2c0a --- /dev/null +++ b/lib/ddtrace/contrib/active_record/event.rb @@ -0,0 +1,30 @@ +require 'ddtrace/contrib/active_support/notifications/event' + +module Datadog + module Contrib + module ActiveRecord + # Defines basic behaviors for an ActiveRecord event. + module Event + def self.included(base) + base.send(:include, ActiveSupport::Notifications::Event) + base.send(:extend, ClassMethods) + end + + # Class methods for ActiveRecord events. + module ClassMethods + def span_options + { service: configuration[:service_name] } + end + + def tracer + configuration[:tracer] + end + + def configuration + Datadog.configuration[:active_record] + end + end + end + end + end +end diff --git a/lib/ddtrace/contrib/active_record/events.rb b/lib/ddtrace/contrib/active_record/events.rb new file mode 100644 index 00000000000..c6824015913 --- /dev/null +++ b/lib/ddtrace/contrib/active_record/events.rb @@ -0,0 +1,30 @@ +require 'ddtrace/contrib/active_record/events/instantiation' +require 'ddtrace/contrib/active_record/events/sql' + +module Datadog + module Contrib + module ActiveRecord + # Defines collection of instrumented ActiveRecord events + module Events + ALL = [ + Events::Instantiation, + Events::SQL + ].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 diff --git a/lib/ddtrace/contrib/active_record/events/instantiation.rb b/lib/ddtrace/contrib/active_record/events/instantiation.rb new file mode 100644 index 00000000000..f651f3727b8 --- /dev/null +++ b/lib/ddtrace/contrib/active_record/events/instantiation.rb @@ -0,0 +1,51 @@ +require 'ddtrace/contrib/active_record/event' + +module Datadog + module Contrib + module ActiveRecord + module Events + # Defines instrumentation for instantiation.active_record event + module Instantiation + include ActiveRecord::Event + + EVENT_NAME = 'instantiation.active_record'.freeze + SPAN_NAME = 'active_record.instantiation'.freeze + DEFAULT_SERVICE_NAME = 'active_record'.freeze + + module_function + + def supported? + Gem.loaded_specs['activerecord'] \ + && Gem.loaded_specs['activerecord'].version >= Gem::Version.new('4.2') + end + + def event_name + self::EVENT_NAME + end + + def span_name + self::SPAN_NAME + end + + def process(span, event, _id, payload) + # Inherit service name from parent, if available. + span.service = if configuration[:orm_service_name] + configuration[:orm_service_name] + elsif span.parent + span.parent.service + else + self::DEFAULT_SERVICE_NAME + end + + span.resource = payload.fetch(:class_name) + span.span_type = 'custom' + span.set_tag('active_record.instantiation.class_name', payload.fetch(:class_name)) + span.set_tag('active_record.instantiation.record_count', payload.fetch(:record_count)) + rescue StandardError => e + Datadog::Tracer.log.debug(e.message) + end + end + end + end + end +end diff --git a/lib/ddtrace/contrib/active_record/events/sql.rb b/lib/ddtrace/contrib/active_record/events/sql.rb new file mode 100644 index 00000000000..634ad328b6c --- /dev/null +++ b/lib/ddtrace/contrib/active_record/events/sql.rb @@ -0,0 +1,48 @@ +require 'ddtrace/contrib/active_record/event' + +module Datadog + module Contrib + module ActiveRecord + module Events + # Defines instrumentation for sql.active_record event + module SQL + include ActiveRecord::Event + + EVENT_NAME = 'sql.active_record'.freeze + SPAN_NAME = 'active_record.sql'.freeze + + module_function + + def event_name + self::EVENT_NAME + end + + def span_name + self::SPAN_NAME + end + + def process(span, event, _id, payload) + connection_config = Utils.connection_config(payload[:connection_id]) + span.name = "#{connection_config[:adapter_name]}.query" + span.service = configuration[:service_name] + span.resource = payload.fetch(:sql) + span.span_type = Datadog::Ext::SQL::TYPE + + # Find out if the SQL query has been cached in this request. This meta is really + # helpful to users because some spans may have 0ns of duration because the query + # is simply cached from memory, so the notification is fired with start == finish. + cached = payload[:cached] || (payload[:name] == 'CACHE') + + span.set_tag('active_record.db.vendor', connection_config[:adapter_name]) + span.set_tag('active_record.db.name', connection_config[:database_name]) + span.set_tag('active_record.db.cached', cached) if cached + span.set_tag('out.host', connection_config[:adapter_host]) + span.set_tag('out.port', connection_config[:adapter_port]) + rescue StandardError => e + Datadog::Tracer.log.debug(e.message) + end + end + end + end + end +end diff --git a/lib/ddtrace/contrib/active_record/patcher.rb b/lib/ddtrace/contrib/active_record/patcher.rb index d05f04c87e7..fb814db0425 100644 --- a/lib/ddtrace/contrib/active_record/patcher.rb +++ b/lib/ddtrace/contrib/active_record/patcher.rb @@ -1,7 +1,7 @@ require 'ddtrace/ext/sql' require 'ddtrace/ext/app_types' require 'ddtrace/contrib/active_record/utils' -require 'ddtrace/contrib/active_support/notifications/subscriber' +require 'ddtrace/contrib/active_record/events' module Datadog module Contrib @@ -9,10 +9,6 @@ module ActiveRecord # Patcher enables patching of 'active_record' module. module Patcher include Base - include ActiveSupport::Notifications::Subscriber - - NAME_SQL = 'sql.active_record'.freeze - NAME_INSTANTIATION = 'instantiation.active_record'.freeze register_as :active_record, auto_patch: false option :service_name, depends_on: [:tracer] do |value| @@ -24,7 +20,7 @@ module Patcher option :tracer, default: Datadog.tracer do |value| (value || Datadog.tracer).tap do |v| # Make sure to update tracers of all subscriptions - subscriptions.each do |subscription| + Events.subscriptions.each do |subscription| subscription.tracer = v end end @@ -32,28 +28,6 @@ module Patcher @patched = false - on_subscribe do - # sql.active_record - subscribe( - self::NAME_SQL, # Event name - 'active_record.sql', # Span name - { service: get_option(:service_name) }, # Span options - get_option(:tracer), # Tracer - &method(:sql) # Handler - ) - - # instantiation.active_record - if instantiation_tracing_supported? - subscribe( - self::NAME_INSTANTIATION, # Event name - 'active_record.instantiation', # Span name - { service: get_option(:service_name) }, # Span options - get_option(:tracer), # Tracer - &method(:instantiation) # Handler - ) - end - end - module_function # patched? tells whether patch has been successfully applied @@ -64,7 +38,7 @@ def patched? def patch if !@patched && defined?(::ActiveRecord) begin - subscribe! + Events.subscribe! @patched = true rescue StandardError => e Datadog::Tracer.log.error("Unable to apply Active Record integration: #{e}") @@ -73,50 +47,6 @@ def patch @patched end - - def instantiation_tracing_supported? - Gem.loaded_specs['activerecord'] \ - && Gem.loaded_specs['activerecord'].version >= Gem::Version.new('4.2') - end - - def sql(span, event, _id, payload) - connection_config = Utils.connection_config(payload[:connection_id]) - span.name = "#{connection_config[:adapter_name]}.query" - span.service = get_option(:service_name) - span.resource = payload.fetch(:sql) - span.span_type = Datadog::Ext::SQL::TYPE - - # Find out if the SQL query has been cached in this request. This meta is really - # helpful to users because some spans may have 0ns of duration because the query - # is simply cached from memory, so the notification is fired with start == finish. - cached = payload[:cached] || (payload[:name] == 'CACHE') - - span.set_tag('active_record.db.vendor', connection_config[:adapter_name]) - span.set_tag('active_record.db.name', connection_config[:database_name]) - span.set_tag('active_record.db.cached', cached) if cached - span.set_tag('out.host', connection_config[:adapter_host]) - span.set_tag('out.port', connection_config[:adapter_port]) - rescue StandardError => e - Datadog::Tracer.log.debug(e.message) - end - - def instantiation(span, event, _id, payload) - # Inherit service name from parent, if available. - span.service = if get_option(:orm_service_name) - get_option(:orm_service_name) - elsif span.parent - span.parent.service - else - 'active_record' - end - - span.resource = payload.fetch(:class_name) - span.span_type = 'custom' - span.set_tag('active_record.instantiation.class_name', payload.fetch(:class_name)) - span.set_tag('active_record.instantiation.record_count', payload.fetch(:record_count)) - rescue StandardError => e - Datadog::Tracer.log.debug(e.message) - end end end end diff --git a/test/contrib/rails/controller_test.rb b/test/contrib/rails/controller_test.rb index 5146f59115d..bc4d0aa08e6 100644 --- a/test/contrib/rails/controller_test.rb +++ b/test/contrib/rails/controller_test.rb @@ -117,7 +117,7 @@ class TracingControllerTest < ActionController::TestCase spans = @tracer.writer.spans # rubocop:disable Style/IdenticalConditionalBranches - if Datadog::Contrib::ActiveRecord::Patcher.instantiation_tracing_supported? + if Datadog::Contrib::ActiveRecord::Events::Instantiation.supported? assert_equal(spans.length, 5) span_instantiation, span_database, span_request, span_cache, span_template = spans diff --git a/test/contrib/rails/database_test.rb b/test/contrib/rails/database_test.rb index 9daf2dec3a7..549f8f36ce2 100644 --- a/test/contrib/rails/database_test.rb +++ b/test/contrib/rails/database_test.rb @@ -44,7 +44,7 @@ class DatabaseTracingTest < ActiveSupport::TestCase end test 'active record traces instantiation' do - if Datadog::Contrib::ActiveRecord::Patcher.instantiation_tracing_supported? + if Datadog::Contrib::ActiveRecord::Events::Instantiation.supported? begin Article.create(title: 'Instantiation test') @tracer.writer.spans # Clear spans @@ -69,7 +69,7 @@ class DatabaseTracingTest < ActiveSupport::TestCase end test 'active record traces instantiation inside parent trace' do - if Datadog::Contrib::ActiveRecord::Patcher.instantiation_tracing_supported? + if Datadog::Contrib::ActiveRecord::Events::Instantiation.supported? begin Article.create(title: 'Instantiation test') @tracer.writer.spans # Clear spans diff --git a/test/contrib/rails/rack_middleware_test.rb b/test/contrib/rails/rack_middleware_test.rb index 9433cd7eee2..082e5ca96e8 100644 --- a/test/contrib/rails/rack_middleware_test.rb +++ b/test/contrib/rails/rack_middleware_test.rb @@ -37,7 +37,7 @@ class FullStackTest < ActionDispatch::IntegrationTest # spans are sorted alphabetically, and ... controller names start # either by m or p (MySQL or PostGreSQL) so the database span is always # the first one. Would fail with an adapter named z-something. - if Datadog::Contrib::ActiveRecord::Patcher.instantiation_tracing_supported? + if Datadog::Contrib::ActiveRecord::Events::Instantiation.supported? assert_equal(spans.length, 6) instantiation_span, database_span, request_span, controller_span, cache_span, render_span = spans else @@ -73,7 +73,7 @@ class FullStackTest < ActionDispatch::IntegrationTest assert_includes(database_span.resource, 'FROM') assert_includes(database_span.resource, 'articles') - if Datadog::Contrib::ActiveRecord::Patcher.instantiation_tracing_supported? + if Datadog::Contrib::ActiveRecord::Events::Instantiation.supported? assert_equal(instantiation_span.name, 'active_record.instantiation') assert_equal(instantiation_span.span_type, 'custom') assert_equal(instantiation_span.service, Datadog.configuration[:rails][:service_name]) diff --git a/test/contrib/sinatra/tracer_activerecord_test.rb b/test/contrib/sinatra/tracer_activerecord_test.rb index b912d15e03c..362d6b735b2 100644 --- a/test/contrib/sinatra/tracer_activerecord_test.rb +++ b/test/contrib/sinatra/tracer_activerecord_test.rb @@ -120,7 +120,7 @@ def test_cached_tag def test_instantiation_tracing # Only supported in Rails 4.2+ - skip unless Datadog::Contrib::ActiveRecord::Patcher.instantiation_tracing_supported? + skip unless Datadog::Contrib::ActiveRecord::Events::Instantiation.supported? # Make sure Article table exists migrate_db