{"id":18021030,"url":"https://github.com/kevinjalbert/rails_request_stats","last_synced_at":"2025-03-26T22:30:34.163Z","repository":{"id":56890689,"uuid":"47233406","full_name":"kevinjalbert/rails_request_stats","owner":"kevinjalbert","description":"Provides additional development statistics on Rails requests in logfile","archived":false,"fork":false,"pushed_at":"2017-11-20T15:09:44.000Z","size":30,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-30T08:23:18.507Z","etag":null,"topics":["rails","rails-requests","rubygem","statistics"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kevinjalbert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-02T03:02:44.000Z","updated_at":"2018-09-26T22:49:47.000Z","dependencies_parsed_at":"2022-08-20T15:20:44.068Z","dependency_job_id":null,"html_url":"https://github.com/kevinjalbert/rails_request_stats","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinjalbert%2Frails_request_stats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinjalbert%2Frails_request_stats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinjalbert%2Frails_request_stats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinjalbert%2Frails_request_stats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kevinjalbert","download_url":"https://codeload.github.com/kevinjalbert/rails_request_stats/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245747394,"owners_count":20665782,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rails","rails-requests","rubygem","statistics"],"created_at":"2024-10-30T06:08:34.348Z","updated_at":"2025-03-26T22:30:33.796Z","avatar_url":"https://github.com/kevinjalbert.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RailsRequestStats\n\n[![Gem Version](https://badge.fury.io/rb/rails_request_stats.svg)](https://badge.fury.io/rb/rails_request_stats)\n[![Build Status](https://travis-ci.org/kevinjalbert/rails_request_stats.svg?branch=master)](https://travis-ci.org/kevinjalbert/rails_request_stats)\n[![Code Climate](https://codeclimate.com/github/kevinjalbert/rails_request_stats/badges/gpa.svg)](https://codeclimate.com/github/kevinjalbert/rails_request_stats)\n[![Test Coverage](https://codeclimate.com/github/kevinjalbert/rails_request_stats/badges/coverage.svg)](https://codeclimate.com/github/kevinjalbert/rails_request_stats/coverage)\n\nDuring development have you ever:\n\n* Wondered how many SQL queries occurred during a request?\n* Been curious on average view and database runtime for a request?\n* Wanted a report containing overall statistics of all unique requests?\n* Wanted a better way to iteratively optimize requests?\n\n`RailsRequestStats` provides a simple drop-in solution to expose more statistics on requests. New information is presented in your development logs, supplying you with the required information to iteratively optimize requests by noticing subtle changes in the number of queries and average runtimes.\n\n## How this Works\n\n`RailsRequestStats::NotificationSubscribers` when required will subscribe to the `sql.active_record`, `start_processing.action_controller`, and `process_action.action_controller` `ActionSupport::Notifications`.\n\n * The `sql.active_record` event allow us to count each SQL query that passes though ActiveRecord, which we count internally.\n * The `cache_read.active_support` event allows us to count each read and hit to the Rails cache.\n * The `cache_fetch_hit.active_support` event allows us to count the cache hits to the Rails cache when using *fetch*.\n * The `start_processing.action_controller` event allows us to clear iternal counts, as well as perform a `GC.start` and capturing the count of objects residing in the `ObjectSpace`.\n * The `process_action.action_controller` event provides us runtime information along with identifying controller action details, we even determine the number of generated objects since the start of processing the action. At this point we are able to synthesis the query information and runtime information and store them internally in running collection of `RailsRequestStats::RequestStats` objects.\n\n**Note** the data collection is tracked and stored in class-level instance variables. Thus this is not threadsafe, as no concurrency mechanisms are used (i.e., mutex). For non-threaded and forking application servers this should be fine.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'rails_request_stats', group: :development\n```\n\n## Example Outputs\n\nWithin the console ./log/development.log you should start seeing the following statement appearing at the end of processing a request:\n\n```\n[RailsRequestStats] (AVG view_runtime: 163.655ms | AVG db_runtime: 15.465ms | AVG generated_object_count: 14523 | query_count: 9 | cached_query_count: 0 | cache_read_count: 3 | cache_hit_count: 3)\n```\n\nFinally when you exit the application's server, you should see a summary report of all the data captured:\n\n```\n[RailsRequestStats] INDEX:html \"/users\" (AVG view_runtime: 128.492ms | AVG db_runtime: 9.186ms | AVG generated_object_count: 25529 | MIN query_count: 8 | MAX query_count: 9) from 4 requests\n[RailsRequestStats] SHOW:html \"/users/2\" (AVG view_runtime: 13.0429ms | AVG db_runtime: 1.69033ms | AVG generated_object_count: 14523 | MIN query_count: 2 | MAX query_count: 2) from 3 requests\n[RailsRequestStats] SHOW:html \"/users/2?test=1\u0026blah=2\" (AVG view_runtime: 17.8252ms | AVG db_runtime: 1.621ms | AVG generated_object_count: 18511 | MIN query_count: 2 | MAX query_count: 2) from 1 requests\n```\n\n## Customizing Outputs\n\n### Memory Stats\nBy setting the following class variable within in an initializer (`./config/initializers/rails_request_stats.rb`):\n\n```ruby\nRailsRequestStats::Report.print_memory_stats = true\n```\n\nYou can see the *generated objects* within the `ObjectSpace` for individual requests:\n\n```\n[RailsRequestStats] (AVG view_runtime: 93.7252ms | AVG db_runtime: 8.66075ms | AVG generated_object_count: 125282 | query_count: 8 | cached_query_count: 0 | cache_read_count: 3 | cache_hit_count: 3 | generated_objects: {:total_generated_objects=\u003e111878, :object=\u003e921, :class=\u003e35, :module=\u003e0, :float=\u003e0, :string=\u003e49501, :regexp=\u003e1556, :array=\u003e17855, :hash=\u003e2087, :struct=\u003e103, :bignum=\u003e0, :file=\u003e0, :data=\u003e37682, :match=\u003e373, :complex=\u003e0, :node=\u003e1688, :iclass=\u003e0})\n```\n\n### Override Reports\n\nYou can manually override the output by monkey-patching in an initializer (`./config/initializers/rails_request_stats.rb`):\n\n```ruby\nmodule RailsRequestStats\n  class Report\n    # Called after every request\n    def report_text\n      # Access to @request_stats (instance of RequestStats)\n    end\n    # Called after the application server is closed (via #at_exit_handler)\n    def exit_report_text\n      # Access to @request_stats (instance of RequestStats)\n    end\n  end\n\n  class NotificationSubscribers\n    # Called when the application server is closed\n    def self.at_exit_handler\n      # Access to @requests (hash of { \u003cpaths\u003e =\u003e RequestStats })\n    end\n  end\nend\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/kevinjalbert/rails_request_stats. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinjalbert%2Frails_request_stats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkevinjalbert%2Frails_request_stats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinjalbert%2Frails_request_stats/lists"}