Introduction
APM tools provide continuous visibility into production performance — tracking response times, error rates, and throughput over time. While profiling is for finding specific bottlenecks, monitoring is for detecting when things go wrong.
Key Concepts
- APM (Application Performance Monitoring): Tools like New Relic or Scout that track production performance metrics continuously.
- Percentiles (p50, p95, p99): Response time metrics showing what percentage of requests complete within that time. p99 = 99% of requests are faster than this value.
- Apdex Score: A standardized metric (0-1) measuring user satisfaction based on response time thresholds.
Real World Context
Your average response time might be 200ms, but p99 could be 8 seconds. Without monitoring percentiles, a bad experience for 1% of users — potentially thousands per day — goes undetected.
Deep Dive
Key Metrics to Track
- Response Time: p50, p95, p99 percentiles
- Throughput: Requests per minute
- Error Rate: Percentage of 5xx responses
- Database Time: Time spent in SQL queries
- Queue Latency: How long background jobs wait before processing
New Relic Setup
ruby# Gemfile gem 'newrelic_rpm'
yaml# config/newrelic.yml production: license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %> app_name: My Rails App
Health Check Endpoint
rubyclass HealthController < ApplicationController skip_before_action :authenticate_user! def show checks = { database: check_database, queue: check_solid_queue } status = checks.values.all? ? :ok : :service_unavailable render json: checks, status: status end private def check_database ActiveRecord::Base.connection.execute('SELECT 1') true rescue StandardError false end def check_solid_queue SolidQueue::Job.where(finished_at: nil).count true rescue StandardError false end end
Custom Metrics with StatsD
rubyclass OrdersController < ApplicationController def create start_time = Time.current @order = Order.create!(order_params) StatsD.increment('orders.created') StatsD.timing('orders.create_time', Time.current - start_time) rescue => e StatsD.increment('orders.failed') raise end end
Common Pitfalls
- Only tracking averages — Averages hide outliers. Track p95 and p99 to catch performance issues affecting a minority of users.
- Not monitoring queue latency — A healthy web server with a backed-up job queue means emails aren't sending and imports aren't processing.
Best Practices
- Set up alerts on p95 response time — Alert when p95 exceeds your SLA threshold (e.g., 2 seconds).
- Monitor database connection pool — Track active and waiting connections to detect pool exhaustion before it causes errors.
Summary
- APM tools provide continuous production performance visibility.
- Track percentiles (p50, p95, p99), not just averages.
- Monitor both web response times and background job queue latency.
- Set up health check endpoints for load balancers and uptime monitoring.
Code Examples
ruby
# Health check endpoint for load balancers
class HealthController < ApplicationController
skip_before_action :authenticate_user!
def show
ActiveRecord::Base.connection.execute('SELECT 1')
head :ok
rescue StandardError
head :service_unavailable
end
end
# config/routes.rb
get '/health', to: 'health#show'