I have been working on a module lately that parses a XML file structure into a hash and writes it to a database. The module includes some classes and methods and I needed a central logger class.
I created a class that inherits from Ruby´s Logger class.
class MyLogger < Logger end
I decided to make this class a Singleton. Singleton is a design pattern that restricts instantiation of a class to only one instance that is globally available. This can e.g. be done by simply including the Singleton Module.
class MyLogger < Logger include Singleton end
I wanted this class to be able to either log to STDOUT or a file. The standard way to do this, is to pass the log device to the Logger class during instantiation. The problem is that the singleton module creates the singleton instance before it is actually needed, called eager instantiation. In order to tell the singleton instance to which log device it should log to, we need to set a member variable in the initialize method. Secondly we need a method to reassign the log device.
class MyLogger < Logger
include Singleton
LOG_FILE = File.open("myfile.log","a")
def initialize
@logdev = Logger::LogDevice.new(LOG_FILE)
@level = INFO
end
def change_logdev_to_stdout
@logdev = Logger::LogDevice.new(STDOUT)
end
end
I could now use the logger methods from everywhere in my code, e.g.:
MyModule::MyLogger.instance.info("Hello World!")
In order to make things a little bit shorter, I added an additional method to the module:
def self.logger return MyModule::MyLogger.instance end
Logging can now been done from everywhere by calling:
MyModule::logger.info("Hello Universe!")