-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
226: Application Performance Monitoring with Scout or New Relic
A few years ago, I was on call for a Ruby on Rails app that handled a decent amount of traffic. Around 2:00 PM on a Tuesday, our Slack alerts started screaming. Users were complaining that the "Order History" page was taking ten seconds to load, but only for some of them. I jumped into the production logs, and everything looked... fine. Every request was returning a 200 OK. I tried to reproduce it in staging, but my test account only had three orders, so the page loaded in 50ms. I spent three hours guessing and checking, digging through controllers and views, before I realized that one specific power user had 4,000 orders, and we had a hidden N+1 query in a helper method that was firing a database call for every single row in that table.
That was the day I stopped relying solely on logs and started using Application Performance Monitoring (APM). When you're running Ruby in production, you're essentially flying a plane; logs are like your altimeter, but an APM tool is your entire radar system. It tells you not just that the plane is slowing down, but exactly which engine is failing and why.
Seeing Beyond the Rails Log
Standard logging tells you that a request happened and how long it took in total. But in a complex Ruby app, a "slow request" is a vague symptom. Was it a slow SQL query? Was it a sluggish external API call to Stripe or Twilio? Or was it just a computationally expensive piece of Ruby code looping over a massive array? This is where tools like Scout or New Relic come in.
These tools use "instrumentation." When you add their gem to your Gemfile, they hook into the Ruby runtime and the Rails middleware. They wrap around your database adapter and your HTTP clients. This means every time your app calls ActiveRecord or Net::HTTP, the APM tool records exactly how long that specific call took and associates it with the current web request. Instead of guessing, you get a "trace"—a waterfall chart showing that of your 10-second request, 9.2 seconds were spent in a single SELECT statement.
Hunting N+1s and Bottlenecks in Production
One of the biggest wins with APM—especially with a tool like Scout—is the automatic detection of N+1 queries. We've all learned about includes and joins in earlier lessons, but it's easy to miss one in a complex view partial. Scout, for instance, monitors your production traffic and flags exactly which line of code is triggering a loop of queries. It doesn't just say "you have an N+1"; it tells you "this specific action is calling this query 100 times per request."
I also want you to stop looking at "Average Response Time." Averages are a lie in software engineering. If nine users have a 100ms experience and one user has a 10-second experience, your average is roughly one second. That doesn't accurately describe anyone's experience. APM tools give you percentiles—specifically p95 and p99. If your p95 is high, it means 5% of your users are having a miserable time. That's the number you should be optimizing for.
Choosing Between Lightweight and Enterprise Monitoring
You'll generally see two paths here: the "comprehensive" route and the "focused" route. New Relic is the industry giant. It provides deep JVM/Ruby metrics, server health, browser monitoring, and complex alerting. It's incredibly powerful, but it can be overwhelming—and expensive—for a small team. You can spend hours just configuring the dashboard.
Scout takes a different approach. It focuses heavily on the developer experience, specifically targeting the things that kill Rails apps: N+1s and slow endpoints. It’s generally easier to set up and gets you to the "aha!" moment faster. If you're a solo dev or in a small startup, I usually recommend starting with something lightweight. You don't need a cockpit with 50 dials if you only need to know why your database is screaming.
📋 Practical Task
Exercise: Finding the Ghost in the Machine
In this exercise, you will simulate a production performance leak and use an APM tool to identify the culprit. Since you likely don't have a high-traffic production site, you will use a local environment to generate "bad" data.
- The Setup: Create a simple Rails application with a
Usermodel and aPostmodel (one-to-many). Create a seed file that generates 10 users, each with 500 posts. - The Leak: Create a controller action called
#indexthat renders a list of users and their last post's title. Intentionally write this using an N+1 pattern (e.g., callinguser.posts.last.titleinside a loop in the view without usingincludes). - The Implementation: Sign up for a free trial of Scout or New Relic. Add the respective gem to your
Gemfile, runbundle install, and configure the API key in your environment variables as per the tool's documentation. - The Hunt: Start your server and refresh the index page a few times. Log into your APM dashboard and locate the "Slowest Transactions" or "N+1" section.
- The Fix: Use the trace provided by the tool to find the exact line in your view or controller causing the issue. Fix it using
.includes(:posts)and verify in the APM dashboard that the query count for that action has dropped from N+1 to a constant number.
There are no comments for now.