Log Every SQL Query to Database in Rails

Log every SQL query to database in Rails

SQL logging in rails -
In brief - you need to override ActiveRecord execute method. There you can add any logic for logging.

Log every SQL query to database in Rails 3

Put it in config/initializers. Most likely it's because of reloading classes each time in dev env. This code need to be executed only once though.

Ruby on Rails SQL Logging

If you use active record, you can overwrite the active record logger :

ActiveRecord::Base.logger = Logger.new("#{Rails.root}/log/sql_log.log")

Display SQL queries in log with Rails 4

the rails console never writes to the log file, but you can achieve it quite easily, for example, if you execute following after starting the rails console

ActiveRecord::Base.logger = Logger.new STDOUT

rails will log all SQL statements to stdout, thus display them in your terminal. and since Logger.new accepts any stream as first argument, you could just let it write to the rails development.log:

ActiveRecord::Base.logger = Logger.new File.open('log/development.log', 'a')

How to show SQL queries run in the Rails console?

Rails 3+

Enter this line in the console:

ActiveRecord::Base.logger = Logger.new(STDOUT)

Rails 2

Enter this line in the console:

ActiveRecord::Base.connection.instance_variable_set :@logger, Logger.new(STDOUT)

ActiveRecord log which query went to which database

As I know you can't do it with ActiveRecord natively. But you can override log method in AbstractAdapter if you really need it:

class ActiveRecord::ConnectionAdapters::AbstractAdapter
alias :original_log :log
def log(sql, name = "SQL", binds = [], statement_name = nil)
#add info that you want to display to name
name = "#{name} #{@connection.hash}"
original_log(sql, name, binds, statement_name) { yield }
end
end

The output:

D, [2017-03-15T20:55:59.200533 #73440] DEBUG -- :    -4111614587995646180 (0.5ms)  create table foo(i int)
D, [2017-03-15T20:55:59.201178 #73440] DEBUG -- : -4097137311320758185 (0.1ms) create table foo(i int)
D, [2017-03-15T20:55:59.201298 #73440] DEBUG -- : -4111614587995646180 (0.0ms) insert into foo(i) values (1)
D, [2017-03-15T20:55:59.201426 #73440] DEBUG -- : -4097137311320758185 (0.1ms) insert into foo(i) values (2)
D, [2017-03-15T20:55:59.202229 #73440] DEBUG -- : -4111614587995646180 (0.7ms) select * from foo
D, [2017-03-15T20:55:59.202360 #73440] DEBUG -- : -4097137311320758185 (0.0ms) select * from foo

Being more human-friendly

The above code logs the connection hash, and that's enough to tell one connection from another. If you want to log something more human-friendly than that, you'll need to get a little tricky.

What we can do is to decorate the abstract adapter with a method to return a human-friendly connection name. During your program's initialization, add a #log_name method to each connection adapter:

Base1.connection.define_singleton_method(:log_name) { "one" }
Base2.connection.define_singleton_method(:log_name) { "two" }

The monkey-patch can now use the #log_name method:

class ActiveRecord::ConnectionAdapters::AbstractAdapter
alias :original_log :log
def log(sql, name = "SQL", binds = [], statement_name = nil)
connection_name = respond_to?(:log_name) ? log_name : nil
name = [connection_name, name].compact.join(" ")
original_log(sql, name, binds, statement_name) { yield }
end
end

The output:

D, [2017-03-21T10:10:53.330021 #22147] DEBUG -- :   one (0.3ms)  create table foo(i int)
D, [2017-03-21T10:10:53.330380 #22147] DEBUG -- : two (0.2ms) create table foo(i int)
D, [2017-03-21T10:10:53.330464 #22147] DEBUG -- : one (0.0ms) insert into foo(i) values (1)
D, [2017-03-21T10:10:53.330536 #22147] DEBUG -- : two (0.0ms) insert into foo(i) values (2)
D, [2017-03-21T10:10:53.331002 #22147] DEBUG -- : one (0.4ms) select * from foo
D, [2017-03-21T10:10:53.331104 #22147] DEBUG -- : two (0.0ms) select * from foo

Rails Logs: Only show Create, Update, and Destroy SQL statements in Logs and nothing else

You can disable logging of ActiveRecord database queries by setting the log_level to :info.

Then use Rails' ActiveSupport::Instrumentation and subscribe to the sql.active_record event.

Just add the following code into an initializer:

# in `config/initializers/query_logger.rb`
class QueryLogger
def call(name, started, finished, unique_id, payload)
query = payload[:sql]

Rails.logger.info("SQL Query: #{query}") unless query.start_with?('SELECT')
end
end

ActiveSupport::Notifications.subscribe('sql.active_record', QueryLogger.new)

Rails 2.3 log all database queries separatly

You don't need to monkey-patch ActiveRecord to get logging (which you're doing incorrectly here anyway). I assume you want this in production, since in development all queries are already logged. Simply set this in config/environments/production.rb:

config.log_level = :debug

Or if you want to restrict this to SQL queries only, without the other verbosity, try this:

ActiveRecord::Base.logger.level = Logger::DEBUG

Or if your goal is to write the SQL queries to a dedicated logfile, check out this question: Rails3 SQL logging output in a separate file

Log SQL queries during rake tasks

Depending on your environment, Rake will log sql queries just like any Rails process will & in the same logfile. So on your dev box, check your log/development.log file - it will contain your Rake task's queries. If you want queries logged in production, set the log level in your Rake task to DEBUG, and make sure the rake task depends on :environment.

desc "Task with SQL logging"
task :test_log => :environment do
Rails.logger.level = Logger::DEBUG
Your code here...
end


Related Topics



Leave a reply



Submit