如何通过ActiveSupport事件暴露Rails各API请求的ActiveRecord查询数?
实现Rails请求ActiveRecord查询数的事件化暴露
完全可以做到把查询数注入process_action.action_controller事件的负载中,无需依赖第三方gem的日志输出,下面是具体实现方案:
核心思路
- 利用
sql.active_record事件统计每个请求周期内的SQL查询次数(可按需排除缓存查询、Schema查询) - 将查询数通过线程安全的方式存储(避免跨请求污染)
- 订阅
process_action.action_controller事件,把统计的查询数追加到事件负载里
具体实现代码
方式1:无需额外gem,用Thread.current实现
在config/initializers/query_count_instrumentation.rb中添加以下代码:
# 统计SQL查询次数 ActiveSupport::Notifications.subscribe('sql.active_record') do |_name, _start, _finish, _id, payload| # 按需排除缓存查询、Schema查询,可根据业务调整 next if payload[:cached] || payload[:name] == 'SCHEMA' current_count = Thread.current[:ar_query_count] || 0 Thread.current[:ar_query_count] = current_count + 1 end # 清理线程变量,避免跨请求污染 Rails.application.config.after_initialize do ActionController::Base.around_action do |_controller, block| Thread.current[:ar_query_count] = 0 block.call ensure Thread.current[:ar_query_count] = nil end end # 将查询数注入process_action事件负载 ActiveSupport::Notifications.subscribe('process_action.action_controller') do |_name, _start, _finish, _id, payload| payload[:query_count] = Thread.current[:ar_query_count] || 0 end
方式2:用request_store提升线程安全性(推荐)
如果担心Thread.current在复杂场景下的线程安全问题,可以使用request_storegem:
- 先添加gem到Gemfile:
gem 'request_store'
- 执行
bundle install后,创建初始化文件config/initializers/query_count_instrumentation.rb:
# 统计SQL查询次数 ActiveSupport::Notifications.subscribe('sql.active_record') do |_name, _start, _finish, _id, payload| next if payload[:cached] || payload[:name] == 'SCHEMA' RequestStore.store[:ar_query_count] ||= 0 RequestStore.store[:ar_query_count] += 1 end # 将查询数注入process_action事件负载 ActiveSupport::Notifications.subscribe('process_action.action_controller') do |_name, _start, _finish, _id, payload| payload[:query_count] = RequestStore.store[:ar_query_count] || 0 end
验证方法
你可以在任意地方订阅process_action.action_controller事件来获取查询数,比如在初始化文件中添加测试代码:
ActiveSupport::Notifications.subscribe('process_action.action_controller') do |_name, _start, _finish, _id, payload| puts "请求路径: #{payload[:path]} | 查询次数: #{payload[:query_count]} | 响应状态: #{payload[:status]}" end
启动Rails服务后,发起API请求就能看到控制台输出包含查询数的事件数据。
内容的提问来源于stack exchange,提问作者Pattu
相关产品推荐
相关产品推荐

