gitlab-ce/lib/gitlab/database/query_analyzer.rb

61 lines
1.9 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Database
# The purpose of this class is to implement a various query analyzers based on `pg_query`
# And process them all via `Gitlab::Database::QueryAnalyzers::*`
class QueryAnalyzer
ANALYZERS = [].freeze
Parsed = Struct.new(
:sql, :connection, :pg
)
def hook!
@subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |event|
process_sql(event.payload[:sql], event.payload[:connection])
end
end
private
def process_sql(sql, connection)
analyzers = enabled_analyzers(connection)
return unless analyzers.any?
parsed = parse(sql, connection)
return unless parsed
analyzers.each do |analyzer|
analyzer.analyze(parsed)
rescue => e # rubocop:disable Style/RescueStandardError
# We catch all standard errors to prevent validation errors to introduce fatal errors in production
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
end
end
def enabled_analyzers(connection)
ANALYZERS.select do |analyzer|
analyzer.enabled?(connection)
rescue StandardError => e # rubocop:disable Style/RescueStandardError
# We catch all standard errors to prevent validation errors to introduce fatal errors in production
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
end
end
def parse(sql, connection)
parsed = PgQuery.parse(sql)
return unless parsed
normalized = PgQuery.normalize(sql)
Parsed.new(normalized, connection, parsed)
rescue PgQuery::ParseError => e
# Ignore PgQuery parse errors (due to depth limit or other reasons)
Gitlab::ErrorTracking.track_exception(e)
nil
end
end
end
end