Rails: Skip logging backtrace - ruby-on-rails

I am logging the errors of a rails application using exception_logger (https://github.com/ryancheung/exception_logger) and it is working file. But it is logging the backtrace which I don't want to be logged.
Is there any way to stop logging backtrace?

Side note: why would you want that? Backtraces are very valuable as they tell you exactly where a problem (exception) occurs in your code.
Anyway, it seems that logging exceptions backtrace is not configurable in the exception_logger gem. So your only option would be to monkey-patch some of its code. I'd try to patch the setter for the backtrace in the LoggedException model.
Put this into an initializer under lib/initializers:
# lib/initializers/logged_exception_patch.rb
module ExceptionLogger
class LoggedException < ActiveRecord::Base
def backtrace=(trace)
write_attribute :backtrace, ""
end
end
end
This code will make the model just ignore back traces when saving the logged exceptions and save a blank string to the backtrace column instead.
But let me say again - I think that if you are logging real exceptions on a real site, sooner or later you will regret not logging the back traces because you will get an exception with an unclear origin...

Related

methods for debugging slow queries in active model serializers?

I am having difficulty optimizing my Active Model Serializers to avoid the n+1 problem. As per suggestions from their docs, I have attempted to eager load the associations which i thought were causing my query bottlenecks, but my serializers are still taking forever.
Obviously, i must be doing something wrong. My application is deeply nested with associations, so i guess I'm more interested in discovering a tool to unveil to me exactly WHICH associations are costing me. Right now, i am attaching a stack trace to every query run through the ActiveRecord
ActiveSupport::Notifications.subscribe("sql.active_record") do |_, _, _, _, details|
puts caller.join("\n")
puts "*" * 50
end
which gives me a ridiculous output because i am running so many queries to begin with, but, in addition, the stack traces are not helpful at identifying which serializer is at fault. It shows me which controller method was calling render, but then from there the stack trace simply prints methods from gems/active_model_serializers, which does not help me.
I am hoping to uncover a method of debugging that would be able to identify to me which serializers were at fault, that way i am not guessing at how to optimize my queries. Has anybody discovered anything like this? Thanks!
===================
UPDATE
Just so it is clear, i am already printing a query log, in addition to a stack trace. Unfortunately, with so many associations to keep track of, the query log is not exactly helpful at identifying the source of the query. It is guess work at best, and ineffective at the association scope i am dealing with.
I have abandoned the stack traces altogether, finding them to be totally unhelpful. Now, all i have printing are SQL logs, and i am manually sifting through them, trying to discover the source of the association.
The next method I will attempt (although i hate to resort to it) is commenting out associations until i see improvements in my query times. It will be more effective than trying to trace the source of the problem, but it will provide me no comfort in a production environment (where commenting out critical associations is not an option), so if anybody finds a solution that can help, I would still be very grateful.
I will continue to post updates as I move through this problem, as it may help many others in the future.
======================UPDATE 2
It turns out that commenting out associations in my serializer and reintroducing them one at a time, while ineffective in production, is an excellent way to debug in a local environment. I was able to drill down to the problem within a minute and correct it. Still, this is not an ideal solution. I would ideally like to be able to identify the problem from a log so that in production i could ascertain the issue without affecting the application's behavior.
The active_record_query_trace gem can do that.
Add the following to your Gemfile:
group :development do
gem 'active_record_query_trace'
end
Create an initializer such as config/initializers/active_record_query_trace.rb to enable the gem. If you want to customize how the gem behaves, you can add any combination of the options described in the docs to the initializer as well.
if Rails.env.development?
ActiveRecordQueryTrace.enabled = true
# Optional: other gem config options go here
end
Restart the Rails development server.
Easy way within any gems - is logging each string of code. For example, if you have
that code of serializer:
module Flats
class IndexSerializer < Api::V2::RealtyObjects::IndexSerializer
attributes(
:flat_number,
:entrance_number,
:floor_in_house,
:live_area,
:room_count,
:total_area,
)
end
end
add method which will be log time to your development.log on each attribute:
module Flats
class IndexSerializer < Api::V2::RealtyObjects::IndexSerializer
attribute_list = %i[
flat_number
entrance_number
floor_in_house
live_area
room_count
total_area
]
attributes(*attribute_list)
def logger(name, value)
Rails.logger.debug name, value, "#{Time.now.strftime('%M:%S--%N')}"
end
attribute_list.each do |attribute_name|
define_method attribute_name do |value|
logger(attribute_name, value)
super
end
end
end
end

Customize exception_notifier, Ruby on Rails

I have successfully added the exception_notifier to my rails app, and it is emailing a notification for all exceptions at the application level (which is exactly what I want). The only problem is that I need to have a few short lines of code ran whenever an exception is raised as well, and am certain that there is a way to add these lines of code onto the notifier. But despite reading the documentation found here: https://github.com/smartinez87/exception_notification I am still unclear what/where I should put things. Can someone please explain this a bit better for me. I am relatively new to ROR. I just need to add some additional code to run whenever the notifier is alerted to an exception.
This seems to be the correct link to the background notification:
Using a begin rescue should do the trick.
def method
sentence1
begin
sentence2
sentence3
rescue => e
ExceptionNotifier.notify_exception(e)
Sentence code1
return action
end
end
As explained here:
https://github.com/smartinez87/exception_notification#background-notifications
So as a shorthand: To do code before or after the notification is sended, but outside of the notification method you need to catch the exception in the method who raised it and work there.
But remember: Catching exceptions should be an exception. If you know what could go wrong, try to fix it, not to catch 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.

Low-level exception handling in Rails

How can I use exception handling in Rails? Currently I have done following.
In each controller method I have added
begin
<myCode>
rescue
<exception handler>
But I think with Rails I should be able to define an exception handler method in Application controller and catch all the exceptions from there, without handling them from each method.
I have used 'rescue_action_in_public' in my application controller, but when I given a wrong database name in config/database.yml and load the application, it doesn't catch those exceptions.
My questions are
1 - Is it a recompilation practice to have one exception handler in the application controller and catch the exceptions ? If not, what is the standard way ?
2 - How can I handle the Exceptions like Databse not found, doesn't have permission to view table fields, etc kind of low level exceptions
I'm riding on Rails 3 and I have some projects in Rails 2.3.8 as well
With according to Advanced Rails Recipes book by PragProg, the general exception handling is the good approach.
rescue_action (all environments), and rescue_action_in_public (production) are using to caught any exceptions in abstract controller class. So you do it right way.
Boot application happens before the controllers are loaded, so you can't handle database.yml over there. If you still need to do it, put an initializer ruby file to check that the file exist and a valid, then initialize AR::Base connection to perform DESC table for instance.
For Rails 3 you can use rescue_from in your ApplicationController. If the exceptions you want to catch are at a lower level then you can configure a Rack Middleware layer will allow you to catch exceptions that the controller does not have access to. This is how Hoptoad works. I recently released a rails 3 gem that will catch common exceptions using rescue_from and provide well defined http status codes and error responses for html, json and xml. This may or may not fit your needs. https://github.com/voomify/egregious

Rails: "Stack level too deep" error when calling "id" primary key method

This is a repost on another issue, better isolated this time.
In my environment.rb file I changed this line:
config.time_zone = 'UTC'
to this line:
config.active_record.default_timezone = :utc
Ever since, this call:
Category.find(1).subcategories.map(&:id)
Fails on "Stack level too deep" error after the second time it is run in the development environment when config.cache_classes = false. If config.cache_classes = true, the problem does not occur.
The error is a result of the following code in active_record/attribute_methods.rb around line 252:
def method_missing(method_id, *args, &block)
...
if self.class.primary_key.to_s == method_name
id
....
The call to the "id" function re-calls method_missing and there is nothing that prevents the id to be called over and over again, resulting in stack level too deep.
I'm using Rails 2.3.8.
The Category model has_many :subcategories.
The call fails on variants of that line above (e.g. Category.first.subcategory_ids, use of "each" instead of "map", etc.).
Any thoughts will be highly appreciated.
Thanks!
Amit
Even though this is solved, I just wanted to chime in on this, and report how I fixed this issue. I had the same symptoms as the OP, initial request .id() worked fine, subsequent requests .id() would throw an the "stack too deep" error message. It's a weird error, as it generally it means you have an infinite loop somewhere. I fixed this by changing:
config.action_controller.perform_caching = true
config.cache_classes = false
to
config.action_controller.perform_caching = true
config.cache_classes = true
in environments/production.rb.
UPDATE: The root cause of this issue turned out to be the cache_store. The default MemoryStore will not preserve ActiveRecord models. This is a pretty old bug, and fairly severe, I'm not sure why it hasn't been fixed. Anyways, the workaround is to use a different cache_store. Try using this, in your config/environments/development.rb:
config.cache_store = :file_store
UPDATE #2: C. Bedard posted this analysis of the issue. Seems to sum it up nicely.
Having encountered this problem myself (and being stuck on it repeateadly) I have investigated the error (and hopefully found a good fix). Here's what I know about it:
It happens when ActiveRecord::Base#reset_subclasses is called by the dispatcher between requests (in dev mode only).
ActiveRecord::Base#reset_subclasses wipes out the inheritable_attributes Hash (where #skip_time_zone_conversion_for_attributes is stored).
It will not only happen on objects persisted through requests, as the "monkey test app" from #1290 shows, but also when trying to access generated association methods on AR, even for objects that live only on the current request.
This bug was introduced by this commit where the #skip_time_zone_conversion_for_attributes declaration was changed from base.cattr_accessor to base.class_inheritable_accessor. But then again, that same commit also fixed something else.
The patch initially submitted here that simply avoids clearing the instance_variables and instance_methods in reset_subclasses does introduce massive leaking, and the amounts leaked seem directly proportional to complexity of the app (i.e. number of models, associations and attributes on each of them). I have a pretty complex app which leaks nearly 1Mb on each request in dev mode when the patch is applied. So it's not viable (for me anyways).
While trying out different ways to solve this, I have corrected the initial error (skip_time_zone_conversion_for_attributes being nil on 2nd request), but it uncovered another error (which just didn't happen because the first exception would be raised before getting to it). That error seems to be the one reported in #774 (Stack overflow in method_missing for the 'id' method).
Now, for the solution, my patch (attached) does the following:
It adds wrapper methods for #skip_time_zone_conversion_for_attributes methods, making sure it always reads/writes the value as an class_inheritable_attribute. This way, nil is never returned anymore.
It ensures that the 'id' method is not wiped out when reset_subclasses is called. AR is kinda strange on that one, because it first defines it directly in the source, but redefines itself with #define_read_method when it is first called. And that is precisely what makes it fail after reloading (since reset_subclasses then wipes it out).
I also added a test in reload_models_test.rb, which calls reset_subclasses to try and simulate reloading between requests in dev mode. What I cannot tell at this point is if it really triggers the reloading mechanism as it does on a live dispatcher request cycle. I also tested from script/server and the error was gone.
Sorry for the long paste, it sucks that the rails lighthouse project is private. The patch mentioned above is private.
-- This answer is copied from my original post here.
Finally solved!
After posting a third question and with help of trptcolin, I could confirm a working solution.
The problem: I was using require to include models from within Table-less models (classes that are in app/models but do not extend ActiveRecord::Base). For example, I had a class FilterCategory that performed require 'category'. This messed up with Rails' class caching.
I had to use require in the first place since lines such as Category.find :all failed.
The solution (credit goes to trptcolin): replace Category.find :all with ::Category.find :all. This works without the need to explicitly require any model, and therefore doesn't cause any class caching problems.
The "stack too deep" problem also goes away when using config.active_record.default_timezone = :utc

Resources