RailsActionTracker
A Rails gem that tracks ActiveRecord model operations and service usage during controller action execution. See what your Rails actions are doing under the hood.
Installation
Add to your Gemfile:
gem 'rails_action_tracker'
Install and generate configuration:
bundle install
rails generate rails_action_tracker:install
Start your Rails server and see the output:
UsersController#show - Models and Services accessed during request:
+-------------------+-------------------+-------------------+
| Models Read | Models Written | Services Accessed |
+-------------------+-------------------+-------------------+
| users | user_sessions | Redis |
| posts | audit_logs | Sidekiq |
| comments | | ActionMailer |
+-------------------+-------------------+-------------------+
Configuration
The gem works with sensible defaults out of the box. The generated initializer provides full configuration options:
# config/initializers/rails_action_tracker.rb
RailsActionTracker::Tracker.configure(
print_to_rails_log: true, # Print to Rails logger (default: true)
write_to_file: false, # Write to separate file (default: false)
log_file_path: Rails.root.join('log', 'action_tracker.log'),
# Output format controls (new in v0.2.0+)
print_format: :table, # Format for console/Rails log: :table, :csv, :json
log_format: :table, # Format for log file: :table, :csv, :json
# Custom services to track (optional)
services: [
{ name: 'Redis', pattern: /redis/i },
{ name: 'Sidekiq', pattern: /sidekiq/i },
{ name: 'CustomAPI', pattern: /custom_api/i }
],
# Tables to ignore (optional)
ignored_tables: ['audit_logs', 'session_data']
)
Output Formats
๐จ New in v0.2.0+: The gem now supports different output formats and allows you to configure separate formats for console output and file logging.
Available Formats
-
:table
- Clean tabular format (default) -
:csv
- CSV format with dynamic headers -
:json
- JSON format with different behaviors for print vs log
Format Configuration
RailsActionTracker::Tracker.configure(
print_format: :table, # Format for console/Rails log output
log_format: :json, # Format for log file output (can be different!)
print_to_rails_log: true, # Enable console output
write_to_file: true, # Enable file logging
log_file_path: Rails.root.join('log', 'action_tracker.json')
)
Format Examples
Table Format (:table)
UsersController#show - Models and Services accessed during request:
+-------------------+-------------------+-------------------+
| Models Read | Models Written | Services Accessed |
+-------------------+-------------------+-------------------+
| users | user_sessions | Redis |
| posts | audit_logs | Sidekiq |
+-------------------+-------------------+-------------------+
CSV Print Format (:csv for console)
Action,users,posts,user_sessions,Redis
UsersController#show,R,R,W,Y
CSV Log Format (:csv for file - accumulative)
Action,Elasticsearch,Redis,Sidekiq,posts,profiles,sessions,users
UsersController#show,Y,Y,-,R,R,W,RW
PostsController#create,-,-,Y,RW,-,-,R
JSON Print Format (:json for console)
UsersController#show: {
"read": ["users", "posts"],
"write": ["user_sessions", "audit_logs"],
"services": ["Redis", "Sidekiq"]
}
JSON Log Format (:json for file - accumulative)
{
"UsersController#show": {
"read": ["users", "posts"],
"write": ["user_sessions"],
"services": ["Redis"]
},
"UsersController#update": {
"read": ["users", "posts"],
"write": ["users", "audit_logs"],
"services": ["Redis", "Sidekiq"]
}
}
Format Behavior Differences
Both JSON and CSV formats behave differently for print vs log:
JSON Format:
- JSON Print (console): Shows only current action data in clean format
- JSON Log (file): Accumulates all actions in a persistent structure, merging new data when the same action is visited again
CSV Format:
- CSV Print (console): Shows only current action data with compact headers
- CSV Log (file): Accumulates all actions in a single CSV file with dynamic headers that expand as new tables/services are encountered. When the same action is visited again, access patterns are merged intelligently (e.g., R + W = RW)
Table Format:
- Table Print (console): Shows current action data in formatted table
- Table Log (file): Each action logged separately in table format (no accumulation)
Configuration Options
Basic Configuration
RailsActionTracker::Tracker.configure(
print_to_rails_log: true, # Print to Rails logger (default: true)
write_to_file: false, # Write to separate file (default: false)
log_file_path: nil, # Path to separate log file (required if write_to_file: true)
print_format: :table, # Format for console output: :table, :csv, :json
log_format: :table, # Format for file output (defaults to print_format)
ignored_tables: [], # Tables to ignore from tracking (optional)
ignored_controllers: [], # Controllers to completely ignore (optional)
ignored_actions: {} # Specific controller#action combinations to ignore (optional)
)
Configuration Examples
Option 1: Only log to Rails logger (default)
RailsActionTracker::Tracker.configure(
print_to_rails_log: true,
write_to_file: false
)
Option 2: Only log to separate file
RailsActionTracker::Tracker.configure(
print_to_rails_log: false,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.log')
)
Option 3: Log to both Rails logger and separate file
RailsActionTracker::Tracker.configure(
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.log')
)
Format Configuration Examples
Option 4: Different print and log formats
RailsActionTracker::Tracker.configure(
print_format: :json, # Console shows clean JSON for current action
log_format: :csv, # File saves in CSV format for analysis
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.csv')
)
Option 5: JSON accumulation for analysis
RailsActionTracker::Tracker.configure(
print_format: :table, # Console shows familiar table format
log_format: :json, # File accumulates JSON data across requests
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.json')
)
Option 6: CSV accumulation for spreadsheet analysis
RailsActionTracker::Tracker.configure(
print_format: :table, # Console shows table
log_format: :csv, # File accumulates CSV with dynamic columns
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.csv')
)
Results in accumulated CSV like:
Action | Redis | Sidekiq | posts | profiles | users |
---|---|---|---|---|---|
UsersController#show | Y | - | R | R | RW |
PostsController#create | - | Y | RW | - | R |
Option 7: CSV print and CSV log (different behaviors)
RailsActionTracker::Tracker.configure(
print_format: :csv, # Console shows current action CSV
log_format: :csv, # File accumulates all actions with smart merging
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.csv')
)
Print behavior: Shows only current action's CSV data with minimal headers
Log behavior: Accumulates all actions with expanding headers and intelligent merging
Option 8: JSON everywhere with different behaviors
RailsActionTracker::Tracker.configure(
print_format: :json, # Console: current action JSON only
log_format: :json, # File: accumulative JSON structure
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.json')
)
Custom Service Detection
You can customize which services are detected by providing custom patterns:
RailsActionTracker::Tracker.configure(
print_to_rails_log: true,
services: [
{ name: "Redis", pattern: /redis/i },
{ name: "CustomAPI", pattern: /custom_api|my_service/i },
{ name: "PaymentGateway", pattern: /stripe|paypal/i }
]
)
Ignoring Tables
You can specify tables to ignore from tracking (useful for system tables, audit logs, etc.):
RailsActionTracker::Tracker.configure(
print_to_rails_log: true,
ignored_tables: [
'pg_attribute', # PostgreSQL system tables
'pg_index',
'pg_class',
'ar_internal_metadata', # Rails internal tables
'schema_migrations',
'audit_logs', # Your custom tables to ignore
'session_data'
]
)
Default ignored tables:
-
pg_attribute
,pg_index
,pg_class
,pg_namespace
,pg_type
(PostgreSQL system tables) -
ar_internal_metadata
,schema_migrations
(Rails internal tables)
Ignoring Controllers and Actions
You have flexible options for ignoring controllers and actions to reduce noise:
Simple Controller Ignoring
RailsActionTracker::Tracker.configure(
# Ignore entire controllers (all actions)
ignored_controllers: [
'Rails::PwaController', # Ignore PWA controller completely
'HealthCheckController', # Ignore health check controller
'Assets::ServingController'
]
)
Basic Action Ignoring
RailsActionTracker::Tracker.configure(
# Ignore specific controller#action combinations
ignored_actions: {
'ApplicationController' => ['ping', 'status'], # Ignore specific actions
'ApiController' => ['heartbeat'], # Multiple controllers
'AdminController' => ['dashboard_stats'] # can have ignored actions
}
)
Advanced Flexible Action Ignoring
The ignored_actions
configuration supports flexible patterns:
1. Ignore entire controller by providing empty actions array:
RailsActionTracker::Tracker.configure(
ignored_actions: {
'Rails::PwaController' => [], # Empty array = ignore entire controller
'HealthController' => nil # nil = ignore entire controller
}
)
2. Ignore specific actions for multiple controllers:
RailsActionTracker::Tracker.configure(
ignored_actions: {
'ApplicationController' => ['ping', 'status', 'health'],
'ApiController' => ['heartbeat', 'version'],
'AdminController' => ['dashboard_stats', 'system_info']
}
)
3. Global action ignoring (ignore actions across ALL controllers):
RailsActionTracker::Tracker.configure(
ignored_actions: {
'' => ['ping', 'status', 'health'] # Empty string key = applies to all controllers
}
)
This will ignore the ping
, status
, and health
actions regardless of which controller they're called from.
4. Combined patterns:
RailsActionTracker::Tracker.configure(
ignored_controllers: [
'Rails::PwaController' # Ignore this controller completely
],
ignored_actions: {
'' => ['ping', 'health'], # Global actions to ignore
'ApplicationController' => ['status'], # Controller-specific actions
'MonitoringController' => [], # Ignore entire controller
'ApiController' => ['heartbeat', 'version'] # Multiple specific actions
}
)
Common Use Cases
Ignore noisy Rails controllers:
ignored_controllers: ['Rails::PwaController', 'Rails::ConductorController']
Ignore health/monitoring endpoints:
ignored_actions: {
'' => ['ping', 'health', 'status', 'heartbeat'] # Global ignore
}
Ignore admin dashboard noise:
ignored_actions: {
'AdminController' => ['dashboard_stats', 'system_metrics'],
'MonitoringController' => [] # Ignore entire monitoring controller
}
Development/debugging setup:
ignored_actions: {
'' => ['ping', 'health'], # Always ignore these
'DevelopmentController' => [], # Ignore entire dev controller
'TestController' => ['debug', 'trace']
}
Manual Usage
You can also use the tracker manually in your code:
RailsActionTracker::Tracker.start_tracking
# Your code here...
User.find(1)
Post.create(title: "Hello")
RailsActionTracker::Tracker.print_summary
RailsActionTracker::Tracker.stop_tracking
Format Use Cases
Development & Debugging
# Clean console output, detailed JSON logs for analysis
RailsActionTracker::Tracker.configure(
print_format: :table, # Easy to read during development
log_format: :json, # Detailed logs for debugging
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'action_tracker.json')
)
Performance Analysis
# CSV accumulation for importing into spreadsheet tools
RailsActionTracker::Tracker.configure(
print_format: :table, # Console stays readable
log_format: :csv, # Perfect for Excel/Google Sheets with accumulated data
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'performance_analysis.csv')
)
Results in comprehensive CSV with all actions and merged access patterns. Headers expand automatically as new tables/services are discovered, making it perfect for pivot tables and data analysis.
API Documentation Generation
# JSON logs for automated API documentation
RailsActionTracker::Tracker.configure(
print_format: :json, # Immediate JSON feedback
log_format: :json, # Accumulated endpoint data
print_to_rails_log: true,
write_to_file: true,
log_file_path: Rails.root.join('log', 'api_endpoints.json')
)
Monitoring & Alerting
# CSV for log aggregation systems
RailsActionTracker::Tracker.configure(
print_format: :table, # Human-readable console
log_format: :csv, # Machine-readable logs
print_to_rails_log: false, # Reduce console noise
write_to_file: true,
log_file_path: Rails.root.join('log', 'monitoring.csv')
)
How It Works
The gem integrates seamlessly with Rails:
- Automatic middleware wraps each request
- ActiveSupport::Notifications captures SQL queries and Rails events
- Smart parsing identifies model read/write operations
- Service detection tracks common Rails services (Redis, Sidekiq, etc.)
- Thread-safe - each request tracked independently
Features
- ๐ Model tracking - See which ActiveRecord models are read/written
- ๐ข Service detection - Monitor Redis, Sidekiq, HTTP calls, and more
- ๐ Flexible logging - Rails logger, separate files, or both
- ๐จ Multiple output formats - Table, CSV, and JSON formats with separate print/log controls
- ๐ JSON accumulation - Persistent JSON logs that merge data across requests
- ๐ Format flexibility - Different formats for console vs file output
- โก Zero configuration - Works immediately after installation
- ๐งต Thread-safe - Handles concurrent requests properly
- ๐ Production ready - Minimal performance impact
- ๐ง Backward compatible - Seamless upgrade from v1.x configurations
Thread Safety
The gem is thread-safe and uses thread-local storage to track operations. Each request is tracked independently, so concurrent requests won't interfere with each other.
Performance Impact
The gem is designed to have minimal performance impact:
- Only active during non-test environments by default
- Uses efficient Set data structures for deduplication
- Subscribes only to necessary notification channels
- Skips tracking for asset requests and common non-action paths
Supported Rails Versions
This gem is tested and compatible with:
Ruby Versions: 2.7.x, 3.0.x, 3.1.x, 3.4.x
Rails Versions: 5.0+ through 7.1+ (see our CI for the full compatibility matrix)
Currently Tested Combinations:
- Ruby 2.7.x with Rails 6.0, 6.1, 7.0, 7.1
- Ruby 3.0.x with Rails 6.0, 6.1, 7.0, 7.1
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/deepakmahakale/rails_action_tracker.
For development setup and contribution guidelines, see:
- CONTRIBUTING.md - Contribution guidelines and process
- DEVELOPMENT.md - Development setup and testing instructions
License
The gem is available as open source under the terms of the MIT License.