diff --git a/README.md b/README.md index d6dc869..72ecaf3 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,24 @@ To start tracking, simply start your rails application server. When your server `sql_tracker` can also track sql queries when running rails tests (e.g. your controller or integration tests), it will dump the data after all the tests are finished. +### Tracking Using a Block + +It is also possible to track queries executed within a block. This method uses a new subscriber to `sql.active_record` event notifications for each invocation. Results using this method are not saved to a file. + +```ruby +query_data = SqlTracker.track do + # Run some active record queries +end + +query_data.values +# => +# [{ +# :sql=>"SELECT * FROM users", +# :count=>1, +# :duration=>1.0, +# :source=>["app/models/user.rb:12"] +# }] +``` ## Reporting diff --git a/lib/sql_tracker.rb b/lib/sql_tracker.rb index 3e2770c..3a32187 100644 --- a/lib/sql_tracker.rb +++ b/lib/sql_tracker.rb @@ -8,11 +8,20 @@ def self.initialize! config = SqlTracker::Config.apply_defaults handler = SqlTracker::Handler.new(config) - ActiveSupport::Notifications.subscribe('sql.active_record', handler) + handler.subscribe @already_initialized = true at_exit { handler.save } end + + def self.track + config = SqlTracker::Config.apply_defaults + handler = SqlTracker::Handler.new(config) + handler.subscribe + yield + handler.unsubscribe + handler.data + end end if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i >= 3 diff --git a/lib/sql_tracker/handler.rb b/lib/sql_tracker/handler.rb index 6bc84a8..9797c36 100644 --- a/lib/sql_tracker/handler.rb +++ b/lib/sql_tracker/handler.rb @@ -12,6 +12,21 @@ def initialize(config) @data = {} # {key: {sql:, count:, duration, source: []}, ...} end + def subscribe + @subscription ||= ActiveSupport::Notifications.subscribe( + 'sql.active_record', + self + ) + end + + def unsubscribe + return unless @subscription + + ActiveSupport::Notifications.unsubscribe(@subscription) + + @subscription = nil + end + def call(_name, started, finished, _id, payload) return unless @config.enabled diff --git a/sql_tracker.gemspec b/sql_tracker.gemspec index e08429b..000e5b4 100644 --- a/sql_tracker.gemspec +++ b/sql_tracker.gemspec @@ -19,7 +19,7 @@ Gem::Specification.new do |spec| spec.executables = ['sql_tracker'] spec.require_paths = ['lib'] - spec.add_development_dependency 'bundler', '~> 1.12' + spec.add_development_dependency 'bundler' spec.add_development_dependency 'rake', '~> 10.0' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'activesupport', '>= 3.0.0' diff --git a/test/sql_tracker_test.rb b/test/sql_tracker_test.rb new file mode 100644 index 0000000..c3f26bc --- /dev/null +++ b/test/sql_tracker_test.rb @@ -0,0 +1,37 @@ +require 'test_helper' + +module SqlTracker + class HandlerTest < Minitest::Test + def test_tracking_queries_with_a_block + config = SqlTracker::Config.apply_defaults + config.enabled = true + config.tracked_sql_command = %w(SELECT INSERT) + + expected_queries = [ + 'SELECT * FROM users', + 'insert into users VALUES (xxx)' + ] + + query_data = SqlTracker.track do + expected_queries.each { |q| instrument_query(q) } + instrument_query('DELETE FROM users WHERE id = 1') + end + + instrument_query('SELECT * FROM comments') + + assert_equal( + expected_queries, + query_data.values.map { |v| v[:sql] } + ) + end + + private + + def instrument_query(query) + ActiveSupport::Notifications.instrument( + 'sql.active_record', + sql: query + ) + end + end +end