16

我正在编写 Logger 并遇到自动添加类名的问题,我从中调用了 print_log 方法。例如这样的:

class Logger
  def self.print_log(string)
    puts Time.now.strftime('%T | ') + *caller_class_name_here* + ' - ' + string 
  end
end

class MyClass
  def initialize
    Logger.print_log 'called .new() method'
  end
end

作为调用MyClass.new方法的结果,我想在输出中看到:

14:41:23 | MyClass - 称为 .new() 方法

我确定可以使用 using caller,但找不到如何使用

4

3 回答 3

6

您可以使用这样的模块(Rails 样式):

module Loggable
  extend ActiveSupport::Concern

  def log_prefix
    @log_prefix ||= (self.class == Class ? "#{self.to_s}" : "#{self.class.to_s}").freeze
  end

  included do
    [:debug, :info, :warn, :error, :fatal].each do |level|
      define_method level do |str = nil|
        caller = caller_locations(1,1)[0].label
        prefix = "[#{log_prefix}##{caller}] "
        prefix << level.to_s.upcase[0]
        str = "#{prefix}: #{str}"
        puts str if ENV["DEBUG"]
        Rails.logger.send(level, str)
      end
    end
  end
end

你的代码将是:

class MyClass
  include Loggable
  extend Loggable

  def instance_method
    debug "Hello"
  end

  def self.klass_method
    debug "Klass"
  end
end
于 2014-04-25T00:11:29.923 回答
4

我不确定是否可以得到你想要的类名。我会为此创建一个记录器实例,您可以在创建它时将类名传递给它。

class Logger
  def initialize(class_name)
    @class_name = class_name
  end

  def print_log(message)
    puts Time.now.strftime('%T | ') + @class_name + ' - ' + message
  end
end

class MyClass
  def initalize
    @logger = Logger.new self.class.name
    @logger.print_log 'called .new() method'
  end
end

可能比您想要的更冗长,但易于理解的明确代码。

对于任何严肃的工作,我建议使用标准库 logger。您可能必须将其包装在您自己的调用中以根据需要获取日志消息,但您将获得应有的日志轮换和文件处理。

于 2013-10-30T12:00:40.620 回答
2

在折腾了caller一段时间之后,它可能不会为你做这件事,也不是caller_locations。可以跟踪在当前线程上实例化的最后一个对象的类,例如

class Class
  alias :_new :new
  def new *args
    Thread.current.thread_variable_set :classes, ((Thread.current.thread_variable_get(:classes) || []) << self).last(10)
    _new *args
  end
end

这保留了最后 10 个对象的类,但这并不直接等同于层次结构,例如

class X
  def initialize
    puts Thread.current.thread_variable_get(:classes)
  end
end

class Y
end

class Z
  def initialize
    @y = Y.new
    @x = X.new
  end
end

X.new 输出以下内容(在控制台会话中)

RubyToken::TkNL
RubyToken::TkEND
RubyToken::TkNL
RubyToken::TkCONSTANT
RubyToken::TkDOT
RubyToken::TkIDENTIFIER
RubyToken::TkNL
Y
Z
X
于 2013-10-30T12:48:29.573 回答