ruby

Getting Started with Custom Instrumentation in Rails Using AppSignal

Aestimo Kirina

Aestimo Kirina on

Getting Started with Custom Instrumentation in Rails Using AppSignal

Imagine debugging a performance issue in your Rails ecommerce app’s checkout process. The default logs display a vague "slow request," but this is insufficient to determine what's actually happening. You need to pinpoint exactly which database query, external API call, or background job is causing the bottleneck. More importantly, you need to understand the business impact: How many customers are abandoning their carts due to this issue? What's the revenue loss per minute?

Custom instrumentation with AppSignal for Ruby enables you to tag and measure these components in real time, providing both technical insights and business intelligence.

In this tutorial, we'll custom instrument a checkout flow in a Rails ecommerce app to create actionable insights for improving your app.

Prerequisites

Before diving into custom instrumentation, you'll need:

  • Ruby on Rails - A local installation of Ruby (version 3+ is recommended), and Rails (version 8+ is recommended).
  • Local database set up - Ensure you have SQLite 3 or PostgreSQL already installed on your local development machine.
  • AppSignal account - if you don't have one, you can sign up for a free trial.
  • Basic familiarity with Ruby and Ruby on Rails

Let's install the AppSignal gem in the example application — a simple Rails 8 ecommerce app. Fork the app's source code to follow along.

Installing AppSignal for Ruby

Open the Gemfile and add the line:

Ruby
# Gemfile ... gem "appsignal"

Then run bundle install to install the AppSignal for Ruby gem.

Next, run the command bundle exec appsignal install <YOUR_APPSIGNAL_API_KEY> in the terminal, which should run the install script and give you options to:

  • Choose your app's name as it should appear on the AppSignal dashboard.
  • Set configurations using a Ruby-based configuration file, an environment variable, or a YAML file (legacy method).

With the app properly configured and the test data sent, let's explore custom instrumentation in Rails for a better idea of why you need it in the first place.

Note: Find YOUR_APPSIGNAL_API_KEY in your AppSignal dashboard.

What Is Custom Instrumentation, and Why Do You Need It?

By default, AppSignal provides very good monitoring for Rails applications. It automatically tracks web requests, database queries, background jobs, and errors, which gives you a glimpse into your app's performance. However, when you're running a business-critical process like an ecommerce checkout flow, you need insights that go beyond the essentials. This is where custom instrumentation comes in.

Custom instrumentation is the practice of adding monitoring to specific parts of your application. It allows you to track interactions that wouldn't be automatically picked up by the AppSignal for Ruby integration. In the context of the ecommerce checkout example, this means tracking things like how long inventory validation is taking, when customers abandon their carts, which payment methods are failing more often, and so forth.

When both automatic and custom instrumentation are working together, you can expect a clearer picture of the overall health of your Rails application. This is from a technical standpoint that product and engineering teams might appreciate, and from a business-centered approach that makes marketing and other business teams happy.

In the following steps, you'll learn how to add custom instrumentation to the checkout flow of our example ecommerce app. You'll also learn some techniques for building custom dashboards to display the data tracked by the custom instrumentation.

Setting Up Custom Instrumentation

Before you implement any custom instrumentation, it's important that you understand that it should be applied strategically rather than all over your application. Adding custom instrumentation everywhere can lead to performance overheads due to overwhelming amounts of data, making it difficult to identify the metrics that actually matter.

Instead, focus on instrumenting:

  • Critical business processes - these can include checkout flows, payment processing, user registration, and so forth.
  • Areas that might suffer from performance issues - such as complex database operations or external API calls that might not be automatically tracked by the AppSignal for Ruby integration.
  • Areas where you need business intelligence data - these would include any events featuring customer conversions, feature adoption, or revenue-impacting operations.

This targeted approach ensures you get valuable insights that won't adversely impact your app's performance.

In the next section, you'll learn how to add custom instrumentation to our example app's checkout flow to collect data on how users navigate between pages.

Custom Instrumentation for a Checkout Flow: Tracking User Journeys

