joshuay03/dial

A modern profiler for your Rails application

Ruby

229

134 commits

updated Jan 17, 2026

See the code

README

Dial

Version Build

A modern profiler for your Rails application.

Utilizes vernier for profiling and prosopite for N+1 query detection.

[!NOTE] Check out the resources in the vernier project for more information on how to interpret the viewer, as well as comparisons with other profilers, including stackprof.

Demo

Installation

  1. Add the gem to your Rails application's Gemfile:
gem "dial"
  1. Install the gem:
bundle install
  1. Mount the engine in your config/routes.rb file:
# this will mount the engine at /dial
mount Dial::Engine, at: "/dial"
  1. (Optional) Configure the gem in an initializer:
# config/initializers/dial.rb

Dial.configure do |config|
  config.enabled = !Rails.env.production? # disable by default in production, use force_param to enable per request
  config.force_param = "profile" # override param name to force profiling
  if Rails.env.staging?
    config.sampling_percentage = 50 # override sampling percentage in staging for A/B testing profiler impact
  end
  unless Rails.env.development?
    config.storage = Dial::Storage::RedisAdapter # use Redis storage in non-development environments
    config.storage_options = { client: Redis.new(url: ENV["REDIS_URL"]), ttl: 86400 }
  end
  config.vernier_interval = 100
  config.vernier_allocation_interval = 10_000
  config.prosopite_ignore_queries += [/pg_sleep/i]
end

Options

OptionDescriptionDefault
enabledWhether profiling is enabled.true
force_paramRequest parameter name to force profiling even when disabled. Always profiles (bypasses sampling)."dial_force"
sampling_percentagePercentage of requests to profile.100 in development, 1 in production
storageStorage adapter class for profile data.Dial::Storage::FileAdapter
storage_optionsOptions hash passed to storage adapter.{ ttl: 3600 }
content_security_policy_nonceSets the content security policy nonce to use when inserting Dial's script. Can be a string, or a Proc which receives env and response headers as arguments and returns the nonce string.Rails generated nonce or nil
toggle_shortcut_keysArray of keys for keyboard shortcut to toggle panel visibility.["Alt", "Shift", "D"]
vernier_intervalSets the interval option for vernier.200
vernier_allocation_intervalSets the allocation_interval option for vernier.2_000
prosopite_ignore_queriesSets the ignore_queries option for prosopite.[/schema_migrations/i]

Storage Backends

File Storage (Default)

Profile data is stored as files on disk with polled expiration. Only suitable for development and single-server deployments.

Dial.configure do |config|
  config.storage = Dial::Storage::FileAdapter
  config.storage_options = { ttl: 86400 }
end

Redis Storage

Profile data is stored in Redis with automatic expiration. Supports both single Redis instances and Redis Cluster.

# Single Redis instance
Dial.configure do |config|
  config.storage = Dial::Storage::RedisAdapter
  config.storage_options = { client: Redis.new(url: "redis://localhost:6379"), ttl: 86400 }
end

# Redis Cluster
Dial.configure do |config|
  config.storage = Dial::Storage::RedisAdapter
  config.storage_options = {
    client: Redis::Cluster.new(nodes: [
      "redis://node1:7000",
      "redis://node2:7001",
      "redis://node3:7002"
    ]),
    ttl: 86400
  }
end

Memcached Storage

Profile data is stored in Memcached with automatic expiration.

Dial.configure do |config|
  config.storage = Dial::Storage::MemcachedAdapter
  config.storage_options = { client: Dalli::Client.new("localhost:11211"), ttl: 86400 }
end

Comparison with rack-mini-profiler

rack-mini-profilerDial
CompatibilityAny Rack applicationOnly Rails applications
Database ProfilingYesYes (via vernier hook - marker table, chart)
N+1 Query DetectionYes (*needs to be inferred)Yes (via prosopite)
Ruby ProfilingYes (with stackprof - flame graph)Yes (via vernier - flame graph, stack chart, call tree)
Ruby Allocation ProfilingYes (with stackprof - flame graph)Yes (via vernier - flame graph, stack chart, call tree)
Memory ProfilingYes (with memory_profiler)Yes (*overall usage only) (via vernier hook - graph)
View ProfilingYesYes (via vernier hook - marker table, chart)
Snapshot SamplingYesNo
Storage BackendsRedis, Memcached, File, MemoryRedis, Memcached, File
Production ReadyYesYes

Development

After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Testing Storage Adapters

To test the Redis and Memcached storage adapters, you'll need running instances: docker compose -f docker-compose.storage.yml up

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/joshuay03/dial.

License

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

Code of Conduct

Everyone interacting in the Dial project's codebase and issue tracker is expected to follow the code of conduct.

joshuay03/dial

A modern profiler for your Rails application

Ruby

229

134 commits

updated Jan 17, 2026

See the code

README

Dial

Version Build

A modern profiler for your Rails application.

