RequestTagger
I did what I did
Can't say "hey man, I'm just a kid."
--Nickelback
Inject a request ID tag into all ActiveRecord queries and HTTP requests made within your [Rails] application.
Any web service requests or database queries your application makes in a given request can be tied together by coalescing your log files in your favourite log aggregator, giving a full picture of every request on your system.
An incoming HTTP header is used as the ID for all subsequent requests.
SQL queries are prepended with a comment that will look something like this:
/* request-id: abc123 */ SELECT * FROM ...
HTTP requests will include an extra header:
X-Request-Id: abc123
The implementation has borrowed ideas from RSpec's allow_any_instance_of
and webmock's stub_request
. Their source code was used as an invaluable reference during development. Thanks to the developers of both libraries for their hard work.
Installation
Add this line to your application's Gemfile:
gem 'request_tagger'
And then rebuild your bundle:
$ bundle install
Usage
The only things you need to do are create an initializer:
# config/initializers/request_tagger.rb
RequestTagger.start
and include the RequestTagger::TagRequests
module in your base controller:
class ApplicationController < ActionController::Base
include RequestTagger::TagRequests
end
You can pass the following options to RequestTagger.start
(values shown are the defaults):
RequestTagger.start(
tag_sql: true, # Tag all ActiveRecord SQL queries
tag_http: true, # Tag all HTTP requests
http_tag_name: 'X-Request-Id', # Header to use for outbound requests
sql_tag_name: 'request-id', # Identifier to use in SQL tags
header: 'HTTP_X_REQUEST_ID' # Header to watch for inbound requests*
)
* Note that an inbound HTTP header e.g. X-Request-Id
will be transformed by Rack to HTTP_X_REQUEST_ID
so take this into account when setting the header
option.
An example usage would be the $request_id
variable provided by nginx:
location / {
proxy_set_header X-Request-Id $request_id;
}
Setting a request ID manually
If you want to manually assign the request ID to be used in tags, just add overwrite the following method in your base controller:
private
def __request_tagger__set_request_id__
RequestTagger.request_id = 'my-custom-request-id'
end
Caveats
- Only web requests made by Net::HTTP are intercepted. Most popular HTTP libraries use this at their core, including Faraday and HTTParty so this should cover the vast majority of cases but feel free to submit a pull request to add more drivers.
- Since Net::HTTP and ActiveRecord are monkeypatched in similar ways to how RSpec and webmock operate, you probably do not want to enable RequestTagger in your test environment. Use
unless Rails.env.test?
in your initializer.
Development
Clone the repository and submit a pull requests to fix any bugs or add any new features.
Write tests for any new code you write and ensure all tests pass before submitting:
$ bin/rspec
Please also run Rubocop and fix any issues before making a pull request:
$ bin/rubocop
License
RequestTagger is licensed under the MIT license. Do whatever you like with the code, just give credit where it's due.