【问题标题】:How can I log the filename and line number that a log statement occurs when logging with Rails 3.2?如何记录使用 Rails 3.2 记录时出现的日志语句的文件名和行号?
【发布时间】:2014-04-28 10:50:23
【问题描述】:

在使用 Rails 3.2 进行日志记录时,我想记录发生日志条目的文件名和行号。

所以,如果在我的 ruby​​ 脚本 customer.rb 在线 23 中,我有一个类似的日志:

Rails.logger.debug "Debug message"

我希望日志记录如下内容:

[customer.rb:23] Debug message

这可能吗?

【问题讨论】:

标签: ruby-on-rails logging ruby-on-rails-3.2


【解决方案1】:

我终于找到了最好的解决方案,它也会影响我的应用程序使用的其他 gem 的日志格式如下:

  1. 打开类Logger::SimpleFormatter并覆盖方法call。您可以在初始化文件 (config/initializers) 中执行此操作。
  2. 更改方法call 以记录来自caller[5] 的文件和行。

这是一个对我有用的示例实现:

class Logger::SimpleFormatter
  def call(severity, time, progname, msg)
    call_details = Kernel.caller[5].gsub(/#{Rails.root}/, '')
    call_details.match /(.+):(.+):/
    filename = $1
    line = $2
    length = 40
    filename = "#{filename[-length, filename.length]}" if filename.length >= length
    filename = filename.rjust(length + 2, '.')
    "[#{severity} #{time} #{filename}:#{line}] #{msg}\n"
  end
end

在上面的解决方案中,我还将文件名限制为最后 40 个字符,以避免打印大文件路径。

【讨论】:

  • 对于 rails 4 我发现你需要 caller[6]
【解决方案2】:

当然,最简单的解决方案是在您的代码中使用 __LINE__ 和 __FILE__ 作为您的消息的一部分,但我认为您想更改记录器的格式选项。我不知道在 Logger 格式化程序中执行此操作的直接方法,但是,如果您想使用一些自定义规则过滤日志,Active upport 中的 TaggedLogging 有助于通过标记日志来做到这一点包含子域、请求 ID 和其他任何帮助调试此类应用程序的行。您可以使用 __FILE__ 和 __LINE__ 变量代替标签 这是一个例子:

logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
logger.tagged("BCX") { logger.info "Stuff" }                            # Logs "[BCX] Stuff"
logger.tagged("BCX", "Jason") { logger.info "Stuff" }                   # Logs "[BCX] [Jason] Stuff"
logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs "[BCX [Jason] Stuff

我还建议更改格式化程序,如下例所示:

Log = Logger.new(STDOUT)
  Log.formatter = proc { |severity, datetime, progname, msg|
    "#{severity} #{caller[4]} #{msg}\n"
  }

现在每次调用 Log.INFO('some message') 时,您都应该有日志方法的“调用者”的文件和行号

【讨论】:

    【解决方案3】:

    我会在config/environments/....rb 的环境配置中试验以下几行:

    config.log_formatter = proc { |severity, datetime, progname, msg|
      callee = caller[5]                         # get caller from stack
      callee = callee.split('/').last            # remove path from callee info
      callee = callee.split(':')[0, 2].join(':') # remove method name from info
    
      "[#{callee}] #{msg}\n"
    }
    

    注意:这取决于您的 Rails 版本,您将在 caller 堆栈中找到正确的文件名和行号。在撰写本文时,我在堆栈中的caller[5] 找到了请求的信息,其他版本可能在其他位置有它。因此,这种方法不是很可靠,并且在您将来更新 Rails 版本时肯定会中断。​​

    我看到的问题:只有文件名真的有用吗?如何处理来自 Rails 本身的日志消息?如何对此进行测试以确保堆栈跟踪中的位置在以后的 Rails 版本中保持正确?

    文件名和行号作为记录器格式的默认值真的很好吗?我不这么认为。

    【讨论】:

    • 您的回答很有帮助,但如果您需要我,您需要对其进行编辑首先,我需要告诉您 Rails 3 在 caller[5] 处也有它。其次,我还没有设法让它从你描述的环境设置的配置中工作。
    猜你喜欢
    • 1970-01-01
    • 2012-03-12
    • 2012-05-24
    • 2012-06-13
    • 2018-04-10
    • 2013-10-22
    • 2015-01-19
    相关资源
    最近更新 更多