Joining separate log to main Rails development log - ruby-on-rails

This is the reverse of the question I have seen several times elsewhere, in which someone wants to see how to create an another, separate Rails log from the main development log. For some reason, my Rails app is logging my DelayedJob gem's activity to a separate log (delayed_job.log), but I want it to log to the main development.log file. I am using the Workless gem and NewRelic as well, should this be potentially relevant (although I experimented on this by removing NewRelic, and the issue still remained).
I'm not clear on how this happened. However, I was having some trouble earlier with seeing SQL insertions and deletions in my log, and another user kindly suggested that I use the following in an initializer file:
if defined?(Rails) && !Rails.env.nil?
logger = Logger.new(STDOUT)
ActiveRecord::Base.logger = logger
ActiveResource::Base.logger = logger
end
Once I did this, I saw the SQL statements, but no longer saw the DelayedJob information in the main development log.
So my question is: How can I make sure that DelayedJob activity logs to the main development log? I don't mind if it also logs to a separate log, but the important thing is that I see its activity in my Mac's console.
Please let me know if you'd like more code from my app - I'd be happy to provide it. Much thanks from a Rails newbie.

Try adding the following line to config/initializers/delayed_job_config.rb
Delayed::Worker.logger = Logger.new(STDOUT)

I finally got this to work. All thanks to Seamus Abshere's answer to the question here. I put what he posted below in an initializer file. This got delayed_job to log to my development.rb file (huzzah!).
However, delayed_job still isn't logging into my console (for reasons I still don't understand). I solved that by opening a new console tab and entering tail -f log/development.log.
Different from what Seamus wrote, though, auto-flushing=true is deprecated in Rails 4 and my Heroku app crashed. I resolved this by removing it from my initializer file and placing it in my environments/development.rb file as config.autoflush_log = true. However, I found that neither of the two types of flushing were necessary to make this work.
Here is his code (without the auto-flushing):
file_handle = File.open("log/#{Rails.env}_delayed_jobs.log", (File::WRONLY | File::APPEND | File::CREAT))
# Be paranoid about syncing
file_handle.sync = true
# Hack the existing Rails.logger object to use our new file handle
Rails.logger.instance_variable_set :#log, file_handle
# Calls to Rails.logger go to the same object as Delayed::Worker.logger
Delayed::Worker.logger = Rails.logger
If the above code doesn't work, try replacing Rails.logger with RAILS_DEFAULT_LOGGER.

Related

Multithreading in Rails: Circular dependency detected while autoloading constant

