turniere-backend/lib/local/request_profiling.rb

46 lines
1.3 KiB
Ruby

# frozen_string_literal: true
module Local
class RequestProfiling
IGNORED_SQL_NAMES = %w[SCHEMA CACHE].freeze
IGNORED_SQL = /\A(?:BEGIN|COMMIT|ROLLBACK|SAVEPOINT|RELEASE)/i
def initialize(enabled: false)
@enabled = enabled
@measurements = []
end
def measure(name)
return yield unless @enabled
query_count = 0
subscriber = lambda do |_event_name, _start, _finish, _id, payload|
sql = payload[:sql].to_s
next if IGNORED_SQL_NAMES.include?(payload[:name])
next if sql.match?(IGNORED_SQL)
query_count += 1
end
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
result = nil
ActiveSupport::Notifications.subscribed(subscriber, 'sql.active_record') do
result = yield
end
duration = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1000.0
@measurements << { name:, duration: duration.round(1), query_count: }
result
end
def apply_to(response, label:)
return unless @enabled
response.set_header('Server-Timing', @measurements.map { |m| "#{m[:name]};dur=#{m[:duration]}" }.join(', '))
response.set_header(
'X-Turniere-Profile',
"#{label}: #{@measurements.map { |m| "#{m[:name]}=#{m[:duration]}ms/#{m[:query_count]}sql" }.join(', ')}"
)
end
end
end