lib/yard/logging.rb in yard-0.9.36 vs lib/yard/logging.rb in yard-0.9.37

- old
+ new

@@ -1,91 +1,156 @@ # encoding: utf-8 # frozen_string_literal: true -require 'logger' require 'thread' module YARD # Handles console logging for info, warnings and errors. # Uses the stdlib Logger class in Ruby for all the backend logic. - class Logger < ::Logger + class Logger + # Log severity levels + module Severity + # Debugging log level + DEBUG = 0 + + # Information log level + INFO = 1 + + # Warning log level + WARN = 2 + + # Error log level + ERROR = 3 + + # Fatal log level + FATAL = 4 + + # Unknown log level + UNKNOWN = 5 + + # @private + SEVERITIES = { + DEBUG => :debug, + INFO => :info, + WARN => :warn, + ERROR => :error, + FATAL => :fatal, + UNKNOWN => :unknown + } + end + + include Severity + # The list of characters displayed beside the progress bar to indicate # "movement". # @since 0.8.2 PROGRESS_INDICATORS = %w(⣷ ⣯ ⣟ ⡿ ⢿ ⣻ ⣽ ⣾) # @return [IO] the IO object being logged to # @since 0.8.2 - def io; @logdev end - def io=(pipe) @logdev = pipe end + attr_accessor :io # @return [Boolean] whether backtraces should be shown (by default # this is on). def show_backtraces; @show_backtraces || level == DEBUG end attr_writer :show_backtraces + # @return [DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN] the logging level + attr_accessor :level + + # @return [Boolean] whether a warn message has been emitted. Used for status tracking. + attr_accessor :warned + # @return [Boolean] whether progress indicators should be shown when # logging CLIs (by default this is off). def show_progress return false if YARD.ruby18? # threading is too ineffective for progress support - return false if YARD.windows? # windows has poor ANSI support return false unless io.tty? # no TTY support on IO return false unless level > INFO # no progress in verbose/debug modes @show_progress end attr_writer :show_progress + # @!group Constructor Methods + # The logger instance # @return [Logger] the logger instance def self.instance(pipe = STDOUT) @logger ||= new(pipe) end # Creates a new logger + # @private def initialize(pipe, *args) - super(pipe, *args) self.io = pipe self.show_backtraces = true self.show_progress = false self.level = WARN - self.formatter = method(:format_log) self.warned = false @progress_indicator = 0 @mutex = Mutex.new @progress_msg = nil @progress_last_update = Time.now end - # Changes the debug level to DEBUG if $DEBUG is set - # and writes a debugging message. - def debug(*args) - self.level = DEBUG if $DEBUG - super + # @!macro [attach] logger.create_log_method + # @method $1(message) + # Logs a message with the $1 severity level. + # @param message [String] the message to log + # @see #log + # @return [void] + # @private + def self.create_log_method(name) + severity = Severity.const_get(name.to_s.upcase) + define_method(name) { |message| log(severity, message) } end + # @!group Logging Methods + + create_log_method :info + create_log_method :error + create_log_method :fatal + create_log_method :unknown + + # Changes the debug level to DEBUG if $DEBUG is set and writes a debugging message. + create_log_method :debug + # Remembers when a warning occurs and writes a warning message. - def warn(*args) - self.warned = true - super + create_log_method :warn + + # Logs a message with a given severity + # @param severity [DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN] the severity level + # @param message [String] the message to log + def log(severity, message) + self.level = DEBUG if $DEBUG + return unless severity >= level + + self.warned = true if severity == WARN + clear_line + puts "[#{SEVERITIES[severity].to_s.downcase}]: #{message}" end - attr_accessor :warned - # Captures the duration of a block of code for benchmark analysis. Also - # calls {#progress} on the message to display it to the user. + # @!group Level Control Methods + + # Sets the logger level for the duration of the block # - # @todo Implement capture storage for reporting of benchmarks - # @param [String] msg the message to display - # @param [Symbol, nil] nontty_log the level to log as if the output - # stream is not a TTY. Use +nil+ for no alternate logging. - # @yield a block of arbitrary code to benchmark - # @return [void] - def capture(msg, nontty_log = :debug) - progress(msg, nontty_log) + # @example + # log.enter_level(Logger::ERROR) do + # YARD.parse_string "def x; end" + # end + # @param [Fixnum] new_level the logger level for the duration of the block. + # values can be found in Ruby's Logger class. + # @yield the block with the logger temporarily set to +new_level+ + def enter_level(new_level = level) + old_level = level + self.level = new_level yield ensure - clear_progress + self.level = old_level end + # @!group Utility Printing Methods + # Displays a progress indicator for a given message. This progress report # is only displayed on TTY displays, otherwise the message is passed to # the +nontty_log+ level. # # @param [String] msg the message to log @@ -118,11 +183,11 @@ # Clears the progress indicator in the TTY display. # @return [void] # @since 0.8.2 def clear_progress return unless show_progress - print_no_newline("\e[?25h\e[2K") + io.write("\e[?25h\e[2K") @progress_msg = nil end # Displays an unformatted line to the logger output stream, adding # a newline. @@ -131,20 +196,17 @@ # @since 0.8.2 def puts(msg = '') print("#{msg}\n") end - alias print_no_newline << - private :print_no_newline - # Displays an unformatted line to the logger output stream. # @param [String] msg the message to display # @return [void] # @since 0.8.2 def print(msg = '') clear_line - print_no_newline(msg) + io.write(msg) end alias << print # Prints the backtrace +exc+ to the logger as error data. # @@ -156,50 +218,43 @@ send(level_meth, "#{exc.class.class_name}: #{exc.message}") send(level_meth, "Stack trace:" + exc.backtrace[0..5].map {|x| "\n\t#{x}" }.join + "\n") end + # @!group Benchmarking Methods + + # Captures the duration of a block of code for benchmark analysis. Also + # calls {#progress} on the message to display it to the user. + # + # @todo Implement capture storage for reporting of benchmarks + # @param [String] msg the message to display + # @param [Symbol, nil] nontty_log the level to log as if the output + # stream is not a TTY. Use +nil+ for no alternate logging. + # @yield a block of arbitrary code to benchmark + # @return [void] + def capture(msg, nontty_log = :debug) + progress(msg, nontty_log) + yield + ensure + clear_progress + end + + # @!endgroup + # Warns that the Ruby environment does not support continuations. Applies # to JRuby, Rubinius and MacRuby. This warning will only display once # per Ruby process. # # @deprecated Continuations are no longer needed by YARD 0.8.0+. # @return [void] + # @private def warn_no_continuations end - # Sets the logger level for the duration of the block - # - # @example - # log.enter_level(Logger::ERROR) do - # YARD.parse_string "def x; end" - # end - # @param [Fixnum] new_level the logger level for the duration of the block. - # values can be found in Ruby's Logger class. - # @yield the block with the logger temporarily set to +new_level+ - def enter_level(new_level = level) - old_level = level - self.level = new_level - yield - ensure - self.level = old_level - end - private - # Override this internal Logger method to clear line - def add(*args) - clear_line - super(*args) - end - def clear_line return unless @progress_msg - print_no_newline("\e[2K\r") - end - - # Log format (from Logger implementation). Used by Logger internally - def format_log(sev, _time, _prog, msg) - "[#{sev.downcase}]: #{msg}\n" + io.write("\e[2K\r") end end end