gitlab-org--gitlab-foss/lib/gitlab/database/transaction/context.rb

125 lines
3.0 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Database
module Transaction
class Context
attr_reader :context
LOG_SAVEPOINTS_THRESHOLD = 1 # 1 `SAVEPOINT` created in a transaction
LOG_DURATION_S_THRESHOLD = 120 # transaction that is running for 2 minutes or longer
LOG_THROTTLE_DURATION = 1
def initialize
@context = {}
end
def set_start_time
@context[:start_time] = current_timestamp
end
def set_depth(depth)
@context[:depth] = [@context[:depth].to_i, depth].max
end
def increment_savepoints
@context[:savepoints] = @context[:savepoints].to_i + 1
end
def increment_rollbacks
@context[:rollbacks] = @context[:rollbacks].to_i + 1
end
def increment_releases
@context[:releases] = @context[:releases].to_i + 1
end
def track_sql(sql)
(@context[:queries] ||= []).push(sql)
end
def track_backtrace(backtrace)
cleaned_backtrace = Gitlab::BacktraceCleaner.clean_backtrace(backtrace)
(@context[:backtraces] ||= []).push(cleaned_backtrace)
end
def duration
return unless @context[:start_time].present?
current_timestamp - @context[:start_time]
end
def savepoints_threshold_exceeded?
@context[:savepoints].to_i >= LOG_SAVEPOINTS_THRESHOLD
end
def duration_threshold_exceeded?
duration.to_i >= LOG_DURATION_S_THRESHOLD
end
def should_log?
return false if logged_already?
savepoints_threshold_exceeded? || duration_threshold_exceeded?
end
def commit
log(:commit)
end
def rollback
log(:rollback)
end
def backtraces
@context[:backtraces].to_a
end
private
def queries
@context[:queries].to_a.join("\n")
end
def current_timestamp
::Gitlab::Metrics::System.monotonic_time
end
def logged_already?
return false if @context[:last_log_timestamp].nil?
(current_timestamp - @context[:last_log_timestamp].to_i) < LOG_THROTTLE_DURATION
end
def set_last_log_timestamp
@context[:last_log_timestamp] = current_timestamp
end
def log(operation)
return unless should_log?
set_last_log_timestamp
attributes = {
class: self.class.name,
result: operation,
duration_s: duration,
depth: @context[:depth].to_i,
savepoints_count: @context[:savepoints].to_i,
rollbacks_count: @context[:rollbacks].to_i,
releases_count: @context[:releases].to_i,
sql: queries,
savepoint_backtraces: backtraces
}
application_info(attributes)
end
def application_info(attributes)
Gitlab::AppJsonLogger.info(attributes)
end
end
end
end
end