Understanding user behavior during the checkout process is important for both business success and technical optimization. From a business perspective, tracking how users go through your ecommerce flow helps identify conversion bottlenecks. From a technical standpoint, correlating user journey data with performance metrics reveals how technical issues directly impact business outcomes.

For example, if you notice users consistently dropping off at the billing information step, you can correlate this with technical metrics like page load times, errors, or API response times to see if technical issues are causing business losses. This combined perspective is essential for knowing which fixes will have the highest impact on both user experience and revenue.

Since user journey tracking and detailed pageview analytics aren't automatically captured by the AppSignal for Ruby integration, this makes user journey analysis an ideal use case for custom instrumentation.

In our Rails ecommerce app, we'll instrument the user's path through the checkout process — from product browsing to checkout. This will help you understand both the technical performance at each step and the business impact of any issues that arise during the customer's journey. But before going into the code, you should understand how the checkout flow happens in our example ecommerce app.

Note: To keep things simple, no payment flow has been implemented in the example app's checkout flow.

The Checkout Flow

In our example application, the checkout process starts with a shopper browsing through the store's products. When they find something they like, they add the product(s) to their cart:

Checkout flow - shopping for products

Next, the customer can decide to either clear their cart (they could also decide to navigate to another page without placing an order) or to proceed to checkout:

Checkout flow - adding a product to cart

A customer who wants to actually buy something will proceed to checkout, where they will input their billing information:

Checkout flow - adding a product to cart

And then "place an order" to complete the checkout flow:

Checkout flow - adding a product to cart

Now that you've seen the checkout flow from the user's perspective, you'll go through the code that powers this process and add custom instrumentation to collect metrics such as:

  • Page tracking - to understand where users are coming from and where they are going.
  • Cart behaviour tracking - to understand the user's interactions with the cart.

Once you have the custom instrumentation in place and it's collecting data as expected, you'll visualize the data in your AppSignal dashboard.

Let's start with instrumenting the user journey.

Tracking the User Journey

By instrumenting each step of the checkout process, you can identify exactly where users are dropping off and correlate these drop-offs with performance issues, errors, or specific user behaviors that impact conversion rates.

Since most of the user's journey happens within a browser session, you'll focus on instrumenting the relevant controllers. Instead of adding instrumentation code to every controller used in the user's journey, keep things organized by using a UserJourneyTracker controller concern and adding the custom instrumented code there:

Ruby
# app/controllers/concerns/user_journey_tracker.rb module UserJourneyTracker extend ActiveSupport::Concern included do before_action :track_page_view end private def track_page_view journey_step = { timestamp: Time.current, controller: controller_name, action: action_name, path: request.path, method: request.method, referrer: request.referrer, user_agent: request.user_agent, session_duration: session_duration, page_sequence: increment_page_sequence } ... # Track in AppSignal Appsignal.increment_counter( "user_journey.page_view", 1, { controller: controller_name, action: action_name, path: request.path, session_duration: session_duration, page_in_session: session[:journey_steps].length, has_cart_items: cart_items.any?, user_type: logged_in? ? "authenticated" : "guest" } ) end ... end

Here, you define a track_page_view method that tracks the pages the user is visiting as they shop on the site, the browser they are using, how long they stay on the site, and more. Then, you use an AppSignal.increment_counter to track the number of pages the user has viewed with additional context, like whether the user has any items in the cart, whether the user is logged in or not, and so forth, and send this data over to AppSignal.

You can then use this concern in the ApplicationController:

Ruby
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base include UserJourneyTracker ... end

Now, all controllers that inherit from the ApplicationController will also inherit the UserJourneyTracker functionality (for example, the ProductsController which controls the products index and show pages):

Ruby
# app/controllers/products_controller.rb class ProductsController < ApplicationController def index @products = Product.active.includes(images_attachments: :blob) @products = @products.by_category(params[:category]) if params[:category].present? @categories = Product.distinct.pluck(:category).compact end def show @product = Product.find(params[:id]) end end

And the CartController which controls the cart:

