diff options
Diffstat (limited to 'lib/gitlab/database/query_analyzer.rb')
-rw-r--r-- | lib/gitlab/database/query_analyzer.rb | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/lib/gitlab/database/query_analyzer.rb b/lib/gitlab/database/query_analyzer.rb new file mode 100644 index 00000000000..830ad1383c0 --- /dev/null +++ b/lib/gitlab/database/query_analyzer.rb @@ -0,0 +1,60 @@ +# 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 |