Debugging in Ruby with AppSignal
Tags: ruby
Published: 2022-09-28 14:38:08

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'](https://blog.appsignal.com/2021/12/01/ruby-on-rails-application-monitoring-with-appsignal.html).

## 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.

![Backtrace Section](https://blog.appsignal.com/images/blog/2022-09/backtrace.png)

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:

```ruby
# 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.

![error as log_level](https://blog.appsignal.com/images/blog/2022-09/error.png)

Now, check out the logs when we set `log_level` as `debug`.

![debug as log_level](https://blog.appsignal.com/images/blog/2022-09/debug.png)

Finally, let's see what happens when we set `log_level` as `trace`.

![trace as log_level](https://blog.appsignal.com/images/blog/2022-09/trace.png)

## 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.

```ruby
# 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.

```ruby
# 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.

```ruby
# 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.

```ruby
{:name=>"Customized Exception", :msg=>"A new exception occurred", :content=>#<NoMethodError: undefined method `object' for nil:NilClass>}
```

![Custom Exception](https://blog.appsignal.com/images/blog/2022-09/custom-exception.png)

## 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](https://docs.appsignal.com/ruby/instrumentation/exception-handling.html). [Check AppSignal's Ruby documentation](https://docs.appsignal.com/ruby/) 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](https://blog.appsignal.com/ruby-magic)!**