I'm developing an application using Ruby on Rails.
I would like to erase old queries in the ActiveRecord::Base.logger object every time when I call a new action, essentially where ENV = production.
The goal is not to erase all queries like using config.log_level :info. I need only last queries to build a file with those queries.
Here is some code:
in the lib:
module SqlHunter
class ActiveRecord::ConnectionAdapters::AbstractAdapter
##queries = [] # without this line it work perfectly
##logging = false
cattr_accessor :queries, :logging
def log_info_with_trace(sql, name, runtime)
##queries << sql if ##logging
end
alias_method_chain :log_info, :trace
end
end
in the controller (report action)
ActiveRecord::ConnectionAdapters::AbstractAdapter::logging = true
.....
sqlfile = File.open("public/advancedStats/#{#dir_name}/advancedStatQuery.sql", 'w')
#queries = ActiveRecord::ConnectionAdapters::AbstractAdapter::queries
for query in #queries do
sqlfile.write("#{query} \n")
end
sqlfile.close
I asked an old related question here
link text
Thanks to Tamás Mezei and Damien MATHIEU for their last answer
Mondher
So you want to filter the SQL queries in production mode or am I missing the point?
If it's about just filtering, prod mode will automatically filter sql queries. If you'd like to filter when developing, edit the config/environments/development.rb file and insert
config.log_level = :info
Essentially, it will filter SQL with all the other stuff that's below info level (debug stuff).
If you want some more sophisticated solution, you can always exend/override the AbstractAdapter class in
RUBY_HOME/lib/gems/1.8/gems/activerecord-nnn/active_record/connection_adapters/abstract_adapter.rb
Related
I would like to create(if not exists) partition tables for each month for some time in the future:
execute """
CREATE TABLE IF NOT EXISTS #{table}_p#{start_date.year}_#{month}
PARTITION OF #{table} FOR VALUES
FROM ('#{start_date}')
TO ('#{stop_date}')
"""
I run it dynamically, eg: for next 12 month starting from today.
I would like to make it during migration, but run it each time migration starts. I can't use Repo since in time of the migration it's not yet started. I didn't find any ability to do it with Ecto.Migration api.
Do you have any ideas how to achieve this?
I made it with support of feature added in ecto 3.5.0. I added separate migration folder wich is used for so called 'repeated_migrations'.
#doc """
repeated migrations are run each deploy(e.g: ensure partitions). Repetition achieved by down method that does nothing.
"""
def run_repeated_migrations do
for repo <- repos() do
path = Ecto.Migrator.migrations_path(repo, "repeated_migrations")
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, path, :up, all: true))
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, path, :down, all: true))
end
end
method in repeated_migrations/20210427134701_partition_creation.exs
def down do
# to make this migration repeatable we run 'up' following by 'down'. Down do nothing.
execute "SELECT 1"
end
According to the Rails Guides:
Query caching is a Rails feature that caches the result set returned
by each query so that if Rails encounters the same query again for
that request, it will use the cached result set as opposed to running
the query against the database again.
Then follows an example where the same query is executed within a controller's action:
class ProductsController < ApplicationController
def index
# Run a find query
#products = Product.all
...
# Run the same query again
#products = Product.all
end
end
In my view layout at several places I call Category.pluck(:id). In the development log I then see this line several times:
SELECT "categories"."id" FROM "categories"
This happens even if I set this: config.action_controller.perform_caching = true for development. Why is this happening?
The query cache come from Rack.
Run rake middleware
And look for ActiveRecord::QueryCache
If thats in your middleware, SQL caching should be enabled, unless something else is turning it off.
Here is some documentation on the query cache:
http://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/QueryCache.html
And the Rack code
http://api.rubyonrails.org/classes/ActiveRecord/QueryCache.html
We have a use case where we need to run assets:precompile outside of the deploy/restart process, and therefore preferably without having to restart the Rails server processes. Is this possible in a Passenger environment?
I've been banging my head trying a bunch of stuff within Rake tasks and fiddling with Rails.application.config.assets stuff, but nothing makes the application pickup the changes to the digests except restarting Passenger with /usr/bin/env touch ~/project/current/tmp/restart.txt
We ended up going with a 2 part solution:
Part 1 is to setup the app to hit redis to store an 'assets:version' (we just went with a timestamp). Then, whenever our process was done precompiling, we update this assets version with the latest timestamp.
Part 2 was that we added a before_filter :check_assets_version in our main application_controller that all our other controllers inherit from. This method looks something like this:
def check_assets_version
##version ||= 1
latest_version = get_assets_version # wrapped call to redis to get latest version
# clear assets cache if current version isn't the same as the latest version from redis
unless latest_version.blank? || latest_version.to_s == ##version
##version = latest_version
if Rails.env.production? || Rails.env.sandbox? || Rails.env.experimental?
nondev_reset_sprockets
else
dev_reset_sprockets ##version
end
end
end
And those two reset methods look like this:
def nondev_reset_sprockets
manifest = YAML.load(File.read(Rails.root.join("public","assets","manifest.yml")))
manifest.each do |key, value|
Rails.application.config.assets.digests[key] = value
end
end
The nondev reset "stuffs" each of the values into memory from the new generated manifest file
def dev_reset_sprockets(version)
environment = Rails.application.assets
environment = environment.instance_variable_get('#environment') if environment.is_a?(Sprockets::Index)
environment.version = version
end
The dev reset just kicks sprockets "version" value so that it thinks (correctly so) it needs to reparse and live recompile the latest assets.
Another way of updating the assets in production is as follows:
Rails.application.assets_manifest.instance_eval do
new_manifest = Sprockets::Manifest.new(manifest.dir, manifest.filename)
#data = new_manifest.instance_variable_get(:#data)
end
For Rails 4 (Sprockets 2.11), you can do:
Rails.application.assets_manifest = Sprockets::Manifest.new(Rails.env, Rails.application.assets_manifest.path)
# see sprockets-rails/lib/railtie.rb
ActionView::Base.assets_manifest = Rails.application.assets_manifest
Is there a way to disable SQL query logging when I'm executing commands in the console? Ideally, it would be great if I can just disable it and re-enable it with a command in the console.
I'm trying to debug something and using "puts" to print out some relevant data. However, the sql query output is making it hard to read.
Edit:
I found another solution, since setting the logger to nil sometimes raised an error, if something other than my code tried to call logger.warn
Instead of setting the logger to nil you can set the level of the logger to 1.
ActiveRecord::Base.logger.level = 1 # or Logger::INFO
To turn it off:
old_logger = ActiveRecord::Base.logger
ActiveRecord::Base.logger = nil
To turn it back on:
ActiveRecord::Base.logger = old_logger
This might not be a suitable solution for the console, but Rails has a method for this problem: Logger#silence
ActiveRecord::Base.logger.silence do
# the stuff you want to be silenced
end
Here's a variation I consider somewhat cleaner, that still allows potential other logging from AR. In config/environments/development.rb :
config.after_initialize do
ActiveRecord::Base.logger = Rails.logger.clone
ActiveRecord::Base.logger.level = Logger::INFO
end
For Rails 4 you can put the following in an environment file:
# /config/environments/development.rb
config.active_record.logger = nil
In case someone wants to actually knock out SQL statement logging (without changing logging level, and while keeping the logging from their AR models):
The line that writes to the log (in Rails 3.2.16, anyway) is the call to debug in lib/active_record/log_subscriber.rb:50.
That debug method is defined by ActiveSupport::LogSubscriber.
So we can knock out the logging by overwriting it like so:
module ActiveSupport
class LogSubscriber
def debug(*args, &block)
end
end
end
I used this: config.log_level = :info
edit-in config/environments/performance.rb
Working great for me, rejecting SQL output, and show only rendering and important info.
In Rails 3.2 I'm doing something like this in config/environment/development.rb:
module MyApp
class Application < Rails::Application
console do
ActiveRecord::Base.logger = Logger.new( Rails.root.join("log", "development.log") )
end
end
end
Just as an FYI, in Rails 2 you can do
ActiveRecord::Base.silence { <code you don't want to log goes here> }
Obviously the curly braces could be replaced with a do end block if you wanted.
I use activerecord 6.0.3.3 and I had to include ActiveSupport::LoggerSilence
include ActiveSupport::LoggerSilence
ActiveSupport::LoggerSilence.silence do
## everything you want to silence
end
This however did not work with anything related to creating or deleting SQL tables like ActiveRecord::Migration.drop_table. For this to be silenced I added:
ActiveRecord::Schema.verbose = false
I had to solve this for ActiveRecord 6, and I based my answer on fakeleft's response, but it wasn't quite right, since it was suppressing other logging such as the logging of nested views. What I did was created config/initializers/activerecord_logger.rb:
# Suppress SQL statement logging if necessary
# This is a dirty, dirty trick, but it works:
if ENV["ACTIVERECORD_HIDE_SQL"].present?
module ActiveRecord
class LogSubscriber
def sql(event)
end
end
end
end
The log subscriber in AR 6 has a sql event that we want to hide, so this is very narrowly targeted to skip that event.
I’m developing an application dedicated to generate statistical reports, I would like that user after saving their stat report they save sql queries too. To do that I wrote the following module:
module SqlHunter
class ActiveRecord::ConnectionAdapters::AbstractAdapter
##queries = []
cattr_accessor :queries
def log_info_with_trace(sql, name, runtime)
return unless #logger && #logger.debug?
##queries << sql
end
alias_method_chain :log_info, :trace
end
end
in the controller I wrote that
sqlfile = File.open("public/advancedStats/#{#dir_name}/advancedStatQuery.sql", 'w')
#queries = ActiveRecord::ConnectionAdapters::AbstractAdapter::queries
for query in #queries do
sqlfile.write("#{query} \n")
end
sqlfile.close
I also modified Rails environment by adding this line:
ActiveRecord::Base.logger.level = Logger::DEBUG
This program is working and I can get all queries but, I need only the specific queries done by one user to generate a stat report.
Is someone has any idea,
Thanks,
mgatri
You could add an accessor that says if you wish to log or not.
##queries = []
##loging = false
cattr_accessor :queries, :logging
def log_info_with_trace(sql, name, runtime)
return unless #logger && #logger.debug?
##queries << sql if ##logging
end
When you do a ActiveRecord::ConnectionAdapters::AbstractAdapter::logging = true
Then, your SQL queries will be logged. When you set it to false, they won't.
So you can log them only whenever you want.
To erase the old queries, you just need to clear the array.
ActiveRecord::ConnectionAdapters::AbstractAdapter::queries.clear