Our production logs are long and contain a lot more than just errors. I'd like a second log file with just the errors/exceptions in.
Is this possible?
We're using rails 2.x
Thanks.
For example, to log all ActiveRecord::Base errors in a file called log/exceptions.log
new_logger = Logger.new('log/exceptions.log')
new_logger.level = Logger::ERROR
new_logger.error('THIS IS A NEW EXCEPTION!')
ActiveRecord::Base.logger = new_logger
For controllers and view(because ActionView logger doesn't have it's own logger, so it depends on the ActionController logger):
ActionController::Base.logger = new_logger
Try the following. Put the rescue_from method in your controller.
I haven't tested this. But maybe it puts you in the right direction
class ApplicationController < ActionController::Base
rescue_from StandardError do |exception|
new_logger = Logger.new('log/exceptions.log')
new_logger.info('THIS IS A NEW EXCEPTION!')
new_logger.info(exception.message)
new_logger.info(exception.backtrace)
# Raise it anyway because you just want to put it in the log
raise exception
end
end
If you use Rails 2.1 (also not tested)
class ApplicationController < ActionController::Base
def rescue_action_in_public(exception)
new_logger = Logger.new('log/exceptions.log')
new_logger.info('THIS IS A NEW EXCEPTION!')
new_logger.info(exception.message)
new_logger.info(exception.backtrace)
# Raise it anyway because you just want to put it in the log
raise exception
end
end
Related
I'm trying to access the request object in app/controllers/application_controller.rb. My code is:
class ApplicationController < ActionController::API
include ActionView::Layouts
include ActionController::RequestForgeryProtection
protect_from_forgery
before_action :require_login
private
def require_login
unless logged_in?
logger.log "#{request}"
end
end
def logged_in?
false
end
end
This results in the error:
comparison of String with 0 failed, highlighting the line logger.log "#{request}"
I thought it was a problem with the middleware not being loaded, so I tried to load it in config/application.rb:
config.middleware.use ActionDispatch::Request
But this results in another error:
undefined method 'call' for ActionDispatch::Request
I seem to keep having to add things back in since I used the --api option and it strips a lot of things out. But I don't know how to add back in access to the request option. Any help?
It looks like you are mis-using logger.log. In the simple example below, I have outlined three ways to approach this. If you want to use logger.log, you need to specify at minimum a severity level. That is the source of the comparison of String with 0 failed message you are receiving.
class ApplicationController < ActionController::API
before_action :log_request
def log_request
logger.log request # This doesn't work
logger.info("#{request}") # This works
logger.log(Logger::WARN,"#{request}") # This works
end
end
Valid levels are: FATAL, ERROR, WARN, INFO, DEBUG.
Reference: http://ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html#method-i-add (logger.log is an alias for logger.add)
Logger#add(severity, message = nil, progname = nil) { ... }
I am trying to create my own StandardError exception, but I cannot seem to fire rescue_from with the raise. The error is raised but never rescued. I built a simple application to try it, as follows:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
class ApplicationController::LocationInvalid < StandardError
end
rescue_from ApplicationController::LocationInvalid, with: :reset_it
raise ApplicationController::LocationInvalid
private
def reset_it(exception)
session.clear
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
puts 'Reset it processed'
end
end
When I wrap the raise in begin/rescue/end, it prints e as ApplicationController::LocationInvalid:
begin
raise ApplicationController::LocationInvalid
rescue => e
puts e
end
Output:
Started GET "/" for 127.0.0.1 at 2015-08-21 15:19:32 -0400
ApplicationController::LocationInvalid
I've tried various forms of specifying the ApplicationController class and not with no change in the results...
According to source code of Rails https://github.com/rails/rails/blob/f62fb985b6a7b90872148f0786219c9cc94c9356/actionpack/lib/action_controller/metal/rescue.rb#L32
rescue_with works only during process_action call but you are raising exception during class evaluation. Probably the easiest way how to test it is to create simple controller with some action and try to raise exception during that action and rescue_with should work.
So in my application_controller I have a helper method that raises an exception in a certain case, and a rescue_from for that exception in the same file. The structure looks something like the following:
application_controller.rb:
class ApplicationController < ActionController::Base
helper_method :my_method
def my_method
begin
# some code
rescue xyz
# some code
unless something
raise MyException.new()
end
rescue
raise MyException.new()
end
end
rescue_from 'MyException' do |e|
# some code
end
class MyException < StandardError; end
end
For some reason, when MyException is raised in my helper method, it is not caught by the rescue_from. I'm honestly not sure how to proceed...I don't think putting the rescue_from before the method would affect anything, since I have more than one handler defined like this and they work fine.
I tried almost everything on web, all I want is to call a method whenever an exception like "ActiveRecord::RecordNotFound" or "No route matches" appears.
Rescues from ApplicationController does not work, but why?
class ApplicationController < ActionController::Base
protect_from_forgery
private
def self.send_report_error(message)
Notifier.page_failure(message).deliver
end
rescue ActiveRecord::RecordNotFound
# handle not found error
send_report_error ActiveRecord::RecordNotFound.to_s
rescue ActiveRecord::ActiveRecordError
# handle other ActiveRecord errors
send_report_error ActiveRecord::ActiveRecordError.to_s
rescue # StandardError
# handle most other errors
send_report_error "common error"
rescue Exception
# handle everything else
send_report_error "common exception"
end
Use rescue_from. For example:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :send_report_error
end
http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html
For a specific role (group of users) I added the :readonly to every find on the active record
def self.find(*args)
if User.current_user.has_role? 'i_can_only_read'
with_scope({:find => {:readonly => true}}) do
result = super *args
end
end
end
Of course it raises now ActiveRecord::ReadOnlyRecord Exceptions in Controller passed on to the user; not very nice.
Can I catch this type of error in one place? Like in production.rb or in the application.rb? Or can I configure a specific error page for this error?
Yes, simply override rescue_action_in_public like this:
class ApplicationController < ActionController::Base
...
def rescue_action_in_public(exception)
case exception
when ActiveRecord::ReadOnlyRecord
# DO SOME LOGIC HERE
end
end
end
end
This will execute your action when in "production", but leave you with an informative stack trace when you are in "development".
Rails has a number of other rescue_action_* methods that might be more suitable to your problem...take a look at http://api.rubyonrails.org/classes/ActionController/Rescue.html