Monitor the Performance of Your Ruby on Rails Application Using AppSignal
Tags: ruby, rails, apm, appsignal
Published: 2024-06-26 12:00:00

In the first part of this article series, we deployed a simple Ruby on Rails application to DigitalOcean's app platform. We also hooked up a Rails app to AppSignal, seeing how simple errors are tracked and displayed in AppSignal's Errors dashboard.

In this part of the series, we'll dive into how to set up the following for your Ruby on Rails application using AppSignal:

- Performance monitoring
- Rails background jobs monitoring, including how to monitor simple API calls
- Logging
- Notification alerts

Let's get into it!

## Monitoring Rails App Performance Using AppSignal

When your uptime monitor shows that your app is up, it may be tempting to think that everything is okay. But, in reality, trouble could be brewing under the hood in the form of slow processes, unoptimized database queries, and long-running service calls.

This is a very important matter when you consider that there's a [correlation between slow-loading web pages and a low visitor conversion rate](https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/mobile-page-speed-conversion-data/). In a nutshell, those slow-running processes will cost you a lot if left unchecked. But with so many moving parts to a Ruby on Rails app, the important questions are: what should you look for, and where?

That's where AppSignal comes into play. Let's look at how you can use AppSignal to keep track of your Rails app's performance.

### Tracking Response Times

From the default dashboard, AppSignal provides two graphs that can give you a quick overview of how slow (or fast) your Rails app is running: the _Throughput_ and _Response time_ graphs.

