diff --git a/lib/logging.rb b/lib/logging.rb
deleted file mode 100644
index 79dc249f..00000000
--- a/lib/logging.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# a simple module to be included into a class that want to log
-#
-# use the standard logger and the class name as the program name
-#
-# The standard functions are available on the log object
-# And the log level may be set after inclusion with level function (that takes symbols)
-
-require "logger"
-
-module Logging
- def self.included(base)
- base.extend(Methods)
- end
- def log
- self.class.log
- end
-
- module Methods
- def log
- return @logger if @logger
- @logger = Logger.new log_stream
- @logger.progname = self.name.split("::").last
- @logger.datetime_format = '%M:%S'
- @logger.level = Logger::INFO
- @logger
- end
- def log_level l
- log.level = case l
- when :unknown
- Logger::UNKNOWN
- when :fatal
- Logger::FATAL
- when :error
- Logger::ERROR
- when :warn
- Logger::WARN
- when :info
- Logger::INFO
- when :debug
- Logger::DEBUG
- else
- raise "unknown log level #{l}"
- end
- end
-
- private
- def log_stream
- STDOUT
- end
- end
-end
diff --git a/lib/risc/interpreter.rb b/lib/risc/interpreter.rb
index c9e7964b..5c258841 100644
--- a/lib/risc/interpreter.rb
+++ b/lib/risc/interpreter.rb
@@ -13,8 +13,8 @@ module Risc
class Interpreter
# fire events for changed pc and register contents
include Util::Eventable
- include Logging
- log_level :info
+ include Util::Logging
+ log_level :debug
attr_reader :instruction , :clock # current instruction or pc
attr_reader :registers # the registers, 16 (a hash, sym -> contents)
diff --git a/lib/risc/machine.rb b/lib/risc/machine.rb
index 5c770f6c..9e43479e 100644
--- a/lib/risc/machine.rb
+++ b/lib/risc/machine.rb
@@ -13,8 +13,8 @@ module Risc
#
class Machine
- include Logging
- log_level :info
+ include Util::Logging
+ log_level :debug
def initialize
@booted = false
diff --git a/lib/risc/text_writer.rb b/lib/risc/text_writer.rb
index e428510b..1467e8d2 100644
--- a/lib/risc/text_writer.rb
+++ b/lib/risc/text_writer.rb
@@ -13,7 +13,7 @@ module Risc
# we just add it to pointers.
class TextWriter
- include Logging
+ include Util::Logging
log_level :info
def initialize(machine)
diff --git a/lib/rubyx.rb b/lib/rubyx.rb
index 439f06a1..8e414e8b 100644
--- a/lib/rubyx.rb
+++ b/lib/rubyx.rb
@@ -9,7 +9,7 @@ end
require "rx-file"
-require_relative "logging"
+require "util/logging"
require_relative "elf/object_writer"
require_relative "risc"
require_relative "arm/arm_machine"
diff --git a/lib/util/logger.rb b/lib/util/logger.rb
new file mode 100644
index 00000000..1514a872
--- /dev/null
+++ b/lib/util/logger.rb
@@ -0,0 +1,635 @@
+# Copied logger from logger gem.
+# removed monitor for opal
+# rmoevd shifting and file options
+
+# == Description
+#
+# The Logger class provides a simple but sophisticated logging utility that
+# you can use to output messages.
+#
+# The messages have associated
+# levels, such as +INFO+ or +ERROR+ that indicate their importance.
+# You can then give the Logger a level, and only messages at that
+# level of higher will be printed.
+#
+# The levels are:
+#
+# +FATAL+:: an unhandleable error that results in a program crash
+# +ERROR+:: a handleable error condition
+# +WARN+:: a warning
+# +INFO+:: generic (useful) information about system operation
+# +DEBUG+:: low-level information for developers
+#
+# For instance, in a production system, you may have your Logger set to
+# +INFO+ or even +WARN+
+# When you are developing the system, however, you probably
+# want to know about the program's internal state, and would set the Logger to
+# +DEBUG+.
+#
+# *Note*: Logger does not escape or sanitize any messages passed to it.
+# Developers should be aware of when potentially malicious data (user-input)
+# is passed to Logger, and manually escape the untrusted data:
+#
+# logger.info("User-input: #{input.dump}")
+# logger.info("User-input: %p" % input)
+#
+# You can use #formatter= for escaping all data.
+#
+# original_formatter = Logger::Formatter.new
+# logger.formatter = proc { |severity, datetime, progname, msg|
+# original_formatter.call(severity, datetime, progname, msg.dump)
+# }
+# logger.info(input)
+#
+# === Example
+#
+# This creates a logger to the standard output stream, with a level of +WARN+
+#
+# log = Logger.new(STDOUT)
+# log.level = Logger::WARN
+#
+# log.debug("Created logger")
+# log.info("Program started")
+# log.warn("Nothing to do!")
+#
+# begin
+# File.each_line(path) do |line|
+# unless line =~ /^(\w+) = (.*)$/
+# log.error("Line in wrong format: #{line}")
+# end
+# end
+# rescue => err
+# log.fatal("Caught exception; exiting")
+# log.fatal(err)
+# end
+#
+# Because the Logger's level is set to +WARN+, only the warning, error, and
+# fatal messages are recorded. The debug and info messages are silently
+# discarded.
+#
+# === Features
+#
+# There are several interesting features that Logger provides, like
+# auto-rolling of log files, setting the format of log messages, and
+# specifying a program name in conjunction with the message. The next section
+# shows you how to achieve these things.
+#
+#
+# == HOWTOs
+#
+# === How to create a logger
+#
+# The options below give you various choices, in more or less increasing
+# complexity.
+#
+# 1. Create a logger which logs messages to STDERR/STDOUT.
+#
+# logger = Logger.new(STDERR)
+# logger = Logger.new(STDOUT)
+#
+# 2. Create a logger for the file which has the specified name.
+#
+# logger = Logger.new('logfile.log')
+#
+# 3. Create a logger for the specified file.
+#
+# file = File.open('foo.log', File::WRONLY | File::APPEND)
+# # To create new (and to remove old) logfile, add File::CREAT like;
+# # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT)
+# logger = Logger.new(file)
+#
+# 4. Create a logger which ages logfile once it reaches a certain size. Leave
+# 10 "old log files" and each file is about 1,024,000 bytes.
+#
+# logger = Logger.new('foo.log', 10, 1024000)
+#
+# 5. Create a logger which ages logfile daily/weekly/monthly.
+#
+# logger = Logger.new('foo.log', 'daily')
+# logger = Logger.new('foo.log', 'weekly')
+# logger = Logger.new('foo.log', 'monthly')
+#
+# === How to log a message
+#
+# Notice the different methods (+fatal+, +error+, +info+) being used to log
+# messages of various levels? Other methods in this family are +warn+ and
+# +debug+. +add+ is used below to log a message of an arbitrary (perhaps
+# dynamic) level.
+#
+# 1. Message in block.
+#
+# logger.fatal { "Argument 'foo' not given." }
+#
+# 2. Message as a string.
+#
+# logger.error "Argument #{ @foo } mismatch."
+#
+# 3. With progname.
+#
+# logger.info('initialize') { "Initializing..." }
+#
+# 4. With severity.
+#
+# logger.add(Logger::FATAL) { 'Fatal error!' }
+#
+# The block form allows you to create potentially complex log messages,
+# but to delay their evaluation until and unless the message is
+# logged. For example, if we have the following:
+#
+# logger.debug { "This is a " + potentially + " expensive operation" }
+#
+# If the logger's level is +INFO+ or higher, no debug messages will be logged,
+# and the entire block will not even be evaluated. Compare to this:
+#
+# logger.debug("This is a " + potentially + " expensive operation")
+#
+# Here, the string concatenation is done every time, even if the log
+# level is not set to show the debug message.
+#
+# === How to close a logger
+#
+# logger.close
+#
+# === Setting severity threshold
+#
+# 1. Original interface.
+#
+# logger.sev_threshold = Logger::WARN
+#
+# 2. Log4r (somewhat) compatible interface.
+#
+# logger.level = Logger::INFO
+#
+# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
+#
+#
+# == Format
+#
+# Log messages are rendered in the output stream in a certain format by
+# default. The default format and a sample are shown below:
+#
+# Log format:
+# SeverityID, [Date Time mSec #pid] SeverityLabel -- ProgName: message
+#
+# Log sample:
+# I, [Wed Mar 03 02:34:24 JST 1999 895701 #19074] INFO -- Main: info.
+#
+#
+# Or, you may change the overall format with #formatter= method.
+#
+# logger.formatter = proc do |severity, datetime, progname, msg|
+# "#{datetime}: #{msg}\n"
+# end
+# # e.g. "Thu Sep 22 08:51:08 GMT+9:00 2005: hello world"
+#
+module Util
+ class Logger
+ VERSION = "1.2.8"
+ ProgName = "#{File.basename(__FILE__)}/#{VERSION}"
+
+ class Error < RuntimeError # :nodoc:
+ end
+ # not used after 1.2.7. just for compat.
+ class ShiftingError < Error # :nodoc:
+ end
+
+ # Logging severity.
+ module Severity
+ # Low-level information, mostly for developers
+ DEBUG = 0
+ # generic, useful information about system operation
+ INFO = 1
+ # a warning
+ WARN = 2
+ # a handleable error condition
+ ERROR = 3
+ # an unhandleable error that results in a program crash
+ FATAL = 4
+ # an unknown message that should always be logged
+ UNKNOWN = 5
+ end
+ include Severity
+
+ # Logging severity threshold (e.g. Logger::INFO).
+ attr_accessor :level
+
+ # program name to include in log messages.
+ attr_accessor :progname
+
+
+ # Logging formatter, as a +Proc+ that will take four arguments and
+ # return the formatted message. The arguments are:
+ #
+ # +severity+:: The Severity of the log message
+ # +time+:: A Time instance representing when the message was logged
+ # +progname+:: The #progname configured, or passed to the logger method
+ # +msg+:: The _Object_ the user passed to the log message; not necessarily a String.
+ #
+ # The block should return an Object that can be written to the logging device via +write+. The
+ # default formatter is used when no formatter is set.
+ attr_accessor :formatter
+
+ alias sev_threshold level
+ alias sev_threshold= level=
+
+ # Returns +true+ iff the current severity level allows for the printing of
+ # +DEBUG+ messages.
+ def debug?; @level <= DEBUG; end
+
+ # Returns +true+ iff the current severity level allows for the printing of
+ # +INFO+ messages.
+ def info?; @level <= INFO; end
+
+ # Returns +true+ iff the current severity level allows for the printing of
+ # +WARN+ messages.
+ def warn?; @level <= WARN; end
+
+ # Returns +true+ iff the current severity level allows for the printing of
+ # +ERROR+ messages.
+ def error?; @level <= ERROR; end
+
+ # Returns +true+ iff the current severity level allows for the printing of
+ # +FATAL+ messages.
+ def fatal?; @level <= FATAL; end
+
+ #
+ # === Synopsis
+ #
+ # Logger.new(name)
+ # Logger.new(name)
+ #
+ # === Args
+ #
+ # +logdev+::
+ # The log device. This is a filename (String) or IO object (typically
+ # +STDOUT+, +STDERR+, or an open file).
+ #
+ # === Description
+ #
+ # Create an instance.
+ #
+ def initialize(logdev)
+ @progname = nil
+ @level = DEBUG
+ @default_formatter = Formatter.new
+ @formatter = nil
+ @logdev = nil
+ if logdev
+ @logdev = LogDevice.new(logdev)
+ end
+ end
+
+ #
+ # === Synopsis
+ #
+ # Logger#add(severity, message = nil, progname = nil) { ... }
+ #
+ # === Args
+ #
+ # +severity+::
+ # Severity. Constants are defined in Logger namespace: +DEBUG+, +INFO+,
+ # +WARN+, +ERROR+, +FATAL+, or +UNKNOWN+.
+ # +message+::
+ # The log message. A String or Exception.
+ # +progname+::
+ # Program name string. Can be omitted. Treated as a message if no
+ # +message+ and +block+ are given.
+ # +block+::
+ # Can be omitted. Called to get a message string if +message+ is nil.
+ #
+ # === Return
+ #
+ # +true+ if successful, +false+ otherwise.
+ #
+ # When the given severity is not high enough (for this particular logger), log
+ # no message, and return +true+.
+ #
+ # === Description
+ #
+ # Log a message if the given severity is high enough. This is the generic
+ # logging method. Users will be more inclined to use #debug, #info, #warn,
+ # #error, and #fatal.
+ #
+ # Message format: +message+ can be any object, but it has to be
+ # converted to a String in order to log it. Generally, +inspect+ is used
+ # if the given object is not a String.
+ # A special case is an +Exception+ object, which will be printed in detail,
+ # including message, class, and backtrace. See #msg2str for the
+ # implementation if required.
+ #
+ # === Bugs
+ #
+ # * Logfile is not locked.
+ # * Append open does not need to lock file.
+ # * If the OS which supports multi I/O, records possibly be mixed.
+ #
+ def add(severity, message = nil, progname = nil, &block)
+ severity ||= UNKNOWN
+ 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.write(
+ format_message(format_severity(severity), Time.now, progname, message))
+ true
+ end
+ alias log add
+
+ #
+ # Dump given message to the log device without any formatting. If no log
+ # device exists, return +nil+.
+ #
+ def <<(msg)
+ unless @logdev.nil?
+ @logdev.write(msg)
+ end
+ end
+
+ #
+ # Log a +DEBUG+ message.
+ #
+ # See #info for more information.
+ #
+ def debug(progname = nil, &block)
+ add(DEBUG, nil, progname, &block)
+ end
+
+ #
+ # :call-seq:
+ # info(message)
+ # info(progname,&block)
+ #
+ # Log an +INFO+ message.
+ #
+ # +message+:: the message to log; does not need to be a String
+ # +progname+:: in the block form, this is the #progname to use in the
+ # the log message. The default can be set with #progname=
+ # &block:: evaluates to the message to log. This is not evaluated
+ # unless the logger's level is sufficient
+ # to log the message. This allows you to create
+ # potentially expensive logging messages that are
+ # only called when the logger is configured to show them.
+ #
+ # === Examples
+ #
+ # logger.info("MainApp") { "Received connection from #{ip}" }
+ # # ...
+ # logger.info "Waiting for input from user"
+ # # ...
+ # logger.info { "User typed #{input}" }
+ #
+ # You'll probably stick to the second form above, unless you want to provide a
+ # program name (which you can do with #progname= as well).
+ #
+ # === Return
+ #
+ # See #add.
+ #
+ def info(progname = nil, &block)
+ add(INFO, nil, progname, &block)
+ end
+
+ #
+ # Log a +WARN+ message.
+ #
+ # See #info for more information.
+ #
+ def warn(progname = nil, &block)
+ add(WARN, nil, progname, &block)
+ end
+
+ #
+ # Log an +ERROR+ message.
+ #
+ # See #info for more information.
+ #
+ def error(progname = nil, &block)
+ add(ERROR, nil, progname, &block)
+ end
+
+ #
+ # Log a +FATAL+ message.
+ #
+ # See #info for more information.
+ #
+ def fatal(progname = nil, &block)
+ add(FATAL, nil, progname, &block)
+ end
+
+ #
+ # Log an +UNKNOWN+ message. This will be printed no matter what the logger's
+ # level.
+ #
+ # See #info for more information.
+ #
+ def unknown(progname = nil, &block)
+ add(UNKNOWN, nil, progname, &block)
+ end
+
+ #
+ # Close the logging device.
+ #
+ def close
+ @logdev.close if @logdev
+ end
+
+ private
+
+ # Severity label for logging. (max 5 char)
+ SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY)
+
+ def format_severity(severity)
+ SEV_LABEL[severity] || 'ANY'
+ end
+
+ def format_message(severity, datetime, progname, msg)
+ (@formatter || @default_formatter).call(severity, datetime, progname, msg)
+ end
+
+
+ # Default formatter for log messages
+ class Formatter
+ def call(severity, time, progname, msg)
+ "#{severity} #{progname} #{time.strftime("%M-%S-%L")} #{progname}::#{msg2str(msg)}\n"
+ end
+
+ private
+
+ def msg2str(msg)
+ case msg
+ when ::String
+ msg
+ when ::Exception
+ "#{ msg.message } (#{ msg.class })\n" <<
+ (msg.backtrace || []).join("\n")
+ else
+ msg.inspect
+ end
+ end
+ end
+
+
+ # Device used for logging messages.
+ class LogDevice
+ attr_reader :dev
+ attr_reader :filename
+
+ def initialize(log)
+ @dev = log
+ end
+
+ def write(message)
+ @dev.write(message)
+ end
+
+ def close
+ begin
+ @dev.close rescue nil
+ rescue Exception
+ @dev.close rescue nil
+ end
+ end
+
+ private
+
+ SiD = 24 * 60 * 60
+
+
+ def eod(t)
+ Time.mktime(t.year, t.month, t.mday, 23, 59, 59)
+ end
+ end
+
+
+ #
+ # == Description
+ #
+ # Application -- Add logging support to your application.
+ #
+ # == Usage
+ #
+ # 1. Define your application class as a sub-class of this class.
+ # 2. Override 'run' method in your class to do many things.
+ # 3. Instantiate it and invoke 'start'.
+ #
+ # == Example
+ #
+ # class FooApp < Application
+ # def initialize(foo_app, application_specific, arguments)
+ # super('FooApp') # Name of the application.
+ # end
+ #
+ # def run
+ # ...
+ # log(WARN, 'warning', 'my_method1')
+ # ...
+ # @log.error('my_method2') { 'Error!' }
+ # ...
+ # end
+ # end
+ #
+ # status = FooApp.new(....).start
+ #
+ class Application
+ include Logger::Severity
+
+ # Name of the application given at initialize.
+ attr_reader :appname
+
+ #
+ # == Synopsis
+ #
+ # Application.new(appname = '')
+ #
+ # == Args
+ #
+ # +appname+:: Name of the application.
+ #
+ # == Description
+ #
+ # Create an instance. Log device is +STDERR+ by default. This can be
+ # changed with #set_log.
+ #
+ def initialize(appname = nil)
+ @appname = appname
+ @log = Logger.new(STDERR)
+ @log.progname = @appname
+ @level = @log.level
+ end
+
+ #
+ # Start the application. Return the status code.
+ #
+ def start
+ status = -1
+ begin
+ log(INFO, "Start of #{ @appname }.")
+ status = run
+ rescue
+ log(FATAL, "Detected an exception. Stopping ... #{$!} (#{$!.class})\n" << $@.join("\n"))
+ ensure
+ log(INFO, "End of #{ @appname }. (status: #{ status.to_s })")
+ end
+ status
+ end
+
+ # Logger for this application. See the class Logger for an explanation.
+ def logger
+ @log
+ end
+
+ #
+ # Sets the logger for this application. See the class Logger for an explanation.
+ #
+ def logger=(logger)
+ @log = logger
+ @log.progname = @appname
+ @log.level = @level
+ end
+
+ #
+ # Sets the log device for this application. See Logger.new for an explanation
+ # of the arguments.
+ #
+ def set_log(logdev)
+ @log = Logger.new(logdev)
+ @log.progname = @appname
+ @log.level = @level
+ end
+
+ def log=(logdev)
+ set_log(logdev)
+ end
+
+ #
+ # Set the logging threshold, just like Logger#level=.
+ #
+ def level=(level)
+ @level = level
+ @log.level = @level
+ end
+
+ #
+ # See Logger#add. This application's +appname+ is used.
+ #
+ def log(severity, message = nil, &block)
+ @log.add(severity, message, @appname, &block) if @log
+ end
+
+ private
+
+ def run
+ # TODO: should be an NotImplementedError
+ raise RuntimeError.new('Method run must be defined in the derived class.')
+ end
+ end
+ end
+end
diff --git a/lib/util/logging.rb b/lib/util/logging.rb
new file mode 100644
index 00000000..5340c21e
--- /dev/null
+++ b/lib/util/logging.rb
@@ -0,0 +1,52 @@
+# a simple module to be included into a class that want to log
+#
+# use the standard logger and the class name as the program name
+#
+# The standard functions are available on the log object
+# And the log level may be set after inclusion with level function (that takes symbols)
+
+require_relative "logger"
+
+module Util
+ module Logging
+ def self.included(base)
+ base.extend(Methods)
+ end
+ def log
+ self.class.log
+ end
+
+ module Methods
+ def log
+ return @logger if @logger
+ @logger = Logger.new log_stream
+ @logger.progname = self.name.split("::").last
+ @logger.level = Logger::INFO
+ @logger
+ end
+ def log_level l
+ log.level = case l
+ when :unknown
+ Logger::UNKNOWN
+ when :fatal
+ Logger::FATAL
+ when :error
+ Logger::ERROR
+ when :warn
+ Logger::WARN
+ when :info
+ Logger::INFO
+ when :debug
+ Logger::DEBUG
+ else
+ raise "unknown log level #{l}"
+ end
+ end
+
+ private
+ def log_stream
+ STDOUT
+ end
+ end
+ end
+end
diff --git a/test/lib/test_log.rb b/test/lib/test_log.rb
index e603d9db..53e3eb40 100644
--- a/test/lib/test_log.rb
+++ b/test/lib/test_log.rb
@@ -7,7 +7,7 @@ class MemLogger
def self.log_stream
@stream = StringIO.new
end
- include Logging
+ include Util::Logging
end
class LoggerTest < MiniTest::Test