summaryrefslogtreecommitdiff
path: root/lib/leap_cli/log.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/leap_cli/log.rb')
-rw-r--r--lib/leap_cli/log.rb284
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
+