From 4a73e099b7504b1d81d96d9b395e185821516f14 Mon Sep 17 00:00:00 2001 From: Peter Rhoades Date: Sat, 24 May 2014 15:00:14 +0100 Subject: [PATCH 1/3] Allow Jekyll's logger to be set to any Logger compatible instance * Stevenson now inherits from Logger and extends some methods to use $stderr for log messages greater than info level. * LogWriter provides an interface between Jekyll and Logger to maintain API. --- lib/jekyll.rb | 7 ++- lib/jekyll/log_writer.rb | 103 +++++++++++++++++++++++++++++++ lib/jekyll/stevenson.rb | 129 ++++++++++++--------------------------- 3 files changed, 147 insertions(+), 92 deletions(-) create mode 100644 lib/jekyll/log_writer.rb diff --git a/lib/jekyll.rb b/lib/jekyll.rb index 26c6e569..b8e65c00 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -31,6 +31,7 @@ require 'toml' # internal requires require 'jekyll/version' require 'jekyll/utils' +require 'jekyll/log_writer' require 'jekyll/stevenson' require 'jekyll/deprecator' require 'jekyll/configuration' @@ -115,7 +116,11 @@ module Jekyll end def self.logger - @logger ||= Stevenson.new + @logger ||= LogWriter.new(Stevenson.new) + end + + def self.logger=(writer) + @logger = LogWriter.new(writer) end # Public: File system root diff --git a/lib/jekyll/log_writer.rb b/lib/jekyll/log_writer.rb new file mode 100644 index 00000000..c9320585 --- /dev/null +++ b/lib/jekyll/log_writer.rb @@ -0,0 +1,103 @@ +require 'logger' +module Jekyll + class LogWriter + attr_reader :writer + + LOG_LEVELS = { + debug: 0, + info: 1, + warn: 2, + error: 3 + } + + # Public: Create a new instance of Jekyll's log writer + # + # writer - Logger compatible instance + # log_level - (optional, symbol) the log level + # + # Returns nothing + def initialize(writer, level = :info) + @writer = writer + self.log_level = level + end + + # Public: Set the log level on the writer + # + # level - (symbol) the log level + # + # Returns nothing + def log_level=(level) + writer.level = LOG_LEVELS.fetch(level) + end + + # Public: Print a jekyll debug message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def debug(topic, message = nil) + writer.debug(message(topic, message)) + end + + # Public: Print a jekyll message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def info(topic, message = nil) + writer.info(message(topic, message)) + end + + # Public: Print a jekyll message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def warn(topic, message = nil) + writer.warn(message(topic, message).yellow) + end + + # Public: Print a jekyll error message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def error(topic, message = nil) + writer.error(message(topic, message).red) + end + + # Public: Print a Jekyll error message and immediately abort the process + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail (can be omitted) + # + # Returns nothing + def abort_with(topic, message = nil) + error(topic, message) + abort + end + + # Public: Build a Jekyll topic method + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns the formatted message + def message(topic, message) + formatted_topic(topic) + message.to_s.gsub(/\s+/, ' ') + end + + # Public: Format the topic + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # + # Returns the formatted topic statement + def formatted_topic(topic) + "#{topic} ".rjust(20) + end + end +end diff --git a/lib/jekyll/stevenson.rb b/lib/jekyll/stevenson.rb index b50368c1..f940fa4a 100644 --- a/lib/jekyll/stevenson.rb +++ b/lib/jekyll/stevenson.rb @@ -1,102 +1,49 @@ +require 'logger' module Jekyll - class Stevenson - attr_accessor :log_level - - LOG_LEVELS = { - debug: 0, - info: 1, - warn: 2, - error: 3 - } - - # Public: Create a new instance of Stevenson, Jekyll's logger - # - # level - (optional, symbol) the log level - # - # Returns nothing - def initialize(level = :info) - @log_level = level + class Stevenson < ::Logger + def initialize + @progname = nil + @level = DEBUG + @default_formatter = Formatter.new + @logdev = $stdout + @formatter = proc do |severity, datetime, progname, msg| + "#{msg}" + end end - # Public: Print a jekyll debug message to stdout - # - # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. - # message - the message detail - # - # Returns nothing - def debug(topic, message = nil) - $stdout.puts(message(topic, message)) if should_log(:debug) + def add(severity, message = nil, progname = nil, &block) + severity ||= UNKNOWN + @logdev = set_logdevice(severity) + + if @logdev.nil? or severity < @level + return true + end + progname ||= @progname + if message.nil? + if block_given? + message = yield + else + message = progname + progname = @progname + end + end + @logdev.puts( + format_message(format_severity(severity), Time.now, progname, message)) + true end - # Public: Print a jekyll message to stdout - # - # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. - # message - the message detail - # - # Returns nothing - def info(topic, message = nil) - $stdout.puts(message(topic, message)) if should_log(:info) + def close + # No LogDevice in use end - # Public: Print a jekyll message to stderr - # - # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. - # message - the message detail - # - # Returns nothing - def warn(topic, message = nil) - $stderr.puts(message(topic, message).yellow) if should_log(:warn) - end + private - # Public: Print a jekyll error message to stderr - # - # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. - # message - the message detail - # - # Returns nothing - def error(topic, message = nil) - $stderr.puts(message(topic, message).red) if should_log(:error) - end - - # Public: Print a Jekyll error message to stderr and immediately abort the process - # - # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. - # message - the message detail (can be omitted) - # - # Returns nothing - def abort_with(topic, message = nil) - error(topic, message) - abort - end - - # Public: Build a Jekyll topic method - # - # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. - # message - the message detail - # - # Returns the formatted message - def message(topic, message) - formatted_topic(topic) + message.to_s.gsub(/\s+/, ' ') - end - - # Public: Format the topic - # - # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. - # - # Returns the formatted topic statement - def formatted_topic(topic) - "#{topic} ".rjust(20) - end - - # Public: Determine whether the current log level warrants logging at the - # proposed level. - # - # level_of_message - the log level of the message (symbol) - # - # Returns true if the log level of the message is greater than or equal to - # this logger's log level. - def should_log(level_of_message) - LOG_LEVELS.fetch(log_level) <= LOG_LEVELS.fetch(level_of_message) + def set_logdevice(severity) + if severity > INFO + $stderr + else + $stdout + end end end end From e6345f39a9aad3ebc3da67aa1bb6610f9d5c2847 Mon Sep 17 00:00:00 2001 From: Peter Rhoades Date: Sat, 24 May 2014 21:22:10 +0100 Subject: [PATCH 2/3] Renaming LogWriter to LogAdapter and adding tests for class String coloring moved to Stevenson as not responsibility of LogAdapter --- lib/jekyll.rb | 7 ++- lib/jekyll/{log_writer.rb => log_adapter.rb} | 12 ++-- lib/jekyll/stevenson.rb | 11 +++- test/test_log_adapter.rb | 59 ++++++++++++++++++++ 4 files changed, 80 insertions(+), 9 deletions(-) rename lib/jekyll/{log_writer.rb => log_adapter.rb} (92%) create mode 100644 test/test_log_adapter.rb diff --git a/lib/jekyll.rb b/lib/jekyll.rb index b8e65c00..b79880f2 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -21,6 +21,7 @@ require 'time' require 'safe_yaml/load' require 'English' require 'pathname' +require 'logger' # 3rd party require 'liquid' @@ -31,7 +32,7 @@ require 'toml' # internal requires require 'jekyll/version' require 'jekyll/utils' -require 'jekyll/log_writer' +require 'jekyll/log_adapter' require 'jekyll/stevenson' require 'jekyll/deprecator' require 'jekyll/configuration' @@ -116,11 +117,11 @@ module Jekyll end def self.logger - @logger ||= LogWriter.new(Stevenson.new) + @logger ||= LogAdapter.new(Stevenson.new) end def self.logger=(writer) - @logger = LogWriter.new(writer) + @logger = LogAdapter.new(writer) end # Public: File system root diff --git a/lib/jekyll/log_writer.rb b/lib/jekyll/log_adapter.rb similarity index 92% rename from lib/jekyll/log_writer.rb rename to lib/jekyll/log_adapter.rb index c9320585..5c4fb952 100644 --- a/lib/jekyll/log_writer.rb +++ b/lib/jekyll/log_adapter.rb @@ -1,6 +1,6 @@ require 'logger' module Jekyll - class LogWriter + class LogAdapter attr_reader :writer LOG_LEVELS = { @@ -57,7 +57,7 @@ module Jekyll # # Returns nothing def warn(topic, message = nil) - writer.warn(message(topic, message).yellow) + writer.warn(message(topic, message)) end # Public: Print a jekyll error message @@ -67,7 +67,7 @@ module Jekyll # # Returns nothing def error(topic, message = nil) - writer.error(message(topic, message).red) + writer.error(message(topic, message)) end # Public: Print a Jekyll error message and immediately abort the process @@ -81,7 +81,9 @@ module Jekyll abort end - # Public: Build a Jekyll topic method + private + + # Internal: Build a Jekyll topic method # # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. # message - the message detail @@ -91,7 +93,7 @@ module Jekyll formatted_topic(topic) + message.to_s.gsub(/\s+/, ' ') end - # Public: Format the topic + # Internal: Format the topic # # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. # diff --git a/lib/jekyll/stevenson.rb b/lib/jekyll/stevenson.rb index f940fa4a..9a9f412e 100644 --- a/lib/jekyll/stevenson.rb +++ b/lib/jekyll/stevenson.rb @@ -1,4 +1,3 @@ -require 'logger' module Jekyll class Stevenson < ::Logger def initialize @@ -32,6 +31,16 @@ module Jekyll true end + # Log a +WARN+ message + def warn(progname = nil, &block) + add(WARN, nil, progname.yellow, &block) + end + + # Log an +ERROR+ message + def error(progname = nil, &block) + add(ERROR, nil, progname.red, &block) + end + def close # No LogDevice in use end diff --git a/test/test_log_adapter.rb b/test/test_log_adapter.rb new file mode 100644 index 00000000..3dd3465e --- /dev/null +++ b/test/test_log_adapter.rb @@ -0,0 +1,59 @@ +require 'helper' + +class TestLogAdapter < Test::Unit::TestCase + class LoggerDouble + attr_accessor :level + end + + context "#log_level=" do + should "set the writers logging level" do + subject = Jekyll::LogAdapter.new(LoggerDouble.new) + subject.log_level = :error + assert_equal Jekyll::LogAdapter::LOG_LEVELS[:error], subject.writer.level + end + end + + context "#debug" do + should "call #debug on writer return true" do + writer = LoggerDouble.new + logger = Jekyll::LogAdapter.new(writer) + stub(writer).debug('topic '.rjust(20) + 'log message') { true } + assert logger.debug('topic', 'log message') + end + end + + context "#info" do + should "call #info on writer return true" do + writer = LoggerDouble.new + logger = Jekyll::LogAdapter.new(writer) + stub(writer).info('topic '.rjust(20) + 'log message') { true } + assert logger.info('topic', 'log message') + end + end + + context "#warn" do + should "call #warn on writer return true" do + writer = LoggerDouble.new + logger = Jekyll::LogAdapter.new(writer) + stub(writer).warn('topic '.rjust(20) + 'log message') { true } + assert logger.warn('topic', 'log message') + end + end + + context "#error" do + should "call #error on writer return true" do + writer = LoggerDouble.new + logger = Jekyll::LogAdapter.new(writer) + stub(writer).error('topic '.rjust(20) + 'log message') { true } + assert logger.error('topic', 'log message') + end + end + + context "#abort_with" do + should "call #error and abort" do + logger = Jekyll::LogAdapter.new(LoggerDouble.new) + stub(logger).error('topic', 'log message') { true } + assert_raise(SystemExit) { logger.abort_with('topic', 'log message') } + end + end +end From 4bdf4197dbaf61ab4ffda21d905100cf7b8dea70 Mon Sep 17 00:00:00 2001 From: Peter Rhoades Date: Sun, 25 May 2014 23:19:29 +0100 Subject: [PATCH 3/3] Rocket style hash and switching integers for Logger severity constants --- lib/jekyll/log_adapter.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/jekyll/log_adapter.rb b/lib/jekyll/log_adapter.rb index 5c4fb952..f22f47ad 100644 --- a/lib/jekyll/log_adapter.rb +++ b/lib/jekyll/log_adapter.rb @@ -1,13 +1,12 @@ -require 'logger' module Jekyll class LogAdapter attr_reader :writer LOG_LEVELS = { - debug: 0, - info: 1, - warn: 2, - error: 3 + :debug => ::Logger::DEBUG, + :info => ::Logger::INFO, + :warn => ::Logger::WARN, + :error => ::Logger::ERROR } # Public: Create a new instance of Jekyll's log writer