diff options
author | elijah <elijah@riseup.net> | 2016-10-05 14:35:56 -0700 |
---|---|---|
committer | elijah <elijah@riseup.net> | 2016-10-05 14:35:56 -0700 |
commit | 7abfbd6abae14fa6a72350f7b75268ff561354ee (patch) | |
tree | af5c969c905a8d2a95f2b2aa7c4dd6f4b8763126 /lib/leap_cli/log.rb | |
parent | cc57bc6c0ff99d88f3bfeff1b04297e9b91e6988 (diff) | |
parent | f95e08ef7d8defbde4a19e138b1ac4ebc9677669 (diff) |
Merge branch 'develop'
# Conflicts:
# lib/leap_cli/version.rb
Diffstat (limited to 'lib/leap_cli/log.rb')
-rw-r--r-- | lib/leap_cli/log.rb | 284 |
1 files changed, 196 insertions, 88 deletions
diff --git a/lib/leap_cli/log.rb b/lib/leap_cli/log.rb index 6589ad4..af2fae7 100644 --- a/lib/leap_cli/log.rb +++ b/lib/leap_cli/log.rb @@ -1,58 +1,84 @@ -require 'paint' - ## ## LOGGING ## -## Ugh. This class does not work well with multiple threads! -## module LeapCli - extend self + module LogCommand + @@logger = nil - attr_accessor :log_in_color + def log(*args, &block) + logger.log(*args, &block) + end - # logging options - def log_level - @log_level ||= 1 - end - def set_log_level(value) - @log_level = value - end + def log_raw(*args, &block) + logger.log_raw(*args, &block) + end - def indent_level - @indent_level ||= 0 - end - def indent_level=(value) - @indent_level = value - end + # global shared logger + def logger + @@logger ||= LeapCli::LeapLogger.new + end - def log_file - @log_file - end - def log_file=(value) - @log_file = value - if @log_file - if !File.directory?(File.dirname(@log_file)) - Util.bail!('Invalid log file "%s", directory "%s" does not exist' % [@log_file, File.dirname(@log_file)]) - end - @log_output_stream = File.open(@log_file, 'a') + # thread safe logger + def new_logger + logger.dup end - end - def log_output_stream - @log_output_stream - end + # deprecated + def log_level + logger.log_level + end + + # + # These probably should have been part of the logger originally, + # but they are made available here for convenience: + # + + def bail!(*args, &block) + Util.bail!(*args, &block) + end + def assert!(*args, &block) + Util.assert!(*args, &block) + end + + end end module LeapCli - module Log + class LeapLogger # # these are log titles typically associated with files # - FILE_TITLES = [:updated, :created, :removed, :missing, :nochange, :loading] + FILE_TITLES = %w(updated created removed missing nochange loading) + + # TODO: use these + IMPORTANT = 0 + INFO = 1 + DEBUG = 2 + TRACE = 3 + attr_reader :log_output_stream, :log_file + attr_accessor :indent_level, :log_level, :log_in_color + + def initialize() + @log_level = 1 + @indent_level = 0 + @log_file = nil + @log_output_stream = nil + @log_in_color = true + end + + def log_file=(value) + @log_file = value + if @log_file + if !File.directory?(File.dirname(@log_file)) + Util.bail!('Invalid log file "%s", directory "%s" does not exist' % [@log_file, File.dirname(@log_file)]) + end + @log_output_stream = File.open(@log_file, 'a') + end + end # # master logging function. @@ -63,74 +89,95 @@ module LeapCli # * Integer: the log level (0, 1, 2) # * Symbol: the prefix title to colorize. may be one of # [:error, :warning, :info, :updated, :created, :removed, :no_change, :missing] - # * Hash: a hash of options. so far, only :indent is supported. + # * Hash: a hash of options. + # :wrap -- if true, appy intend to each line in message. + # :color -- apply color to message or prefix + # :style -- apply style to message or prefix # - def log(*args) level = args.grep(Integer).first || 1 title = args.grep(Symbol).first message = args.grep(String).first options = args.grep(Hash).first || {} - unless message && LeapCli.log_level >= level + host = options[:host] + if title + title = title.to_s + end + if @log_level < level || (title.nil? && message.nil?) return end - # prefix - clear_prefix = colored_prefix = "" - if title - prefix_options = case title - when :error then ['error', :red, :bold] - when :fatal_error then ['fatal error:', :red, :bold] - when :warning then ['warning:', :yellow, :bold] - when :info then ['info', :cyan, :bold] - when :note then ['NOTE:', :cyan, :bold] - when :updated then ['updated', :cyan, :bold] - when :updating then ['updating', :cyan, :bold] - when :created then ['created', :green, :bold] - when :removed then ['removed', :red, :bold] - when :nochange then ['no change', :magenta] - when :loading then ['loading', :magenta] - when :missing then ['missing', :yellow, :bold] - when :skipping then ['skipping', :yellow, :bold] - when :run then ['run', :magenta] - when :failed then ['FAILED', :red, :bold] - when :completed then ['completed', :green, :bold] - when :ran then ['ran', :green, :bold] - when :bail then ['bailing out', :red, :bold] - when :invalid then ['invalid', :red, :bold] - else [title.to_s, :cyan, :bold] - end - if options[:host] - clear_prefix = "[%s] %s " % [options[:host], prefix_options[0]] - colored_prefix = "[%s] %s " % [Paint[options[:host], prefix_options[1], prefix_options[2]], prefix_options[0]] + # + # transform absolute path names + # + if title && FILE_TITLES.include?(title) && message =~ /^\// + message = LeapCli::Path.relative_path(message) + end + + # + # apply filters + # LogFilter will not be defined if no platform was loaded. + # + if defined?(LeapCli::LogFilter) + if title + title, filter_flags = LogFilter.apply_title_filters(title) else - clear_prefix = "%s " % prefix_options[0] - colored_prefix = "%s " % Paint[prefix_options[0], prefix_options[1], prefix_options[2]] + message, filter_flags = LogFilter.apply_message_filters(message) + return if message.nil? end - elsif options[:host] - clear_prefix = colored_prefix = "[%s] " % options[:host] + options = options.merge(filter_flags) end - # transform absolute path names - if title && FILE_TITLES.include?(title) && message =~ /^\// - message = LeapCli::Path.relative_path(message) + # + # set line prefix + # + if (host) + host = host.split('.').first end + prefix = prefix_str(host, title) - log_raw(:log, nil) { [clear_prefix, message].join } - if LeapCli.log_in_color - log_raw(:stdout, options[:indent]) { [colored_prefix, message].join } - else - log_raw(:stdout, options[:indent]) { [clear_prefix, message].join } + # + # write to the log file, always + # + log_raw(:log, nil, prefix) { message } + + # + # log to stdout, maybe in color + # + if @log_in_color + if options[:wrap] + message = message.split("\n") + end + if options[:color] + if host + host = colorize(host, options[:color], options[:style]) + elsif title + title = colorize(title, options[:color], options[:style]) + else + message = colorize(message, options[:color], options[:style]) + end + elsif title + title = colorize(title, :cyan, :bold) + end + # new colorized prefix: + prefix = prefix_str(host, title) end + log_raw(:stdout, options[:indent], prefix) { message } - # run block, if given + # + # run block indented, if given + # if block_given? - LeapCli.indent_level += 1 + @indent_level += 1 yield - LeapCli.indent_level -= 1 + @indent_level -= 1 end end + def debug(*args) + self.log(3, *args) + end + # # Add a raw log entry, without any modifications (other than indent). # Content to be logged is yielded by the block. @@ -139,23 +186,26 @@ module LeapCli # if mode == :stdout, output is sent to STDOUT. # if mode == :log, output is sent to log file, if present. # - def log_raw(mode, indent=nil, &block) - # NOTE: print message (using 'print' produces better results than 'puts' when multiple threads are logging) + def log_raw(mode, indent=nil, prefix=nil, &block) + # NOTE: using 'print' produces better results than 'puts' + # when multiple threads are logging) if mode == :log - if LeapCli.log_output_stream + if @log_output_stream messages = [yield].compact.flatten if messages.any? timestamp = Time.now.strftime("%b %d %H:%M:%S") messages.each do |message| - LeapCli.log_output_stream.print("#{timestamp} #{message}\n") + message = message.rstrip + next if message.empty? + @log_output_stream.print("#{timestamp} #{prefix} #{message}\n") end - LeapCli.log_output_stream.flush + @log_output_stream.flush end end elsif mode == :stdout messages = [yield].compact.flatten if messages.any? - indent ||= LeapCli.indent_level + indent ||= @indent_level indent_str = "" indent_str += " " * indent.to_i if indent.to_i > 0 @@ -163,12 +213,70 @@ module LeapCli else indent_str += ' = ' end + indent_str += prefix if prefix messages.each do |message| + message = message.rstrip + next if message.empty? STDOUT.print("#{indent_str}#{message}\n") end end end end + def colorize(str, color, style=nil) + codes = [FG_COLORS[color] || FG_COLORS[:default]] + if style + codes << EFFECTS[style] || EFFECTS[:nothing] + end + if str.is_a?(String) + ["\033[%sm" % codes.join(';'), str, NO_COLOR].join + elsif str.is_a?(Array) + str.map { |s| + ["\033[%sm" % codes.join(';'), s, NO_COLOR].join + } + end + end + + private + + def prefix_str(host, title) + prefix = "" + prefix += "[" + host + "] " if host + prefix += title + " " if title + prefix += " " if !prefix.empty? && prefix !~ / $/ + return prefix + end + + EFFECTS = { + :reset => 0, :nothing => 0, + :bright => 1, :bold => 1, + :underline => 4, + :inverse => 7, :swap => 7, + } + NO_COLOR = "\033[0m" + FG_COLORS = { + :black => 30, + :red => 31, + :green => 32, + :yellow => 33, + :blue => 34, + :magenta => 35, + :cyan => 36, + :white => 37, + :default => 39, + } + BG_COLORS = { + :black => 40, + :red => 41, + :green => 42, + :yellow => 43, + :blue => 44, + :magenta => 45, + :cyan => 46, + :white => 47, + :default => 49, + } + end -end
\ No newline at end of file +end + |