I have a Rails app in which I have a Rake task that uses multithreading functions supplied by the concurrent-ruby gem.
From time to time I encounter Circular dependency detected while autoloading constant errors.
After Googling for a bit I found this to be related to using threading in combination with loading Rails constants.
I stumbled upon the following GitHub issues: https://github.com/ruby-concurrency/concurrent-ruby/issues/585 and https://github.com/rails/rails/issues/26847
As explained here you need to wrap any code that is called from a new thread in a Rails.application.reloader.wrap do or Rails.application.executor.wrap do block, which is what I did. However, this leads to deadlock.
The recommendation is then to use ActiveSupport::Dependencies.interlock.permit_concurrent_loads to wrap another blocking call on the main thread. However, I am unsure which code I should wrap with this.
Here's what I tried, however this still leads to a deadlock:
#beanstalk = Beaneater.new("#{ENV.fetch("HOST", "host")}:#{ENV.fetch("BEANSTALK_PORT", "11300")}")
tube_name = ENV.fetch("BEANSTALK_QUEUE_NAME", "queue")
pool = Concurrent::FixedThreadPool.new(Concurrent.processor_count * 2)
# Process jobs from tube, the body of this block gets executed on each message received
#beanstalk.jobs.register(tube_name) do |job|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
#logger.info "Received job: #{job.id}"
Concurrent::Future.execute(executor: pool) do
Rails.application.reloader.wrap do
# Stuff that references Rails constants etc
process_beanstalk_message(job.body)
end
end
end
end
#beanstalk.jobs.process!(reserve_timeout: 10)
Can anyone shed a light as to how I should solve this? The odd thing is I encounter this in production while other information on this topic seems to imply it should normally only occur in development.
In production I use the following settings:
config.eager_load = true
config.cache_classes = true.
Autoload paths for all environments are Rails default plus two specific folders ("models/validators" & "jobs/concerns").
eager_load_paths is not modified or set in any of my configs so must be equal to the Rails default.
I am using Rails 5 so enable_dependency_loading should equal to false in production.
You likely need to change your eager_load_paths to include the path to the classes or modules that are raising the errors. eager_load_paths is documented in the Rails Guides.
The problem you're running into is that Rails is not loading these constants when the app starts; it automatically loads them when they are called by some other piece of code. In a multithreaded Rails app, two threads may have a race condition when they try to load these constants.
Telling Rails to eagerly load these constants means they will be loaded once when the Rails app is started. It's not enough to say eager_load = true; you have to specify the paths to the class or module definitions as well. In the Rails application configuration, this is an Array under eager_load_paths. For example, to eager load ActiveJob classes:
config.eager_load_paths += ["#{config.root}/app/jobs"]
Or to load a custom module from lib/:
config.eager_load_paths += ["#{config.root}/lib/custom_module"]
Changing your eager load settings will affect the behavior of Rails. For example, in the Rails development environment, you're probably used to running rails server once, and every time you reload one of the endpoints it will reflect any changes to code you've made. That will not work with config.eager_load = true, because the classes are loaded once, at startup. Therefore, you will typically only change your eager_load settings for production.
Update
You can check your existing eager_load_paths from the rails console. For example, these are the default values for a new Rails 5 app. As you can see, it does not load app/**/*.rb; it loads the specific paths that Rails is expected to know about.
Rails.application.config.eager_load_paths
=> ["/app/assets",
"/app/channels",
"/app/controllers",
"/app/controllers/concerns",
"/app/helpers",
"/app/jobs",
"/app/mailers",
"/app/models",
"/app/models/concerns"]
In my gems (i.e., in plezi and iodine) I solve this with if statements, mostly.
You'll find code such as:
require 'uri' unless defined?(::URI)
or
begin
require 'rack/handler' unless defined?(Rack::Handler)
Rack::Handler::WEBrick = ::Iodine::Rack # Rack::Handler.get(:iodine)
rescue Exception
end
I used these snippets because of Circular dependency detected warnings and errors.
I don't know if this helps, but I thought you might want to try it.
I had this issue while trying out two gems that handles parallel processing;
pmap gem
parallel gem
For pmap I kept getting an error related to Celluloid::TaskTerminated and for parallel I was getting a Circular dependency detected while autoloading constant for when I ran it with more than 1 thread. I knew this issue was related to how my classes and modules were eager loading and race to be placed on a thread. I try enabling both of the configs to true config.cache_classes = true and config.eager_load = true in the development env and that did the trick for me.

Rails 4 - Should I place logger/debug messages inside a block Rails.env.development?

I am using inside a controller a logger message:
logger.debug "Here is the resulting object find_by_sql outputs: #{#deal}"
Should I use
if Rails.env.development?
logger.debug "Here is the resulting object find_by_sql outputs: #{#deal}"
end
Is it generally a good practice to put the logger message inside a Rails.dev block? I don't want to slow even a little little bit the app so the fact i add a if/end block will slow the app.
Letting it without any restriction to the dev mode would compromise the information security?
There's no need to do that with if statements. It's already controlled by log_level of the environment
In your config/environments/development.rb
config.log_level = :debug
But if you put this into config/environments/production.rb (default value, btw), you won't see any debug messages in the production log.
config.log_level = :warn
If you want to temporarily increase verbosity of production logs (for debugging or whatever), change log_level and redeploy. Do your troubleshooting and then rollback the app when you're done. Easier than touching Rails.env checks all over the codebase, isn't it?

Rails full error page not showing for view errors

