7824: Merge branch 'master' into 7824-arvls-arvput-collection-api-usage
[arvados.git] / services / api / lib / audit_logs.rb
1 require 'current_api_client'
2 require 'db_current_time'
3
4 module AuditLogs
5   extend CurrentApiClient
6   extend DbCurrentTime
7
8   def self.delete_old(max_age:, max_batch:)
9     act_as_system_user do
10       if !File.owned?(Rails.root.join('tmp'))
11         Rails.logger.warn("AuditLogs: not owner of #{Rails.root}/tmp, skipping")
12         return
13       end
14       lockfile = Rails.root.join('tmp', 'audit_logs.lock')
15       File.open(lockfile, File::RDWR|File::CREAT, 0600) do |f|
16         return unless f.flock(File::LOCK_NB|File::LOCK_EX)
17
18         sql = "select clock_timestamp() - interval '#{'%.9f' % max_age} seconds'"
19         threshold = ActiveRecord::Base.connection.select_value(sql).to_time.utc
20         Rails.logger.info "AuditLogs: deleting logs older than #{threshold}"
21
22         did_total = 0
23         loop do
24           sql = Log.unscoped.
25                 select(:id).
26                 order(:created_at).
27                 where('event_type in (?)', ['create', 'update', 'destroy', 'delete']).
28                 where('created_at < ?', threshold).
29                 limit(max_batch).
30                 to_sql
31           did = Log.unscoped.where("id in (#{sql})").delete_all
32           did_total += did
33
34           Rails.logger.info "AuditLogs: deleted batch of #{did}"
35           break if did == 0
36         end
37         Rails.logger.info "AuditLogs: deleted total #{did_total}"
38       end
39     end
40   end
41
42   def self.tidy_in_background
43     max_age = Rails.configuration.max_audit_log_age
44     max_batch = Rails.configuration.max_audit_log_delete_batch
45     return if max_age <= 0 || max_batch <= 0
46
47     exp = (max_age/14).seconds
48     need = false
49     Rails.cache.fetch('AuditLogs', expires_in: exp) do
50       need = true
51     end
52     return if !need
53
54     Thread.new do
55       Thread.current.abort_on_exception = false
56       begin
57         delete_old(max_age: max_age, max_batch: max_batch)
58       rescue => e
59         Rails.logger.error "#{e.class}: #{e}\n#{e.backtrace.join("\n\t")}"
60       ensure
61         ActiveRecord::Base.connection.close
62       end
63     end
64   end
65 end