That is a very popular family of the loggers, people use when they develop a code in various languages like log4j for Java,. Today we will be talking about log4r, logger for Ruby, and I will show you of how to use them in the Ruby classes.
It seems that an official documentation mentions it very clear:
require 'log4r'
include Log4r
# create a logger named 'mylog' that logs to stdout
mylog = Logger.new 'mylog'
mylog.outputters = Outputter.stdout
# Now we can log.
def do_log(log)
log.debug "This is a message with level DEBUG"
end
do_log(mylog)
The output will look something like this:
DEBUG mylog: This is a message with level DEBUG
However, when you try to add it into you Ruby class, using so Java concepts and/or your experience with log4j, and you write a code similar to this one, you figure out that this code simply does not work:
require 'log4r'
include Log4r
class MyClass
mylog = Logger.new 'mylog'
mylog.outputters = Outputter.stdout
def my_method
log.debug "This is a message with level DEBUG"
end
end
cl = MyClass.new
cl.my_method
You are expecting that adding loggers into the existed code is a simple procedure, however, you should write some “wrapper” code. That is a code for Global (project wide) and Local (class wide) log4r loggers and their usage in different classes. As usual you can download these files from my repository.
$> cat log4r_loggers.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'log4r'
include Log4r
require 'singleton'
## Global, project wide logger. May be called from any place of the project w/o
## any additional includes
## Usage sample:
## gloggerCF.debug "Logging to console and File: myHash: #{myHash}"
##
## It is currently implements three functions:
## gloggerC() - logging to STDOUT
## gloggerF() - logging to FILE
## gloggerCF() - logging to both STDOUT and FILE
##
GLOBAL_LOGGER_LOG_FILE = "/tmp/conn_pool.log"
class GlobalLogger
include Singleton
attr_reader :gloggerC
attr_reader :gloggerF
attr_reader :gloggerCF
def initialize
@gloggerC= Logger.new("GlobalLoggerConsole")
@gloggerF = Logger.new("GlobalLoggerFile")
@gloggerCF = Logger.new("GlobalLoggerConsoleAndFile")
pf = PatternFormatter.new(:pattern => "%C: #{self.class} %d %l %m Trace: %t")
so = StdoutOutputter.new("console", :formatter => pf)
@gloggerC.outputters << so
@gloggerC.level = DEBUG
fo = FileOutputter.new("f1", :filename => GLOBAL_LOGGER_LOG_FILE, :trunc => false, :formatter => pf)
@gloggerF.outputters << fo
@gloggerF.level = DEBUG
@gloggerCF.outputters << so
@gloggerCF.outputters << fo
@gloggerCF.level = DEBUG
end
end
module Kernel
def gloggerC
GlobalLogger.instance.gloggerC
end
def gloggerF
GlobalLogger.instance.gloggerF
end
def gloggerCF
GlobalLogger.instance.gloggerCF
end
end
## Local, class wide logger. Should have include LocalLogger added to the class, logger is used
## Usage sample:
## class A
## include LocalLogger
## def method
## loggerCF.debug "Logging to console and File: myHash: #{myHash}"
## end
## end
##
## It is currently implements three functions:
## loggerC() - logging to STDOUT
## loggerF() - logging to FILE
## loggerCF() - logging to both STDOUT and FILE
##
## if LOCAL_LOGGER_LOG_FILE not specified, "/tmp/" + self.class.to_s + "./log" will be used
##
LOCAL_LOGGER_LOG_FILE = nil
module LocalLogger
def loggerC
@logger = Logger.new("LocalLoggerConsole")
pf = PatternFormatter.new(:pattern => "%C: #{self.class} %d %l %m Trace: %t")
so = StdoutOutputter.new("console", :formatter => pf)
@logger.outputters << so
@logger.level = DEBUG
@logger
end
def loggerF
logFile = (LOCAL_LOGGER_LOG_FILE.nil?) ? "/tmp/" + self.class.to_s + ".log" : LOCAL_LOGGER_LOG_FILE
@logger = Logger.new("LocalLoggerFile")
pf = PatternFormatter.new(:pattern => "%C: #{self.class} %d %l %m Trace: %t")
fo = FileOutputter.new("f1", :filename => logFile, :trunc => false, :formatter => pf)
@logger.outputters << fo
@logger.level = DEBUG
@logger
end
def loggerCF
logFile = (LOCAL_LOGGER_LOG_FILE.nil?) ? "/tmp/" + self.class.to_s + ".log" : LOCAL_LOGGER_LOG_FILE
@logger = Logger.new("LocalLoggerConsoleAndFile")
pf = PatternFormatter.new(:pattern => "%C: #{self.class} %d %l %m Trace: %t")
so = StdoutOutputter.new("console", :formatter => pf)
fo = FileOutputter.new("f1", :filename => logFile, :trunc => false, :formatter => pf)
@logger.outputters << so @logger.outputters << fo @logger.level = DEBUG @logger end end
Usage:
$> cat use_log4r_loggers.rb
#!/usr/bin/env ruby
require 'rubygems'
require './log4r_loggers.rb'
class MyGlobalClass
def fname
gloggerC.debug "Inside MyGlobalClass, debug message to console"
gloggerF.debug "Inside MyGlobalClass, debug message to file"
mySm = {'key1' => 22, 'key2' => 56}
myHash = {'a' => 1, 'b' => 5, 'c' => mySm}
gloggerC.debug "Inside MyGlobalClass, debug message to console: #{myHash}"
gloggerF.debug "Inside MyGlobalClass, debug message to file: #{myHash}"
gloggerCF.debug "Inside MyGlobalClass, debug message to console/file: #{myHash}"
end
end
class MyWomanClass
include LocalLogger
def fname
loggerC.debug "Inside MyWomanClass, debug message to console"
loggerF.debug "Inside MyWomanClass, debug message to file"
loggerCF.debug "Inside MyWomanClass, debug message to console/file"
end
end
class MyManClass
include LocalLogger
def fname
loggerC.debug "Inside MyManClass, debug message to console"
loggerF.debug "Inside MyManClass, debug message to file"
loggerCF.debug "Inside MyManClass, debug message to console/file"
end
end
myG = MyGlobalClass.new
myG.fname
myM = MyManClass.new
myM.fname
myW = MyWomanClass.new