RequestTrail
Middleware that traces a request through all the layers (middleware, controller, ActiveRecord, cache) and dumps a flame-graph-style summary to the log.
Table of Contents
Installation
Add to your application's Gemfile:
bundle add request_trail
Or install directly:
gem install request_trail
Usage
Rails
RequestTrail auto-inserts itself via a Railtie. No manual middleware configuration is needed — just add the gem to your Gemfile and it will log a summary after every request.
When controller tracing is active, output is tiered:
[RequestTrail] GET /orders 142ms
controller 104ms
sql 38ms (7 queries)
cache 2ms (4 hits, 1 miss)
view 22ms
Without controller data (plain Rack apps), a single-line summary is emitted:
[RequestTrail] GET /orders 142ms | SQL: 7/38.3ms | Cache: 4 hits, 1 miss, 2.0ms
Flame graph formatter
Opt into the ASCII flame-graph formatter for a visual proportional breakdown:
RequestTrail.configure do |config|
config.formatter = RequestTrail::Formatters::FlameGraph.new
end
Output (with ANSI colour when stdout is a TTY):
[RequestTrail] GET /orders 142ms ████████████████████████████████████
controller 104ms ████████████████████████████
sql 38ms █████████
cache 2ms
view 22ms █████
Colour scheme: controller = blue, sql = yellow, cache = green, view = magenta. Plain bars are emitted when stdout is not a TTY (e.g. log files, CI).
Override any layer's ANSI code with the colors: option:
RequestTrail::Formatters::FlameGraph.new(
colorize: true,
colors: { controller: "\e[36m", sql: "\e[31m" }
)
Unspecified layers keep their defaults.
Custom formatters
Any object that responds to format(request, collector) and returns a String can be used as a formatter. Include RequestTrail::Formatters::Base to make the contract explicit:
class MyFormatter
include RequestTrail::Formatters::Base
def format(request, collector)
"#{request.request_method} #{request.path} took #{collector.elapsed_ms.round}ms"
end
end
RequestTrail.configure do |config|
config.formatter = MyFormatter.new
end
format receives:
request— aRack::Requestwith the current HTTP requestcollector— aRequestTrail::Collectorexposingelapsed_ms,sql_count,sql_duration_ms,cache_hits,cache_misses,cache_duration_ms,action_duration_ms, andview_duration_ms
Installation generator
Run the generator to scaffold the initializer:
rails generate request_trail:install
This creates config/initializers/request_trail.rb pre-populated with all available options and their defaults.
Configuration
Add an initializer to customize behavior:
# config/initializers/request_trail.rb
RequestTrail.configure do |config|
config.enabled = true # set to false to disable entirely
config.log_level = :info # Rails logger level (:debug, :info, :warn)
config.threshold_ms = 200 # only log requests slower than this (0 = log all)
config.logger = nil # defaults to Rails.logger
config.formatter = RequestTrail::Formatters::FlameGraph.new # optional
# skip tracing for specific paths (strings = exact match, regexes = pattern match)
config.ignore_paths = ["/health", "/up", /^\/assets/]
# trace only N% of requests — useful in high-traffic production environments
config.sample_rate = 0.1 # 0.0 = never, 1.0 = always (default)
end
Non-Rails (plain Rack)
Insert the middleware manually and attach the subscriber:
require "request_trail"
RequestTrail::Subscriber.attach
use RequestTrail::Middleware
run MyApp
Development
After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec rake to run the full CI suite (audit + lint + tests). You can also run bin/console for an interactive prompt.
Running tests
bundle exec rake spec # full test suite
bundle exec rspec spec/path/to/file_spec.rb # single file
bundle exec rspec spec/path/to/file_spec.rb:42 # single example
Dummy app
A minimal Rails app lives in spec/dummy for manual end-to-end testing. It mounts a single GET /ping endpoint and logs RequestTrail output to spec/dummy/log/request_trail.log.
Start the server:
bundle exec rackup spec/dummy/config.ru --port 3000
Then make a request and tail the log:
curl http://localhost:3000/ping
tail -f spec/dummy/log/request_trail.log
You should see tiered output like:
[RequestTrail] GET /ping 33ms
controller 3ms
sql 0.0ms (0 queries)
cache 0.0ms (0 hits, 0 misses)
view 2.8ms
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/eclectic-coding/request-trail.
License
The gem is available as open source under the terms of the MIT License.