Rails:记录异常的完整堆栈跟踪

142
我一直在尝试找到记录堆栈跟踪的正确方法。我看到了这篇文章,它说用logger.error $!, $!.backtrace是正确的方法,但对我来说不起作用,而用log_error可以。根据文档,我不明白如何通过向error方法传递第二个参数使其工作,因为Rails使用的Ruby logger只接受一个参数。
奇怪的是(或者也许不是),第二个参数被接受,没有任何解释器投诉。但是,我传递给它的任何内容都被忽略了。
有人能解释我漏掉了什么吗?对error的第二个参数有什么见解,以及它是如何被忽略的?
3个回答

246

如果您查看ActiveSupport中BufferedLogger类的源代码,您会发现第二个参数是“progname”。仅当第一个参数为nil且您未给出块或块返回非真值时才使用此参数。

实质上,您无法使用第二个参数输出其他内容。

您想要做的更像是:

begin
  raise
rescue => e
  logger.error e.message
  logger.error e.backtrace.join("\n")
end

根据您的日志设置方式,如果某些记录器不输出换行符,那么迭代每个回溯行并单独打印可能更好,此时您可以执行以下操作:

begin
  raise
rescue => e
  logger.error e.message
  e.backtrace.each { |line| logger.error line }
end

5
我会使用 "\r\n" 来保持跨平台兼容性。 - James Watkins
10
你为什么不使用$/呢?这样就能跨平台兼容了。让 Ruby 来处理这个问题,因为\r\n只适用于少数几种平台。 - vgoff
16
如果多次调用记录器,可能会导致您的消息被拆分并且无法阅读,因为这是不线程安全的。虽然记录器本身是线程安全的,但通常我会将我的消息合并成一个字符串,然后记录它。 - Morozov
当时记录器似乎不支持日志条目中的换行符,因此需要拆分。但是,您是完全正确的,您应该意识到这种方法的局限性。 - darkliquid
+1 @JackWatson 的回答非常奇怪,因为它不是线程安全的。这是很重要的事情,因为我们在谈论 Web 应用程序。 - EvAlex

27

这就是答案。

begin
  raise
rescue => e
  logger.error ([e.message]+e.backtrace).join($/)
end

17
Rails.logger.error [e.message, *e.backtrace].join($/) 的翻译: Rails.logger.error [e.message, *e.backtrace].join($/) - artm
这不包括错误类的名称(例如,RuntimeError)。 - undefined

5

基于kuboon的答案,我发现这种日志格式通用且有用,可以对我的日志文件中的错误进行分类:

begin
  raise
rescue StandardError => e
  Rails.logger.error (["#{self.class} - #{e.class}: #{e.message}"]+e.backtrace).join("\n")
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接