消息发送:ActiveSupport::Notifications
instrument: 通知subscribers
消息订阅:ActiveSupport::LogSubscriber
require 'active_support/configurable' module RailsLog include ActiveSupport::Configurable configure do |config| config.ignore_exception = [ 'ActionController::UnknownFormat' ] config.constraint = -> (req){ User.find_by(id: req.env['rack.session']['user_id'])&.admin? } end end
module RailsLog class ControllerSubscriber < ActiveSupport::LogSubscriber def header_processing(event) return unless logger.debug? payload = event.payload headers = request_headers(payload[:env]) debug " Headers: #{headers.inspect}" end def process_action(event) payload = event.payload if payload[:exception].present? unless RailsLog.config.ignore_exception.include? payload[:exception_object].class.to_s lc = LogRecord.new lc.path = payload[:path] lc.controller = payload[:controller] lc.action = payload[:action] lc.params = payload[:params].except('controller', 'action') lc.headers = request_headers payload[:headers] lc.cookie = payload[:headers]['rack.request.cookie_hash'] lc.session = payload[:headers]['rack.session'].to_hash lc.exception = payload[:exception].join("\r\n") lc.exception_object = payload[:exception_object].class.to_s lc.exception_backtrace = payload[:exception_object].backtrace.join("\r\n") lc.save info 'exception log saved!' end end end def logger ActionController::Base.logger end def request_headers(env) result = env.select { |k, _| k.start_with?('HTTP_') && k != 'HTTP_COOKIE' } result = result.collect { |pair| [pair[0].sub(/^HTTP_/, ''), pair[1]] } result.sort.to_h end end end RailsLog::ControllerSubscriber.attach_to :action_controller
发送邮件的时候记录日志
class ApplicationMailer < ActionMailer::Base def process(method_name, *args) payload = { mailer: self.class.name, action: method_name, message_object_id: self.message.object_id, params: args } ActiveSupport::Notifications.instrument('record.action_mailer', payload) super end def self.deliver_mail(mail) ActiveSupport::Notifications.instrument('deliver.action_mailer') do |payload| set_payload_for_mail(payload, mail) payload[:message_object_id] = mail.object_id result = yield if result.is_a? Net::SMTP::Response payload[:sent_status] = result.status payload[:sent_string] = result.string end end end end ------- module RailsLog class MailerSubscriber < ActiveSupport::LogSubscriber def record(event) payload = event.payload log_mailer = LogMailer.new(message_object_id: payload[:message_object_id], mailer: payload[:mailer]) log_mailer.action = payload[:action] log_mailer.params = payload[:params] log_mailer.save info 'mailer log saved!' end def deliver(event) payload = event.payload log_mailer = LogMailer.find_or_initialize_by(message_object_id: payload[:message_object_id], mailer: payload[:mailer]) log_mailer.sent_status = payload[:sent_status] log_mailer.sent_string = payload[:sent_string] log_mailer.save info 'mailer log updated!' end end end RailsLog::MailerSubscriber.attach_to :action_mailer