0

Log4rを使用した既存のロギングコードの一部がどのように機能するかを次に示します。WorkerX :: a_methodでわかるように、メッセージをログに記録するときはいつでも、クラス名と呼び出し元のメソッドを含める必要があります(すべての呼び出し元の履歴やその他のノイズは必要ありません。これが私の目的でした) 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

私はこのアプローチが本当に好きではありません。むしろ、既存の@loggerインスタンス変数を使用してメッセージを出力し、コンテキストを理解するのに十分賢くしたいと思います。これ、または同様のより単純なアプローチをどのように行うことができますか?

私の環境はRails2.3.11です(今のところ!)。

4

1 に答える 1

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の初期化子の2行目を除いて同じです。

#!/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 gemKernel#set_trace_funcのようなもの、またはを使用するなど) 。このスレッドを参照してください。

于 2011-07-25T03:13:08.933 に答える