如何正确处理错误日志?

时间:2009-03-06 13:24:59

标签: java servlets error-handling

我在发布此问题之前尝试进行多次搜索。如果这是重复,请告诉我,我将删除它。

我的问题围绕处理通过我们的Web应用程序产生的错误的正确方法。我们目前通过log4j记录所有内容。如果发生错误,它只是说“发生了错误。已经通知IT部门,并将在屏幕上尽快纠正此错误”。这告诉用户没什么......但是当我们尝试重现错误时,它也没有告诉开发人员任何事情。我们必须转到错误日志文件夹并尝试查找此错误。我还要提一下,该文件夹中充满了过去一周的日志。每次出现错误时,都会为该用户创建一个日志文件,并将电子邮件发送给分配给处理错误的IT人员。此电子邮件未提及日志文件名,但它是日志文件中写入的相同错误文本的副本。

因此,如果Alicia在7:15遇到问题,但在同一分钟发生了10个其他错误,我必须通过每个日志文件试图找到她的。

我向同事提议的是在数据库中添加错误日志表。这会为每个错误写一条记录,记录它的用户,错误,它发生的页面等等。这样做的好处是我们可以从表中返回主键值(error_log_id)和显示在页面上有一条消息,如“错误参考ID(1337)已被记录,并且已通知正确的IT人员。请保留此参考ID以方便将来使用”。当我们收到电子邮件时,它会告诉我们错误的ID以便快速参考。或者,如果用户是持久的,他们可以使用id与我们联系,我们可以很快找到错误。

如何设置错误记录?顺便说一下,我们的系统使用连接到SQL Server数据库的Java Servlet。

6 个答案:

答案 0 :(得分:5)

我回答了类似的问题here,但我会根据你的问题调整答案。

我们为此目的使用 requestID - 在处理的最开始(在过滤器中)为每个传入(HTTP)请求分配一个请求ID,然后在每个日志行上记录,所以你之后可以通过该ID轻松地查看这些日志并查找所有相关行。

如果您认为将该ID添加到每个日志语句非常繁琐,那么您并不孤单 - 使用Mapped Diagnostic Context(MDC)使Java日志框架变得透明(至少log4j和logback)有这个)。

RequestID也可以作为一个方便的参考号,在发生错误时吐出(如你所建议的那样)。但是,正如其他人所评论的那样,将这些细节加载到数据库并不明智 - 更好地使用文件系统。或者,最简单的方法是只使用requestID - 然后您不需要在发生错误时执行任何特殊操作。它只是帮助您找到正确的日志文件并在该文件中搜索。

一个requestID怎么样?

我们使用以下模式:

  

<实例名>:< currentTimeInMillis><反向>

由以下变量组成:

  • instanceName 唯一标识特定部署环境中的特定JVM。
  • currentTimeInMillis 是不言自明的。我们选择以人类可读的格式“yyyyMMddHHmmssSSS”来表示它,因此很容易从中读取请求的开始时间(注意:SimpleDateFormat不是线程安全的,因此您需要同步它或在每个请求上创建一个新的)。
  • 计数器是特定毫秒内的请求计数器 - 在极少数情况下,您可能需要在一毫秒内生成多个请求ID

正如您所看到的,ID格式的设置方式使得 currentTimeInMillis.counter 组合在特定的JVM中保证是唯一的,并且整个ID保证全局唯一(好吧,不是真正意义上的“全球”,但它足以满足我们的目的),而不需要涉及数据库或其他一些中心节点。此外,使用 instanceName 变量可以限制以后需要查找的日志文件数以查找该请求。

然后,最后一个问题:“在单JVM解决方案中这是好的和花花公子,但是如何将其扩展到多个JVM,通过某些网络协议进行通信?”

当我们使用Spring Remoting进行远程处理时,我们已实现自定义RemoteInvocationFactory(从上下文接收请求ID并将其保存到RemoteInvocation attributes)和RemoteInvocationExecutor(即从属性获取请求ID并将其添加到另一个JVM中的诊断上下文中。

不确定如何使用plain-RMI或其他远程方法实现它。

答案 1 :(得分:1)

我反对将错误日志存储在数据库中的想法。日志记录系统应该尽可能简单,并且不涉及编写日志记录不是100%必需的组件。

登录数据库时事情变得非常复杂 - 例如你可能有麻烦记录任何与数据库相关的错误(如何记录因DB没有响应而发生的错误,例如由于负载过重或基础设施错误);我看到的另一个问题是可能需要为记录等单独的事务。

另一方面,拥有错误的引用ID并不是一个坏主意,但同样,这也意味着增加了日志系统的复杂性(例如,如何通过应用程序的所有层传播引用ID)何时发生错误?)

在我参与的项目中,一般准则是尽可能详细地记录错误,并尽可能多地包含上下文信息(为了写日志,我们通常使用'常规'方法 - log4j或simillar )。通常,即使对于重载系统也是如此。

答案 2 :(得分:1)

如果多台服务器正在运行且每台服务器都自行留下日志消息,则很难跟踪它们。因此,某人或工具应按时间顺序收集和排序。 这是一个有中心点发送所有消息的好方法。

答案 3 :(得分:1)

一种可能的解决方案,让您的错误页面包含“向任何地方发送电子邮件”链接。当用户点击此电子邮件时,电子邮件的正文可能会以一些空行开头,后跟类似的内容:

  

----请不要修改此行下方的信息.---

     

错误详情

任何通过此链接投诉的用户都会自动向您发送所需信息,如果您正在重现错误,则可以快速访问错误消息。您甚至可能有一个发送电子邮件的表单,以便用户永远不会看到这一点(这对某些人来说可能很重要)但是您依赖于您的系统至少能够发送电子邮件。

实际上,我发现在错误页面上的HTML注释中打印错误详细信息很有用,这样我就可以自己找到它们了。

我同意上面的大卫,我不喜欢将这种信息存储在数据库中。

答案 4 :(得分:1)

对于记录策略,您可以看到讨论Logging best practices

答案 5 :(得分:1)

我过去使用的方法类似于您建议的方式(登录数据库),并且非常非常有帮助。

您不仅可以通过SQL获取错误,还可以生成最常见错误的报告并首先参加。

在我们所做的设计上,等于stacktraces属于相同的记录(因为它们完全来自同一个地方)

我们有一个小应用程序汇集了该数据库,我们知道然后生成了一个新的异常而不是收到与前几周剩余时间相加的电子邮件被完全忽略。

当然,这个数据库设计对我们的应用程序非常具体,并且可能有其他标识,我们有软件版本,构建,有时输入参数等等。

随着时间的推移,系统管理员会知道如何处理每种异常,并相应地继续进行。

但是!无论如何,您的申请可能不会那么大。可能你只需解析日志文件就可以了。