Ruby
# app/controllers/cart_controller.rb class CartController < ApplicationController include UserJourneyTracker def show @cart_items = cart_items.includes(:product) @cart_total = calculate_cart_total ... track_event("cart_viewed", enhanced_cart_metadata) end ... private def track_event(event_name, metadata = {}) base_metadata = { session_id: session.id.to_s, user_id: current_user&.id, timestamp: Time.current.iso8601, user_agent: request.user_agent, ip_address: request.remote_ip } # AppSignal custom metric for funnel tracking Appsignal.increment_counter("checkout_funnel.step", 1, { step: event_name, **base_metadata.merge(metadata) }) # Set gauge for tracking where the user is in the checkout flow Appsignal.set_gauge("checkout_funnel.current_step", funnel_step_value(event_name), { session_id: session.id.to_s }) end def enhanced_cart_metadata { cart_value: calculate_cart_total, item_count: cart_items.count, session_duration: session_duration, pages_in_session: session[:journey_steps]&.length || 0, user_type: logged_in? ? "authenticated" : "guest", hesitation_score: calculate_hesitation_score, journey_path: session[:journey_steps]&.last(5)&.map { |s| "#{s[:controller]}##{s[:action]}" }&.join(" → ") } end end

With that in place, you are now collecting some basic business metrics such as:

  • Session identifiers for tracking user sessions
  • User authentication status (whether the user is "authenticated" or browsing as a "guest")
  • The user's current position in the checkout flow
  • Browser and device information, and more

All this data is then sent over to AppSignal.

For technical error and performance metrics, you don't need to do much for now. These are collected automatically by the AppSignal for Ruby integration.

Next, you'll learn how to build a custom dashboard for the custom metrics you've added.

Building a Custom AppSignal Dashboard

Adding a custom dashboard on AppSignal is quite easy. To begin with, click on the "Add dashboard" button link in the left-side menu of your main dashboard:

Adding a custom dashboard - 1

Then, click on the "Create a dashboard" button in the screen that comes next:

Adding a custom dashboard - 2

Which brings up a "New dashboard" dialog:

Adding a custom dashboard - 3

Input a relevant title for your custom dashboard and create your dashboard.

With your new dashboard ready, click on the "Add graph" button in the new dashboard:

Adding a custom dashboard - 4

Finally, complete the new graph's settings:

Adding a custom dashboard - 5

For the new graph settings, you'll need to define:

  • Title - A title for your graph.
  • Description - You can give your graph a description if you want to.
  • Metrics - Here, you'll add the metrics that you defined when you set up your custom instrumentation. For example, you could add user_journey.page_view which was defined in Appsignal.increment_counter in the UserJourneyTracker concern.

Once everything is done, you should have a custom dashboard like the one shown below, displaying all the custom metadata you defined earlier:

Adding a custom dashboard - 6

With this dashboard, you are now able to visualize:

  • Navigational context - You get data on the controller that handled the request, for example, whether it's the "products" or "cart" controller, as well as the action within the controller, for example, "index", "show", or "create", "update" actions.
  • Session context - Like the user's authentication status, how long the user has been active (in seconds), or the number of pages in a session.
  • User behaviour context - For example, if the user has any items in their cart ("true" or "false").

It's now possible to correlate this user pageview data with other technical error and performance data automatically collected by AppSignal. This helps you get a fuller picture of how your app's performance affects a customer's journey and checkout patterns.

Wrapping Up

In this tutorial, you've implemented custom instrumentation in Rails with AppSignal, gaining deeper insights into your application's performance and business metrics. You started by setting up AppSignal in a Rails ecommerce application, then moved on to instrumenting a user's journey in the checkout flow.

Now you might consider taking custom instrumentation to the next level by applying similar steps to other critical flows in your application, such as user registration, payment processing, or feature adoption tracking.

Happy coding!

Wondering what you can do next?

Finished this article? Here are a few more things you can do:

  • Share this article on social media
Aestimo Kirina

Aestimo Kirina

Our guest author Aestimo is a full-stack developer, tech writer/author and SaaS entrepreneur.

All articles by Aestimo Kirina

Become our next author!

Find out more

AppSignal monitors your apps

AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!

Discover AppSignal
AppSignal monitors your apps