lib/backup/logger.rb in backup-3.0.27 vs lib/backup/logger.rb in backup-3.1.0

- old
+ new

@@ -1,152 +1,150 @@ # encoding: utf-8 +require 'backup/logger/console' +require 'backup/logger/logfile' +require 'backup/logger/syslog' + module Backup module Logger - class << self - attr_accessor :quiet - - ## - # Outputs a messages to the console and writes it to the backup.log - def message(string) - to_console loggify(string, :message, :green) - to_file loggify(string, :message) + class Config + class Logger < Struct.new(:class, :options) + def enabled? + options.enabled? + end end - ## - # Outputs an error to the console and writes it to the backup.log - # Called when an Exception has caused the backup process to abort. - def error(string) - to_console loggify(string, :error, :red), true - to_file loggify(string, :error) - end + DSL = Struct.new(:console, :logfile, :syslog) - ## - # Outputs a notice to the console and writes it to the backup.log - # Sets #has_warnings? true so :on_warning notifications will be sent - def warn(string) - @has_warnings = true - to_console loggify(string, :warning, :yellow), true - to_file loggify(string, :warning) - end + attr_reader :loggers, :dsl - # Outputs the data as if it were a regular 'puts' command, - # but also logs it to the backup.log - def normal(string) - to_console loggify(string) - to_file loggify(string) + def initialize + @loggers = [ + Logger.new(Console, Console::Options.new), + Logger.new(Logfile, Logfile::Options.new), + Logger.new(Syslog, Syslog::Options.new) + ] + @dsl = DSL.new(*@loggers.map(&:options)) end + end + ## + # All messages sent to the Logger are stored in Logger.messages + # and sent to all enabled logger's #log method as Message objects. + class Message < Struct.new(:time, :level, :lines) ## - # Silently logs data to the log file - def silent(string) - to_file loggify(string, :silent) + # Returns an Array of the message lines in the following format: + # + # [YYYY/MM/DD HH:MM:SS][level] message line text + def formatted_lines + timestamp = time.strftime("%Y/%m/%d %H:%M:%S") + lines.map {|line| "[#{ timestamp }][#{ level }] #{ line }" } end + end + class << self ## - # Returns an Array of all messages written to the log file for this session - def messages - @messages ||= [] - end + # Returns an Array of Message objects for all logged messages received. + # These are used to attach log files to Mail notifications. + attr_reader :messages ## - # Returns true if any warnings have been issued - def has_warnings? - @has_warnings ||= false + # Allows the Logger to be configured. + # + # # shown with their default values + # Backup::Logger.configure do + # # Console options: + # console.quiet = false + # + # # Logfile options: + # logfile.enabled = true + # logfile.log_path = 'log' + # logfile.max_bytes = 500_000 + # + # # Syslog options: + # syslog.enabled = false + # syslog.ident = 'backup' + # syslog.options = Syslog::LOG_PID + # syslog.facility = Syslog::LOG_LOCAL0 + # syslog.info = Syslog::LOG_INFO + # syslog.warn = Syslog::LOG_WARNING + # syslog.error = Syslog::LOG_ERR + # end + # + # See each Logger's Option class for details. + # @see Console::Options + # @see Logfile::Options + # @see Syslog::Options + def configure(&block) + @config.dsl.instance_eval(&block) end - def clear! - messages.clear - @has_warnings = false + ## + # Sends a message to the Logger using the specified log level. + # +obj+ may be any Object that responds to #to_s (i.e. an Exception) + [:info, :warn, :error].each do |level| + define_method level, lambda {|obj| log(obj, level) } end - def truncate!(max_bytes = 500_000) - log_file = File.join(Config.log_path, 'backup.log') - return unless File.exist?(log_file) - - if File.stat(log_file).size > max_bytes - FileUtils.mv(log_file, log_file + '~') - File.open(log_file + '~', 'r') do |io_in| - File.open(log_file, 'w') do |io_out| - io_in.seek(-max_bytes, IO::SEEK_END) && io_in.gets - while line = io_in.gets - io_out.puts line - end - end - end - FileUtils.rm_f(log_file + '~') - end - end - - private - ## - # Returns the time in [YYYY/MM/DD HH:MM:SS] format - def time - Time.now.strftime("%Y/%m/%d %H:%M:%S") + # Returns true if any +:warn+ level messages have been received. + def has_warnings? + @has_warnings end ## - # Receives a String, or an Object that responds to #to_s (e.g. an - # Exception), from one of the messaging methods and converts it into an - # Array of Strings, split on newline separators. Each line is then - # formatted into a log format based on the given options, and the Array - # returned to be passed to to_console() and/or to_file(). - def loggify(string, type = false, color = false) - lines = string.to_s.split("\n") - if type - type = send(color, type) if color - time_now = time - lines.map {|line| "[#{time_now}][#{type}] #{line}" } - else - lines + # The Logger is available as soon as Backup is loaded, and stores all + # messages it receives. Since the Logger may be configured via the + # command line and/or the user's +config.rb+, no messages are sent + # until configuration can be completed. (see CLI#perform) + # + # Once configuration is completed, this method is called to activate + # all enabled loggers and send them any messages that have been received + # up to this point. From this point onward, these loggers will be sent + # all messages as soon as they're received. + def start! + @config.loggers.each do |logger| + @loggers << logger.class.new(logger.options) if logger.enabled? end + @messages.each do |message| + @loggers.each {|logger| logger.log(message) } + end end ## - # Receives an Array of Strings to be written to the console. - def to_console(lines, stderr = false) - return if quiet - lines.each {|line| stderr ? Kernel.warn(line) : puts(line) } + # Called after each backup model/trigger has been performed. + def clear! + messages.clear + @has_warnings = false end ## - # Receives an Array of Strings to be written to the log file. - def to_file(lines) - File.open(File.join(Config.log_path, 'backup.log'), 'a') do |file| - lines.each {|line| file.puts line } - end - messages.push(*lines) + # If errors are encountered by Backup::CLI while preparing to perform + # the backup jobs, this method is called to dump all messages to the + # console before Backup exits. + def abort! + console = Console.new + console.log(@messages.shift) until @messages.empty? end - ## - # Invokes the #colorize method with the provided string - # and the color code "32" (for green) - def green(string) - colorize(string, 32) - end + private - ## - # Invokes the #colorize method with the provided string - # and the color code "33" (for yellow) - def yellow(string) - colorize(string, 33) + def initialize! + @messages = [] + @loggers = [] + @config = Config.new + @has_warnings = false end - ## - # Invokes the #colorize method the with provided string - # and the color code "31" (for red) - def red(string) - colorize(string, 31) + def log(obj, level) + @has_warnings ||= level == :warn + message = Message.new(Time.now, level, obj.to_s.split("\n")) + @messages << message + @loggers.each {|logger| logger.log(message) } end - ## - # Wraps the provided string in colorizing tags to provide - # easier to view output to the client - def colorize(string, code) - "\e[#{code}m#{string}\e[0m" - end - end + + initialize! end end