Я разработал rails_request_stats, чтобы решить свою личную проблему, оптимизируя определенные конечные точки API Rails на работе. Это дало мне быстрый способ быстро получить необходимую информацию в журналах разработки.
Чтобы лучше всего описать, что и как можно использовать rails_request_stats
, следующее взято непосредственно из README rails_request_stats
:
Во время разработки вы когда-нибудь:
- Интересно, сколько запросов SQL произошло во время запроса?
- Вас интересовало среднее время просмотра и время работы базы данных для запроса?
- Хотите отчет, содержащий общую статистику всех уникальных запросов?
- Нужен лучший способ итеративной оптимизации запросов?
RailsRequestStats
предоставляет простое встраиваемое решение для предоставления дополнительной статистики по запросам. Новая информация представлена в ваших журналах разработки, предоставляя вам необходимую информацию для итеративной оптимизации запросов, отмечая незначительные изменения в количестве запросов и среднем времени выполнения.
Как это работает
RailsRequestStats::NotificationSubscribers
при необходимости подпишется на sql.active_record
, start_processing.action_controller
и process_action.action_controller
ActionSupport::Notifications
.
- Событие
sql.active_record
позволяет нам подсчитывать каждый SQL-запрос, проходящий через ActiveRecord, который мы подсчитываем внутренне. - Событие
cache_read.active_support
позволяет нам подсчитывать каждое чтение и попадание в кеш Rails. - Событие
cache_fetch_hit.active_support
позволяет нам подсчитывать обращения к кешу Rails при использовании fetch. - Событие
start_processing.action_controller
позволяет нам очистить внутренние счетчики, а также выполнитьGC.start
и зафиксировать количество объектов, находящихся вObjectSpace
. - Событие
process_action.action_controller
предоставляет нам информацию о времени выполнения вместе с идентифицирующими деталями действия контроллера, мы даже определяем количество сгенерированных объектов с момента начала обработки действия. На этом этапе мы можем синтезировать информацию о запросе и информацию о времени выполнения и хранить их внутри в текущей коллекцииRailsRequestStats::RequestStats
объектов.
Примечание: сбор данных отслеживается и сохраняется в переменных экземпляра уровня класса. Таким образом, это не потокобезопасно, так как не используются механизмы параллелизма (т. е. мьютекс). Для серверов приложений без потоков и разветвлений это должно быть хорошо.
Установка
Добавьте эту строку в Gemfile вашего приложения:
gem 'rails_request_stats', group: :development
Пример выходных данных
В консоли ./log/development.log вы должны увидеть следующий оператор, появляющийся в конце обработки запроса:
[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)
Наконец, когда вы выходите из сервера приложения, вы должны увидеть сводный отчет обо всех захваченных данных:
[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
[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
[RailsRequestStats] SHOW:html "/users/2?test=1&blah=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
Настройка выходов
Статистика памяти
Установив следующую переменную класса в инициализаторе (./config/initializers/rails_request_stats.rb
):
RailsRequestStats::Report.print_memory_stats = true
Вы можете увидеть созданные объекты в ObjectSpace
для отдельных запросов:
[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=>111878, :object=>921, :class=>35, :module=>0, :float=>0, :string=>49501, :regexp=>1556, :array=>17855, :hash=>2087, :struct=>103, :bignum=>0, :file=>0, :data=>37682, :match=>373, :complex=>0, :node=>1688, :iclass=>0})
Переопределить отчеты
Вы можете вручную переопределить вывод, заплатив обезьяну в инициализаторе (./config/initializers/rails_request_stats.rb
):
module RailsRequestStats class Report # Called after every request def report_text # Access to @request_stats (instance of RequestStats) end # Called after the application server is closed (via #at_exit_handler) def exit_report_text # Access to @request_stats (instance of RequestStats) end end
class NotificationSubscribers # Called when the application server is closed def self.at_exit_handler # Access to @requests (hash of { <paths> => RequestStats }) end end end
Размышления
Я лично использую RailsRequestStats
на работе с момента его создания. Прием был довольно хорошим, он не оказал большого влияния и просто предоставляет дополнительную информацию разработчикам во время повседневной работы. Отмечу, что rack-mini-profiler — отличный драгоценный камень, который как бы вдохновил меня на создание этого драгоценного камня. Я не мог найти хороший способ получить нужную информацию при работе с конечными точками API, с помощью RailsRequestStats
я смог просто вывести ее в журналы.
В будущем я мог бы добавить больше подробных отчетов памяти. Я также должен убедиться, что он продолжает работать в Rails 5, где веб-сервером по умолчанию является Puma, который является параллельным веб-сервером. Это может создать проблему, поскольку информация хранится в переменной экземпляра класса и изменяется на различных этапах жизненного цикла запросов.
Первоначально опубликовано на kevinjalbert.com.