# frozen_string_literal: true module Log class Log class LogFormatter < Logger::Formatter attr_reader :options def initialize(options = {}) @options = options super() # superclass does not take parameters end def call(severity, timestamp, progname, msg) super(severity, timestamp, progname, "#{log_tags}#{msg}") end def log_tags tags = formatted_tags.join ' ' tags.blank? ? '' : "[#{tags}] " end private def formatted_tags elems = [Thread.current[:name].to_s] elems += (options[:tags] || []).map { |e| e.is_a?(Proc) ? e.call : e } elems.reject(&:blank?) end end attr_reader :options # default = {} # Options may include: # tags: an array of static elements and/or callable Procs to include in log output # filename: specifies filename for log in Rails log directory # stream: specifies stream for log output (included for test support) def initialize(options = {}) @options = options end def logger @logger ||= begin new_logger = Logger.new log_destination new_logger.level = numeric_log_level new_logger.formatter = LogFormatter.new options new_logger end end def numeric_log_level AppConfig.numeric_log_level end # Returns filename for log or stream object if specified in options. def log_destination options[:stream].present? ? options[:stream] : log_filepath end def log_filepath @log_filepath ||= log_dir.join log_filename end def log_filename options[:filename].present? ? options[:filename].to_s : "#{Rails.env.to_s}.log" end def log_dir @log_dir ||= begin dir = Rails.root.join 'log' FileUtils.mkdir_p dir dir end end # Same semantics as Log.error except uses current instance of logger. def error(msg, exception = nil, options = {}) Log.log_error logger, msg, exception, options end # Same semantics as Log.raise_error except uses current instance of logger. def raise_error(msg, exception, options = {}) error msg, exception, options raise exception end class << self # Logs and re-raises exception. def raise_error (msg, exception, options = {}) error msg, exception, options raise exception end # Logs error with exception backtrace detail if available. Always uses Rails.logger. # # Options may include: # no_backtrace: true suppresses backtrace # # Returns formatted msg. def error(msg, exception = nil, options = {}) log_error Rails.logger, msg, exception, options end # Same semantics as Log.error except uses specified logger. def log_error(logger, msg, exception = nil, options = {}) message = exception.nil? ? msg : "Exception #{exception.class.name}: #{exception.inspect} #{msg}" logger.error message logger.error exception.backtrace if exception.try(:backtrace) && !options[:no_backtrace] message end end end end