Here’s how some of my existing logging code with Log4r is working. As you can see in the WorkerX::a_method, any time that I log a message I want the class name and the calling method to be included (I don’t want all the caller history or any other noise, which was my purpose behind LgrHelper).
class WorkerX
include LgrHelper
def initialize(args = {})
@logger = Lgr.new({:debug => args[:debug], :logger_type => 'WorkerX'})
end
def a_method
error_msg("some error went down here")
# This prints out: "WorkerX::a_method - some error went down here"
end
end
class Lgr
require 'log4r'
include Log4r
def initialize(args = {}) # args: debug boolean, logger type
@debug = args[:debug]
@logger_type = args[:logger_type]
@logger = Log4r::Logger.new(@logger_type)
format = Log4r::PatternFormatter.new(:pattern => "%l:\t%d - %m")
outputter = Log4r::StdoutOutputter.new('console', :formatter => format)
@logger.outputters = outputter
if @debug then
@logger.level = DEBUG
else
@logger.level = INFO
end
end
def debug(msg)
@logger.debug(msg)
end
def info(msg)
@logger.info(msg)
end
def warn(msg)
@logger.warn(msg)
end
def error(msg)
@logger.error(msg)
end
def level
@logger.level
end
end
module LgrHelper
# This module should only be included in a class that has a @logger instance variable, obviously.
protected
def info_msg(msg)
@logger.info(log_intro_msg(self.method_caller_name) + msg)
end
def debug_msg(msg)
@logger.debug(log_intro_msg(self.method_caller_name) + msg)
end
def warn_msg(msg)
@logger.warn(log_intro_msg(self.method_caller_name) + msg)
end
def error_msg(msg)
@logger.error(log_intro_msg(self.method_caller_name) + msg)
end
def log_intro_msg(method)
msg = class_name
msg += '::'
msg += method
msg += ' - '
msg
end
def class_name
self.class.name
end
def method_caller_name
if /`(.*)'/.match(caller[1]) then # caller.first
$1
else
nil
end
end
end
I really don’t like this approach. I’d rather just use the existing @logger instance variable to print the message and be smart enough to know the context. How can this, or similar simpler approach, be done?
My environment is Rails 2.3.11 (for now!).
After posting my answer using
extend, (see “EDIT“, below), I thought I’d try usingset_trace_functo keep a sort of stack trace like in the discussion I posted to. Here is my final solution; theset_trace_proccall would be put in an initializer or similar.I don’t know how much, if any, the calls to the proc will affect the performance of an application; if it ends up being a concern, perhaps something not as intelligent about the calling class (like my old answer, below) will work better.
[EDIT: What follows is my old answer, referenced above.]
How about using
extend? Here’s a quick-and-dirty script I put together from your code to test it out; I had to reorder things to avoid errors, but the code is the same with the exception ofLgrHelper(which I renamedCallingMethodLogger) and the second line ofWorkerX‘s initializer:The output is:
The downside is, via this method, the caller’s class name isn’t automatically figured out; it’s explicit based on the
@logger_typepassed into theLgrinstance. However, you may be able to use another method to get the actual name of the class–perhaps something like the call_stack gem or usingKernel#set_trace_func–see this thread.