I have a view named new.html.erb with the following code:
<%= some_non_existent_thing.imaginary_method %>
Now, I only see one simple 500 error page, like that:
500 Internal Server Error
If you are the administrator of this website, then please read this web application's log file and/or the web server's log file to find out what went wrong.
Shouldn't I see a pretty formatted page with some information about the exception?
I'm not sure I miss something here, but I believe rails used to show the full error page in development environment when there is something wrong in the view.
Are you sure that you are running the development environment? Check that RAILS_ENV=development or that you are running rails server -e development.
Then check your development.rb file, you should have the following line in it
config.consider_all_requests_local = true
If you happen to have an exception inside an exception, Rails has a middleware that catches it and returns a FAILSAFE_RESPONSE with the following copy:
500 Internal Server Error
If you are the administrator of this website, then please read this web application's log file and/or the web server's log file to find out what went wrong.
A nice way to troubleshoot this is to compare your custom error code with the sample code provided in the Rails 4.2.0 guides.
I'm pointing to that particular version because that whole section was removed in the Rails 5.0.0 guides.
Ideally, you should keep your error views, layout, and controller as free of logic as possible, to avoid running into this issue.
Firstly, as Anton mentions in the answer below, confirm that your config/environments/development.rb has:
config.consider_all_requests_local = true
and that you are running the server in development mode.
I had ensured the above and still observed the error.
This happened in my case, because my logger had some errors. I was using a custom log formatter, which used the String#% method to format the log. % seems to be very buggy and leads to all these weird errors. I figured this one out by adding a debugger line to the controller method and stepping through into the implicit render function call. It hit the bug and reported it as a malformed format string error.
This was the log formatter I was using before, which caused the bugs [I had added it to an initializer file]:
class Logger::SimpleFormatter
def call(severity, time, progname, msg)
"%-7s #{msg}\n" % severity
end
end
These modifications fixed the bug:
class Logger::SimpleFormatter
def call(severity, time, progname, msg)
severity_prefix = "[#{severity}]".ljust(7)
"#{severity_prefix} #{msg}\n"
end
end
This happens if the code is not compilable, for example if you have an if statement missing an end.

logger.debug not writing to log file in Rails

I am trying to debug a model in Rails so I'm using this code:
logger.debug('asasd')
However, I'm tailing the log file development.log but I'm not seeing it add to this file.
I am certain this module is being run
I have confirmed that runtime errors are logging to this file, and I see them when I tail.
How do I get this to work?
Make sure that you have set the log level to debug in environments/appropriate_env_file.rb:
config.log_level = :debug
and also make sure you are tailing the correct log file based on the environment you are running against.
You could attempt to call flush on the logger to force it to write to this file. Usually this would happen after every request:
logger.debug("asasd")
logger.flush
There's also the auto_flushing setting on the Rails.logger instance itself:
Rails.logger.auto_flushing = true
This will make the call to logger.flush unnecessary, as Rails will automatically flush the buffered output to the log file whenever it is written to.

How do I use a custom log for my rake tasks in Ruby on Rails?

I have a rake task that calls functions like this:
namespace :blah do
task :hello_world => :environment do
logger.info("Hello World")
helloworld2
end
end
def helloworld2
logger.info("Hello Again, World")
end
I want the log output to a custom log, and I really don't want to have to pass a log reference every time I make a function call. I found this somewhere (can't find it again):
def logger
##logger ||= Logger.new("#{RAILS_HOME}/log/blah.log")
end
But this does not work for me and I am not sure what it even does because I grabbed the code a long time ago and haven't used it until now. I can't search for ## on google (tried +"##" rails) to see what it does. Any help on this issue would be great. I am hoping for a quick solution and not having to install a gem or plugin (unless there is a really really good reason to.
Thanks!
rake disables logging in production mode. make sure you're running in development mode if you want it to log
What do you mean by "does not work for me"? I just tried this same code and it worked - created a new log file and put some text in it.
##logger is a class variable, it's a language issue, not Rails' one. I believe there's no need in further explanations :)
You've probably mistaken typing "function helloworld2" :)
Advanced Rails Recipes Recipe 84 from #topfunky shows how to define a custom logger. He has some code in the environment config file (production would look like this): RAILS_ROOT/config/environments/production.rb:
config.logger = RAILS_DEFAULT_LOGGER = Logger.new(config.log_path)
I'd test that out instead of redefining the class variable as you have. He might have something on http://nubyonrails.com to check as well.

Resources