Debugging in Ruby with AppSignal
Brena Monteiro
Posted on September 28, 2022
An application monitoring tool (APM) is not just useful for seeing how your application performs through graphs and visuals. We can go deeper and use an APM to understand how your application behaves in a certain environment.
As developers, we should aim to be less reactive to errors and more predictive, avoiding crashes for end-users.
One way to accomplish this is by using monitoring tools to debug our application when an error occurs. AppSignal has advanced features that allow us to intelligently debug our logs and thus reflect this precautionary thinking in our applications.
This article will show you how to better log and debug your Ruby application using AppSignal.
Integrate Your Ruby App with AppSignal
To start debugging with AppSignal, you need to have an AppSignal account.
Integrate your Ruby application with AppSignal by following the steps in the article 'Ruby on Rails Application Monitoring with AppSignal'.
Log Options
Now that you have an application set up to send logs to AppSignal, let's look at the logging options for your Ruby application.
AppSignal offers various log levels for your application according to your project's needs. In this section, we will explore the difference between each log level.
At first glance, we might think these logs are related to the application logs shown in the 'Backtrace' section of AppSignal.
However, changes to log_level
won't reflect the information displayed in the backtrace. It is important to understand that setting the log_level
value relates to AppSignal's communication logs with your application. It has nothing to do with application logs.
This means that when we set the logging level in our application, we change the type of information that appears in the application logs about execution and integration with AppSignal.
In most cases, you can just set the log_level
to error (unless you've had an issue with the AppSignal integration and need to send log information to AppSignal's Support team). The log_level
must be defined in config/appsignal.yml
, as in the example below:
# config/appsignal.yml
production:
<<: *defaults
log_level: error
Watch the application logs when we set error
, warning
, or info
to log_level
. We will see pretty much the same information in the logs.
Now, check out the logs when we set log_level
as debug
.
Finally, let's see what happens when we set log_level
as trace
.
Ignore Your Ruby App's Predicted Errors in AppSignal
You don't need to catch and keep all errors in logs. Some common errors can be expected in an application — we don't need to inflate our logs with 404 errors, for example. Now let's configure AppSignal to ignore errors that are irrelevant to trace.
Ignoring an error is useful when a production bug has already been identified, but the fix is still in development. We already know about the problem's existence, so there's no need to keep filling the error monitoring tool or be notified about it. We can ignore the error's appearance until the patch deployment goes into production. This approach can be applied to all known bugs that have already been cataloged in the issues list.
We can also ignore errors when we know that a service our application communicates with will be down for maintenance. This way, we don't flood the monitoring tool with errors regarding expected maintenance, alerting our monitoring team unnecessarily.
AppSignal's gem provides three ways to handle and ignore predicted errors.
ignore_errors
ignore_errors
helps when you need to ignore all errors generated by a class error or when you don't know the exact error that could happen from there.
Maybe your application needs to do many math calculations, and AppSignal doesn't need to track all related errors. ignore_errors
will reduce the errors list and only keep issues that need to be addressed.
ignore_actions
This is useful if you know exactly which method will generate an error you don't need to trace — for example, a method that will be re-executed until it succeeds. You can also use ignore_actions
for queue processing when another monitoring tool handles logs specific to queue item failures.
ignore_namespace
ignore_namespace
is great if you have an application separated by domain and want to group errors. Maybe you have a specific module to treat payments or to process an order in the background. Grouping it in a namespace for jobs makes sense. Then you can ignore the exceptions that occur inside this namespace.
Configure in Your Ruby App
Include ignore_errors
, ignore_actions
, and ignore_namespace
in your config/appsignal.yml
file, with a list of classes to ignore when this error occurs in your application.
# config/appsignal.yml
production:
<<: *defaults
ignore_errors:
- Net::HTTPGatewayTimeout
- NoMethodError
ignore_actions:
- HomeController#index
ignore_namespace:
- jobs
- payment
Debugging Exceptions in Ruby with AppSignal
Now that we know how to ignore irrelevant errors, it's time to deal with the errors that matter. AppSignal provides functions to configure how an error is sent from your application to the AppSignal monitor. Let's learn about the listen_for_error
feature and extract valuable information from exceptions.
Sometimes, we have a situation where an exception may or may not be thrown due to some parameters (if a job is not running or even if an external endpoint is unavailable). We still want to send detailed information to AppSignal, not just the exception itself. For this case, we'll create a custom exception and use it to send helpful information to the monitoring team.
The first thing we need to do is create a class for our custom exception. Make a new folder called exceptions
inside your application directory. Then create a new class called CustomException
inherited from StandardError
. You can define any information as the content of this exception. By default, an exception already has msg
as an attribute.
In this example, you need to include an exception name
and the content
field to report all details about the exception. In the exception constructor, all attributes are set and the method to send to AppSignal is called.
The block inside Appsignal.listen_for_error
is where the magic happens! The raise will send the exception content to AppSignal in hash format to facilitate the separation of the different contents.
# app/exceptions/custom_exception.rb
class CustomException < StandardError
attr_accessor :name, :content
def initialize(name, msg, content)
@name = name
@msg = msg
@content = content
send_exception_to_appsignal
end
def send_exception_to_appsignal
Appsignal.listen_for_error do
exception_hash = { name: @name, msg: @msg, content: @content }
raise "#{exception_hash}"
end
end
end
Now you can call this custom exception from anywhere, to use it in your application. For this example, we will include it in the controller inside the Home#index
method. We need a block to handle the exception, to avoid sending it to AppSignal. The nil.object
code will throw a NoMethodError
exception, but this exception is handled, and only CustomException
will be sent to AppSignal.
# app/controllers/home_controller.rb
class HomeController < ApplicationController
def index
begin
nil.object
rescue => e
raise CustomException.new("Customized Exception", "A new exception occurred", e)
end
end
end
All done! After starting your application and accessing http://localhost:3000/home#index in your browser, you will see a page with a RuntimeError
exception. In AppSignal, access the 'Errors > Issue list' to see the Customized Exception issue.
{:name=>"Customized Exception", :msg=>"A new exception occurred", :content=>#<NoMethodError: undefined method `object' for nil:NilClass>}
Wrap Up and Next Steps
AppSignal provides a well-documented gem to start truly monitoring your Ruby application. Why not test it? Send data from your local machine without deploying to see if the error configuration is how you want it.
Many other features in AppSignal make it easier to debug Ruby applications, like exception handling. Check AppSignal's Ruby documentation and choose the feature that makes the most sense in your project's context. Make your app easier to debug by decreasing the time your team needs to spend looking into the root cause of bugs in production.
Happy debugging!
P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, subscribe to our Ruby Magic newsletter and never miss a single post!
Posted on September 28, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.