Utilizes vernier for profiling and prosopite for N+1 query detection.

[!NOTE] Check out the resources in the vernier project for more information on how to interpret the viewer, as well as comparisons with other profilers, including stackprof.

Demo

Installation

  1. Add the gem to your Rails application's Gemfile:
gem "dial"
  1. Install the gem:
bundle install
  1. Mount the engine in your config/routes.rb file:
# this will mount the engine at /dial
mount Dial::Engine, at: "/dial"
  1. (Optional) Configure the gem in an initializer:
# config/initializers/dial.rb

Dial.configure do |config|
  config.enabled = !Rails.env.production? # disable by default in production, use force_param to enable per request
  config.force_param = "profile" # override param name to force profiling
  if Rails.env.staging?
    config.sampling_percentage = 50 # override sampling percentage in staging for A/B testing profiler impact
  end
  unless Rails.env.development?
    config.storage = Dial::Storage::RedisAdapter # use Redis storage in non-development environments
    config.storage_options = { client: Redis.new(url: ENV["REDIS_URL"]), ttl: 86400 }
  end
  config.vernier_interval = 100
  config.vernier_allocation_interval = 10_000
  config.prosopite_ignore_queries += [/pg_sleep/i]
end

Options

OptionDescriptionDefault
enabledWhether profiling is enabled.true
force_paramRequest parameter name to force profiling even when disabled. Always profiles (bypasses sampling)."dial_force"
sampling_percentagePercentage of requests to profile.100 in development, 1 in production
storageStorage adapter class for profile data.Dial::Storage::FileAdapter
storage_optionsOptions hash passed to storage adapter.{ ttl: 3600 }
content_security_policy_nonceSets the content security policy nonce to use when inserting Dial's script. Can be a string, or a Proc which receives env and response headers as arguments and returns the nonce string.Rails generated nonce or nil
toggle_shortcut_keysArray of keys for keyboard shortcut to toggle panel visibility.["Alt", "Shift", "D"]
vernier_intervalSets the interval option for vernier.200
vernier_allocation_intervalSets the allocation_interval option for vernier.2_000
prosopite_ignore_queriesSets the ignore_queries option for prosopite.[/schema_migrations/i]

Storage Backends

File Storage (Default)

Profile data is stored as files on disk with polled expiration. Only suitable for development and single-server deployments.

Dial.configure do |config|
  config.storage = Dial::Storage::FileAdapter
  config.storage_options = { ttl: 86400 }
end

Redis Storage

Profile data is stored in Redis with automatic expiration. Supports both single Redis instances and Redis Cluster.

# Single Redis instance
Dial.configure do |config|
  config.storage = Dial::Storage::RedisAdapter
  config.storage_options = { client: Redis.new(url: "redis://localhost:6379"), ttl: 86400 }
end

# Redis Cluster
Dial.configure do |config|
  config.storage = Dial::Storage::RedisAdapter
  config.storage_options = {
    client: Redis::Cluster.new(nodes: [
      "redis://node1:7000",
      "redis://node2:7001",
      "redis://node3:7002"
    ]),
    ttl: 86400
  }
end

Memcached Storage

Profile data is stored in Memcached with automatic expiration.

Dial.configure do |config|
  config.storage = Dial::Storage::MemcachedAdapter
  config.storage_options = { client: Dalli::Client.new("localhost:11211"), ttl: 86400 }
end

Comparison with rack-mini-profiler

rack-mini-profilerDial
CompatibilityAny Rack applicationOnly Rails applications
Database ProfilingYesYes (via vernier hook - marker table, chart)
N+1 Query DetectionYes (*needs to be inferred)Yes (via prosopite)
Ruby ProfilingYes (with stackprof - flame graph)Yes (via vernier - flame graph, stack chart, call tree)
Ruby Allocation ProfilingYes (with stackprof - flame graph)Yes (via vernier - flame graph, stack chart, call tree)
Memory ProfilingYes (with memory_profiler)Yes (*overall usage only) (via vernier hook - graph)
View ProfilingYesYes (via vernier hook - marker table, chart)
Snapshot SamplingYesNo
Storage BackendsRedis, Memcached, File, MemoryRedis, Memcached, File
Production ReadyYesYes

Development

After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Testing Storage Adapters

To test the Redis and Memcached storage adapters, you'll need running instances: docker compose -f docker-compose.storage.yml up

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/joshuay03/dial.

License

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

Code of Conduct

Everyone interacting in the Dial project's codebase and issue tracker is expected to follow the code of conduct.

Project health

RubyGems

Latest release

0.6.0 · Oct 23, 2025

Releases this year

1

Significant stargazers

Juanito

965 followers · starred Nov 2024

Benjamin Fleischer

252 followers · starred May 2025

Indragie Karunaratne

1,291 followers · starred May 2025

Svyatoslav Kryukov

218 followers · starred May 2025