2011-07-15 27 views
0

以下是Log4r中的一些现有日志记录代码的工作方式。正如你可以在WorkerX :: a_method中看到的那样,每当我记录一条消息时,我都希望包含类名和调用方法(我不希望所有的调用者历史或任何其他噪声,这是我的目的LgrHelper)。使用Log4r进行上下文记录

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 

我真的不喜欢这种方法。我宁愿使用现有的@logger实例变量来打印消息,并且足够聪明以了解上下文。如何做到这一点或者类似的简单方法?

我的环境是Rails 2.3.11(现在!)。

回答

1

发布使用extend我的回答后,(请参阅“编辑”,下同),我想我会尝试使用set_trace_func保持一种堆栈跟踪的像我张贴的讨论。这是我的最终解决方案;调用set_trace_proc将被放入初始化程序或类似程序中。

#!/usr/bin/env ruby 

# Keep track of the classes that invoke each "call" event 
# and the method they called as an array of arrays. 
# The array is in the format: [calling_class, called_method] 
set_trace_func proc { |event, file, line, id, bind, klass| 
    if event == "call" 
    Thread.current[:callstack] ||= [] 
    Thread.current[:callstack].push [klass, id] 
    elsif event == "return" 
    Thread.current[:callstack].pop 
    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 

    def invoker 
    Thread.current[:callstack] ||= [] 
    (Thread.current[:callstack][-2] || ['Kernel', 'main']) 
    end 
end 

class CallingMethodLogger < Lgr 
    [:info, :debug, :warn, :error].each do |meth| 
    define_method(meth) { |msg| super("#{invoker[0]}::#{invoker[1]} - #{msg}") } 
    end 
end 

class WorkerX 
    def initialize(args = {}) 
    @logger = CallingMethodLogger.new({:debug => args[:debug], :logger_type => 'WorkerX'}) 
    end 

    def a_method 
    @logger.error("some error went down here") 
    # This prints out: "WorkerX::a_method - some error went down here" 
    end 
end 

w = WorkerX.new 
w.a_method 

我不知道有多少,如果有的话,该PROC的通话将影响应用程序的性能;如果它最终成为一个问题,或许不像调用类的智能(比如我下面的旧答案)会更好。

[编辑:下面是我的老答案,上面提到的。]

有关使用extend如何?这里有一个我的代码放在一起的快速而肮脏的脚本来测试它;我不得不重新安排事情,以避免错误,但代码与LgrHelper例外(我改名为CallingMethodLogger)和WorkerX的初始化函数的第二行是相同的:

#!/usr/bin/env ruby 

module CallingMethodLogger 
    def info(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def debug(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def warn(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def error(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def method_caller_name 
    if /`(.*)'/.match(caller[1]) then # caller.first 
     $1 
    else 
     nil 
    end 
    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 

class WorkerX 
    def initialize(args = {}) 
    @logger = Lgr.new({:debug => args[:debug], :logger_type => 'WorkerX'}) 
    @logger.extend CallingMethodLogger 
    end 

    def a_method 
    @logger.error("some error went down here") 
    # This prints out: "WorkerX::a_method - some error went down here" 
    end 
end 

w = WorkerX.new 
w.a_method 

输出是:

ERROR: 2011-07-24 20:01:40 - WorkerX::a_method - some error went down here 

缺点是,通过这种方法,调用者的类名不会自动计算出来;它基于@logger_type明确传入Lgr实例。但是,您可能可以使用其他方法获取课程的实际名称 - 可能类似call_stack gem或使用Kernel#set_trace_func - 请参阅this thread

+0

这是一些漂亮的东西!奇迹般有效 – keruilin

相关问题