In the first of this two-part series, we covered how to set up AppSignal in a Ruby on Rails application for many great insights out of the box. AppSignal can automatically track errors, monitor performance, and report metrics about some dependencies.
But, in many cases, each of our applications behaves in different ways, so we'll want more than just generic monitoring.
In this post, we will run through adding custom instrumentation and monitoring to a Ruby on Rails application. This will give you deeper insights into how your application is behaving.
Prerequisites if you want to follow along with the code:
- An account on www.appsignal.com
- Docker installed and running (to use
docker-compose
)
To follow along with this post, you will need to set up AppSignal in the sample application with your own AppSignal account.
Custom Instrumentation and Monitoring
When you need more than what AppSignal instruments out of the box, the AppSignal gem allows you to add custom instrumentation to your Rails application.
Instrumenting Parts of the Code
Let's say you want to add a new feature to an application. When a user visits
/posts
to view all posts, they should be able to filter for posts where
the title begins with a specific letter (or something a lot more complex 🪄).
This new search functionality has already been implemented in the Post
model
with the method Post.where_title_starts_with
. Let's update
the PostsController#index
to use the new method if a specific query parameter
is present:
This is such a core part of your application that you'll want to know how it performs and when that performance changes. AppSignal provides a few ways to do this.
First, we will instrument the contents of the Post.where_title_starts_with
method. If you want to receive insights about any code blocks, you can use instrumentation blocks to
wrap the code blocks. Update the method
like this:
Secondly, we also want to instrument the Analytics.track_post_title_search
method being called because
app/services/analytics.rb
is doing some heavy processing. In this case, we
will use method instrumentation
to instrument the entire method more accurately:
Insights
A few minutes after saving the above to the application, take a look at whatever new information is available on your AppSignal dashboard (if you don't see the information, you may need to restart the docker containers again). You can verify that the new feature works by visiting the posts index page with a search param: http://localhost:3000/posts?starts_with=f
Depending on the number of posts created in the database, the
/posts
endpoint will have become a lot slower.
If you open up performance issues on AppSignal ('Performance' -> 'Issue
list') and view the PostsController#index
action, lower down on the page, you
should be able to see an 'Event Timeline'. This gives you a breakdown of how
much time is spent running specific code:
This timeline exists for all performance events, but
here, we can also see the custom instrumentation
events. It shows us that calling Post.where_title_starts_with
took
8.84 seconds to run, with 2.01 seconds used up by the
Analytics.track_post_title_search
method, and the remaining time used up by an
active record query. You can also click into
individual events for further investigation and see more information about their performance — e.g. the sql.active_record
event.
AppSignal's instrumentation helpers give you a more detailed breakdown of the application code, so it's easier to gain insights into particular pieces of code that you think could impact an application's performance. You can learn more about this in AppSignal's instrumentation guide.
Exception Handling
Besides monitoring the performance of your code, you also need to know when the application doesn't behave as expected and where things go wrong. We've already seen how AppSignal reports exceptions that have not been handled by our code. But there's always a bit more than what comes out of the box.
You can start by removing existing code that causes an intermittent error. We
see where this error occurs in the backtrace when viewing the error on
the dashboard. Inside of app/controllers/pages_controller.rb
remove the if
statement:
Now, in the overview dashboard, the application's error rate will drop significantly.
Currently, when a user tries to view a post that doesn't exist, the application
crashes — e.g.,
http://localhost:3000/posts/doesnotexist.
Instead, you might want to show them a message. Add a
rescue to where this could happen inside the PostsController
. Update the
#set_post
method:
Because we are manually handling the exception, it
won't automatically be reported to AppSignal. You can still track errors
manually by using Appsignal.set_error
.
The easiest way to track an error is to simply add it as the function's only argument like Appsignal.set_error(e)
. We also want to take advantage
of the ability to add more context to the request. AppSignal allows you to tag
events with your own arbitrary information using Appsignal.tag_request
:
Now visit http://localhost:3000/posts/doesnotexist to verify that you get back the JSON response as expected, instead of having the application crash.
Insights
After you try to view a post that does not exist, the added updates ensure that the errors are reported to AppSignal.
On the AppSignal dashboard, in 'Errors -> Issue
list', find and view the new reported error
(ActiveRecord::RecordNotFound
).
The error detail page gives us useful context about the error, which by default, includes information about the request such as the HTTP method, parameters, and session data. You can see that the custom tags are also included, which gives you the ability to filter for all of the errors with a matching tag.
Because we tagged the request, it adds this information to errors and other instrumented events. If you view an individual post a few times, e.g., http://localhost:3000/posts/1, you will notice that the tags are also included when you look at the performance measurement ('Performance' -> 'Issue list' -> 'PostsController#show'). You can read more about tagging transactions in the guides.
This ability to add custom metadata to the transaction opens up many opportunities to help diagnose issues in production. A great example of this is adding Kubernetes metadata to your errors.
Metrics
Now that there is some custom instrumentation and error monitoring in place, you might
realize that sometimes, there are large spikes in posts searches. Whenever a
user searches, Analytics#track_post_title_search
is called, which does some calculations and makes an API call to a third-party service.
This third party has rate limits on the API. We want to track how often it is
called to keep an eye on how close the application is to its
limits.
AppSignal allows you to track custom metrics throughout the application as you wish.
First, we will track how often we're calling our analytics service and with what data, using a counter and tags:
Secondly, we will also track the number of posts being returned in the
PostsController#index
, because this is a core part of the application's
behavior, and we know it keeps growing:
The fake traffic script still running on the application will generate some data, but to add more variety, let's also search for posts starting with f, l, and v.
Insights
To view the custom metrics, you will need to create a dashboard with custom graphs on AppSignal. This can be done through the UI, but we will just import one for this example. Under the 'Dashboard' section, click on 'Add dashboard' and import a dashboard with the following:
You should see data on your graphs within a few minutes. Hovering over the lines shows you a legend of the metrics collected within the timeframe you're viewing.
Notice that this shows different lines for each tag value. Currently, our fake
traffic is only searching for the letter e
, but because we manually searched
for other letters, you will see a new line on the graph for each one to indicate
another data point.
Thought that was enough? AppSignal has more custom instrumentation solutions to offer that we won't be covering here. One that's worth a quick mention is breadcrumbs. Breadcrumbs allow you to track a list of actions in your application, which will then be reported in an error. You'll have even more specific and ordered information about what led up to an error.
Read all about custom instrumentation in the guides.
Wrap-up: Custom Instrumentation and Monitoring for Ruby Apps with AppSignal
Part 1 of this series covered the basic setup and use of AppSignal for your Ruby applications.
In this part, we've taken an application that already has great out-of-the-box monitoring and made it even better using the AppSignal gem.
AppSignal's custom instrumentation, error tracking, and performance monitoring features give you the insights you need into how your applications are behaving. It gives your application a lot out of the box while letting you take control when needed.
It's time to let your code run free in the wild, as long as you keep an eye on how it's doing. 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!