A long-lived project that still receives updates
A Rails gem that provides detailed tracking of model read/write operations and service usage during controller action execution, with configurable logging options.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

 Project Readme

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

  1. :table - Clean tabular format (default)
  2. :csv - CSV format with dynamic headers
  3. :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:

  1. Automatic middleware wraps each request
  2. ActiveSupport::Notifications captures SQL queries and Rails events
  3. Smart parsing identifies model read/write operations
  4. Service detection tracks common Rails services (Redis, Sidekiq, etc.)
  5. 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:

License

The gem is available as open source under the terms of the MIT License.