It’s been more than a year since I introduced one of my projects named Rack Web Profiler.
These last months I worked to stabilise, clean the project and also export the part linked to Rails onto a separate gem.
Why this gem
I know there is existing tools to develop and debug Rack and Rails applications like the gem rack-miniprofiler
. But they have some elements missing to allow customisation and easy extension.
That’s why I started creating this gem.
With Rack Web Profiler you have the ability to create custom collectors by using its DSL. It allows you to collect informations then show them on the bar and the panel. All datas collected are stored in an SQLite database so you have access to the requests history.
For now these two gems are just bases but it could be something more in the future.
UI preview
I worked with Thomas De Cicco a digital designer on the UI of the profiler. We tried together to have something light, simple and readable.
The bar
It gives you quick informations about the current request. By clicking an element you can access more informations on the panel.

The panel
It shows you collectors details for a captured request.
You also have a page that gives you the previous requests.

How to use it
I worked to have something which works with as less configuration as possible. But the gem will come with the possibility of having some options to configure it as you like.
Rack → rack-webprofiler
With rack
you need to add the profiler in the middleware like this:
home = lambda { |_env|
[200, { "Content-Type" => "text/html" }, ["<html><body>Hello world!</body></html>"]]
}
builder = Rack::Builder.new do
use Rack::WebProfiler
map('/') { run home }
end
run builder
By default it will use Dir.tmpdir
to define the temporary directory (place where the database is created). You could configure it by using the tmp_dir:
option.
To see more you can go to the GitHub project.
Rails → rails-webprofiler
For Rails the gem only contains specific collectors. It includes the rack-webprofiler
gem to have the bar and panel.
It uses Railtie to automatically load the profiler in the middleware. So you only have to add one gem to the Gemfile as following:
# Gemfile
gem "rails-webprofiler"
It uses the Rails temporary directory as tmp_dir
for the database place.
To see more you can go to the GitHub project.
Sinatra
For now there is nothing for Sinatra but I plan working on a sinatra-webprofiler
gem in the future if there are requests.
How to extend it
Like I said I worked to have something extendable easily. I created a DSL with methods to give you access to the tools you needs.
Here is an example of the time collector.
class TimeCollector
# Just include the DSL.
include Rack::WebProfiler::Collector::DSL
# Base64 icon (using svg icon is better).
icon <<-'ICON'
data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB3aWR0aD0iMjBweCIgaGVpZ2h0PSIyMHB4IiB2aWV3Qm94PSIwIDAgMjAgMjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+ICAgICAgICA8dGl0bGU+R3JvdXAgMjwvdGl0bGU+ICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPiAgICA8ZGVmcz48L2RlZnM+ICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPiAgICAgICAgPGcgaWQ9IkRlc2t0b3AtMiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEwLjAwMDAwMCwgLTE3MC4wMDAwMDApIiBmaWxsPSIjNTg1NDczIj4gICAgICAgICAgICA8ZyBpZD0iUGVyZm9ybWFuY2UiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLCAxNjAuMDAwMDAwKSI+ICAgICAgICAgICAgICAgIDxnIGlkPSJHcm91cC0yIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMC4wMDAwMDAsIDEwLjAwMDAwMCkiPiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEwLDE4IEwxMCwxOCBDMTQuNDE4Mjc4LDE4IDE4LDE0LjQxODI3OCAxOCwxMCBDMTgsNS41ODE3MjIgMTQuNDE4Mjc4LDIgMTAsMiBDNS41ODE3MjIsMiAyLDUuNTgxNzIyIDIsMTAgQzIsMTQuNDE4Mjc4IDUuNTgxNzIyLDE4IDEwLDE4IEwxMCwxOCBMMTAsMTggWiBNMCwxMCBDMCw0LjQ3NzE1MjUgNC40NzcxNTI1LDAgMTAsMCBDMTUuNTIyODQ3NSwwIDIwLDQuNDc3MTUyNSAyMCwxMCBDMjAsMTUuNTIyODQ3NSAxNS41MjI4NDc1LDIwIDEwLDIwIEM0LjQ3NzE1MjUsMjAgMCwxNS41MjI4NDc1IDAsMTAgWiIgaWQ9IlNoYXBlIj48L3BhdGg+ICAgICAgICAgICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLTQzIiB4PSI5IiB5PSI0IiB3aWR0aD0iMiIgaGVpZ2h0PSI1Ij48L3JlY3Q+ICAgICAgICAgICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLTQzLUNvcHkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE0LjAwMDAwMCwgMTAuMDAwMDAwKSByb3RhdGUoLTI3MC4wMDAwMDApIHRyYW5zbGF0ZSgtMTQuMDAwMDAwLCAtMTAuMDAwMDAwKSAiIHg9IjEzIiB5PSI4IiB3aWR0aD0iMiIgaGVpZ2h0PSI0Ij48L3JlY3Q+ICAgICAgICAgICAgICAgIDwvZz4gICAgICAgICAgICA8L2c+ICAgICAgICA8L2c+ICAgIDwvZz48L3N2Zz4=
ICON
identifier "time" # identifier is used as database key and in css.
label "Time" # label is used as text in the panel sidebar.
position 3 # position of the element in the bar and panel sidebar.
# Collect the data you need to store for the view.
# You access to the request and response objects (they are not the originals).
collect do |request, _response|
runtime = request.env[WebProfiler::ENV_RUNTIME] * 1000.0
# Store by key the data you need access in the view.
store :runtime, runtime
# You could set a color status to the bar item.
# Possible values: `:warning`, `:danger`, `:success`
status :warning if runtime >= 200
status :danger if runtime >= 1000
# You could conditionally show or hide panel and bar.
# By default they are shown if they exist in the view.
show_panel false
show_bar true
end
# There is two ways to store the ERB template. Here we store view content
# in the same file as the collector.
template __FILE__, type: :DATA
# But you could put it into a separate file like this:
#template "../template_folder/template_file.erb"
end
__END__
<% tab_content do %>
<%= data(:runtime).round(2) %> ms
<% end %>
Or if it was in a separate file:
<!-- tab_content block just contains the tab content -->
<% tab_content do %>
<!-- use data method to get the values you stored by key -->
<%= data(:runtime).round(2) %> ms
<% end %>
<!-- panel_content block contains the panel content -->
<!-- but here we don't need to show it -->
<% panel_content do %>
<!-- Your pretty HTML code -->
<% end %>
After creating the collector, you simply need to register it as following:
Rack::WebProfiler.register_collector TimeCollector
Registration can’t be done dynamically in your application code. If you don’t always need to show a collector, you have to use the is_enabled?
DSL method.
If you need more details, you have a documentation for the DSL.
Voilà, you have your first collector!
Next steps
The Rack WebProfiler will have some other functionalities in the future. Like being able to toggle the bar, have a search form for the requests list and catch the exceptions to show the informations into the panel.
I also plan to create some other collectors for Rails like I18n, ActiveMailer and ActiveJob collectors.
If you have any feedback, comment or idea of contribution, github!
Sources: