Files
Dalan/lib/barong/activity_logger.rb
2026-08-13 19:56:46 +03:30

82 lines
2.6 KiB
Ruby

# frozen_string_literal: true
module Barong
# admin activities log writer class
class ActivityLogger
ACTION = { post: 'create', put: 'update', get: 'read', delete: 'delete', patch: 'update' }.freeze
def self.async_write(options = {})
@activities ||= Queue.new
@activities.push(options)
@thread ||= Thread.new do
begin
loop do
msg = @activities.pop
params = format_params(msg)
Rails.logger.info("Recording activity for user id: #{params[:user_id]}, topic: #{params[:topic]}," \
" action: #{params[:action]}, result: #{params[:result]}, data: #{params[:data]}")
Activity.create(params)
rescue StandardError => e
Rails.logger.error { "Failed to create activity with params: #{params}\n" \
"Inspect error: #{e.inspect}\n#{e.backtrace.join("\n")}" }
# If system catch Mysql2::Error::ConnectionError
# System will reconnect to DB and push message again to the activities queue
if e.is_a? (ActiveRecord::StatementInvalid)
ActiveRecord::Base.connection.reconnect!
sleep(0.1)
@activities.push(options)
end
end
end
end
end
def self.sync_write(options = {})
Activity.create(format_params(options))
end
def self.format_params(params)
topic = params[:topic].nil? && params[:path].split('admin/')[1].nil? ? 'general' : params[:topic] || params[:path].split('admin/')[1].split('/')[0]
{
user_id: params[:user_id],
target_uid: target_user(params[:payload]) || '',
user_ip: params[:user_ip],
user_agent: params[:user_agent],
topic: topic,
action: ACTION[params[:verb].downcase.to_sym] || 'system',
result: params[:result],
category: 'admin',
data: format_payload(params[:payload])
}
end
def self.format_payload(payload)
return unless payload
return payload.to_json unless valid_json?(payload.keys.first)
payload.keys.first
end
def self.target_user(payload)
# in case payload is missing || empty POST body: payload => {"null" => nil }
return if payload.nil? || payload.keys.first == "null"
if valid_json?(payload.keys.first)
payload = JSON.parse(payload.keys.first)
end
payload[:uid] || payload[:user_uid] || payload['uid'] || payload['user_uid']
end
def self.valid_json?(json)
JSON.parse(json)
true
rescue JSON::ParserError => e
false
end
end
end