![Rails performance tracking with Appsignal](https://blog.appsignal.com/images/blog/2024-06/appsignal-performance-tracking-dashboard.png)

- **Throughput** - This basically measures how many requests per second your app is currently processing (not to be confused with how many requests per second your app can handle overall). The basic rule of thumb is: the more requests per second, the better. However, if your app server handles too many requests per second, it might be time to scale your server resources to handle this.
- **Response time** - The average time a browser response takes in milliseconds. The more time a response takes, the worse your app is running. A good rule of thumb here is that if your Rails web app has sub-100ms response times, you can consider it fast, while 300ms+ response times can be considered slow.

Now, let's say we want to track our app's response times and throughput over a seven-day window. That's very easy to do — just go to the _Graphs_ sub-menu under _Performance_ located on the left-side menu, then use the time filter buttons on top of the graphs, as shown below:

![Performance graphs](https://blog.appsignal.com/images/blog/2024-06/appsignal-performance-graphs.png)

With that, you can easily see if your app runs slow on some days compared to others.

While on this view, it's also important to check out the _Event groups_ graph, located below the _Response time_ and _Throughput_ graphs:

![Event groups breakdown](https://blog.appsignal.com/images/blog/2024-06/event-groups-breakdown.png)

This graph gives you details on how fast or slow your app is running in the controller layer and the view layer. From here, you can find out what's causing slow response times and fix the issues accordingly.

Let's now switch gears to tracking database queries using AppSignal.

### Tracking Database Queries

It is generally true that you can squeeze a lot more speed from your app by optimizing response times and throughput. However, more often than not, slow, unoptimized database queries are the worst offenders when it comes to sluggish app behavior.

Let's take an example of the infamous N+1 query. In the [expense tracker app](https://github.com/iamaestimo/expense-tracker) introduced in part 1, the index method in the expenses controller looks like this:

```ruby
# app/controller/expenses_controller.rb

class ExpensesController < ApplicationController
  ...
  def index
    @expenses = Expense.all
  end
  ...
end
```

This might look innocent, but if you take a look at the _Issues_ list in your AppSignal dashboard, you'll see something interesting:

![N+1 Query issue](https://blog.appsignal.com/images/blog/2024-06/n1-query-issue-list.png)

An N+1 query has been highlighted in the expenses controller's index method.

If we dig further by clicking on the issue link, we get to an _Issue details_ screen like this:

![Slow query explanation](https://blog.appsignal.com/images/blog/2024-06/slow-query-explanation.png)

Notice how AppSignal offers an explanation of the issue, including a link to a more detailed blog post showing you how to deal with it.

Let's move on and learn how AppSignal helps you out with background jobs.

### Keeping Track of Rails Background Jobs with AppSignal

Background jobs are a common feature in many production Ruby on Rails applications, with a variety of job queue processing gems and libraries for you to choose from.

AppSignal supports tracking and monitoring various background job processing libraries, including Sidekiq, Que, Delayed Job, Resque, and others.

Let's say we want a feature where users get daily currency exchange rates in their dashboard.

For this to work, we need an API call to a service providing such rates (we'll use one that doesn't require too much upfront configuration or payment, like [this one](https://www.exchangerate-api.com/docs/free), to fetch currency rates). We also need a background job to queue the call to this service at regular intervals.

The background processing gem we'll use in the expense tracker app is [GoodJob](https://github.com/bensheldon/good_job), but you're free to use whatever suits you.

Let's create a background job to fetch rates:

```ruby
# app/jobs/fetch_rates.rb
...
class FetchRates < ApplicationJob
  self.queue_adapter = :good_job

  def perform
    # fetch rates
    response = HTTParty.get('https://open.er-api.com/v6/latest/USD')

    if response['result'] == "success"
      Rate.create(
        base_rate_name: response['base_code'],
        eur: response['rates']['EUR'],
        cad: response['rates']['CAD'],
        aud: response['rates']['AUD'],
        gbp: response['rates']['GBP']
        )
    end
  end
end
```

And then set GoodJob to run a cron for this job every few minutes (or however you see fit). AppSignal automatically detects the presence of the background service and includes a nifty filter so you can separate it from the default web dashboards:

![Background jobs dashboard](https://blog.appsignal.com/images/blog/2024-06/background-jobs-dashboards.png)

Without the need for much tooling upfront, AppSignal will also detect API calls and keep track of any issues:

![Slow events](https://blog.appsignal.com/images/blog/2024-06/background-jobs-slow-events.png)

If you want to dive deeper into monitoring Rails background jobs with AppSignal, I recommend you [check out the documentation](https://docs.appsignal.com/ruby/integrations/active-job.html). For now, let's turn our attention to uptime monitoring.

## Uptime Monitoring

Another matter that concerns many Rails developers is the continuous availability of their application for end users. Any downtime might mean loss of revenue and have other negative consequences.

Even so, you wouldn't want to poll the uptime status of your app manually. You can set up uptime monitoring using AppSignal.

Setting it up is a breeze. Begin by clicking on the _Uptime monitoring_ link in the left-side menu.

Then, when you click on the _create uptime monitor_ button, you should get a dialog similar to the one shown below:

![Create uptime monitor - one](https://blog.appsignal.com/images/blog/2024-06/uptime-monitor-1.png)
![Create uptime monitor - two](https://blog.appsignal.com/images/blog/2024-06/uptime-monitor-2.png)

Complete your uptime monitor by adding the most important settings:

- **Name** - Give your uptime monitor an appropriate name.
- **URL** - Provide the full URL to the uptime route. Beginning with Rails 7.1, the default uptime route is _https://your-app-domain/up_.
- **Region** - Select the regions where you want to check for uptime.
- **Notification** - Choose the notification channel/s to receive alerts on.

With that done, go ahead and create the monitor!

One thing to note with the AppSignal uptime monitor is that since polling is done almost every minute or so, it's very easy to hit your plan's limits. But there's a very good workaround to this which you can read more about [in their docs](https://docs.appsignal.com/uptime-monitoring/setup.html).

Before moving on to how AppSignal can help with logging, there's another important feature to complete the uptime monitoring layer: free [public status pages](https://docs.appsignal.com/uptime-monitoring/public-status-page.html#set-up).

Click on the _creating a public status_ page link as shown below:

![Creating a public status page - step 1](https://blog.appsignal.com/images/blog/2024-06/public-status-page-1.png)

Then click on the _New status page_ button, bringing you to this:

![Creating a public status page - step 3](https://blog.appsignal.com/images/blog/2024-06/public-status-page-3.png)

![Creating a public status page - step 4](https://blog.appsignal.com/images/blog/2024-06/public-status-page-4.png)

Go ahead and fill in all the required information. Note that if you use a custom domain, you'll need to add a CNAME directive pointing to `cname.appsignal-status.com` in your custom domain's DNS settings.

## Logging with AppSignal

Logging is a relatively new feature in AppSignal, but one that is timely and welcome. Using AppSignal, you don't have to run application monitoring and logging as separate services.

To get started with logging, make sure you are running the latest version of the AppSignal gem. If you have an older version of the gem, update it with:

```shell
bundle update appsignal
```

Then create a new initializer and edit it like so:

```ruby
# config/initializers/appsignal_logging.rb

appsignal_logger = Appsignal::Logger.new("rails")
Rails.logger.broadcast_to(appsignal_logger)
```

Now you can access your app's logs like so:

![Logging dashboard](https://blog.appsignal.com/images/blog/2024-06/logging-dashboard.png)

Notice that you also get a nice filter to filter log records by severity, as well as access to live logs.

You can go through [AppSignal's logging for Ruby documentation here](https://docs.appsignal.com/logging/platforms/integrations/ruby.html).

## Other Notable Features

There are a couple of other notable features you can use in AppSignal: anomaly detection and custom metrics.

### Anomaly Detection

Let's say you are concerned with your app running out of memory. You can easily set up a trigger that sends an email notification if your app has a notable drop in available memory.

Go to the _Anomaly detection_ link and create a new trigger, then configure it:

![Trigger for low memory](https://blog.appsignal.com/images/blog/2024-06/trigger-for-low-memory.png)

- **Metric** - In my case, I am interested in memory usage, but you could choose any other metric that is specific to your use case.
- **Trigger details** - Here, you'll configure the details relevant to your trigger. In my case, the trigger will fire if the host memory goes below 200MB.

### Custom Metrics

AppSignal also gives you the tools to capture and visualize custom metrics. This feature alone warrants an entire article. You can read all about it in [How to Monitor Custom Metrics with AppSignal](https://blog.appsignal.com/2023/04/26/how-to-monitor-custom-metrics-with-appsignal.html) and [check out AppSignal's docs](https://docs.appsignal.com/metrics/custom.html) too.

## Wrapping Up

In part one of this article series, we set up a Rails app hosted on DigitalOcean and monitored it for errors using AppSignal.

In this second and final part, we looked at some of AppSignal's great features for your Rails app, including performance monitoring, uptime monitoring, logging, and more.

There's so much more to AppSignal than could effectively be covered by this article series. I highly encourage you to check it out for your Rails app.

Happy coding!

**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)!**