Ruby on rails 使用Log4r进行上下文日志记录

Ruby on rails 使用Log4r进行上下文日志记录,ruby-on-rails,ruby,logging,refactoring,log4r,Ruby On Rails,Ruby,Logging,Refactoring,Log4r,下面是我现有的Log4r日志代码的工作原理。正如您在WorkerX::a_方法中所看到的,每当我记录消息时,我都希望包含类名和调用方法(我不希望所有调用方历史记录或任何其他杂音,这是我在LgrHelper背后的目的) 我真的不喜欢这种方法。我宁愿使用现有的@logger实例变量来打印消息,并且足够聪明地了解上下文。如何做到这一点,或类似的更简单的方法 我的环境是Rails 2.3.11(目前!)。在使用extend发布我的答案后(请参阅下面的“EDIT”),我想我应该尝试使用set\u trac

下面是我现有的Log4r日志代码的工作原理。正如您在WorkerX::a_方法中所看到的,每当我记录消息时,我都希望包含类名和调用方法(我不希望所有调用方历史记录或任何其他杂音,这是我在LgrHelper背后的目的)

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


我的环境是Rails 2.3.11(目前!)。

在使用
extend
发布我的答案后(请参阅下面的“EDIT”),我想我应该尝试使用
set\u trace\u func
来保持某种堆栈跟踪,就像我发布到的讨论中那样。这是我的最终解决方案;
set\u trace\u 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
输出为:

ERROR:  2011-07-24 20:01:40 - WorkerX::a_method - some error went down here
缺点是,通过这种方法,调用方的类名不会自动计算出来;它是基于传递到
Lgr
实例的
@logger\u type
显式的。但是,您可以使用另一个方法来获取类的实际名称——可能类似于或使用——请参阅

#!/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