In our application we may occasionally have a heavy usage of
logger.debug calls. It appears
to be helpful to examine the fails, especially in multithreading environment. That’s why we
do not want to get rid of these calls. We set the
logger.level = Logger::INFO in production instead.
But what if we need to print debug messages for only one or two of over 9000 files? There is no elegant solution on hand, as far as I know. Let me show an ugly hack to provide such a functionality.
First of all, let’s prepare the function to retrieve the caller’s filename and/or method. This would be a static function somewhere in top-level of our module:
module MyModule def parse_caller # magic number 7 below is the amount of calls # on stack to unwind to get your caller if /^(?<file>.+?):(?<line>\d+)(?::in `(?<method>.*)')?/ =~ caller(7).first file = Regexp.last_match[:file] line = Regexp.last_match[:line].to_i method = Regexp.last_match[:method] [file, line, method] end end end
The magic number “7” there states for an amount of subcalls between our call and resulting
Logger#add. We will examine the original caller of
logger.debug method and reject all
calls except of interesting ones.
The other thing we need is to override the formatter of our logger:
# put this after logger initialization logger.level = Logger::DEBUG logger.formatter = lambda do |sev, dt, prog, msg| f,l,m = parse_caller #↓↓↓↓↓↓↓↓↓↓↓↓ here goes the check ↓↓↓↓↓↓↓↓↓↓↓↓↓ if (f =~ /newclass/i) && (m =~ /failed_method/) original_formatter.call(sev, dt, prog, msg) end end
I know it looks a weird hack, but it works fine. As soon as we don’t need debug logging at all, simply
turn back to
INFO level (and don’t forget to switch back to regular
logger.level = Logger::INFO logger.formatter = Logger::Formatter.new