如何正确处理错误日志?

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

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

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

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

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

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

我们为此目的使用requestID – 在处理的最开始(在filter中)为每个传入(HTTP)请求分配一个请求ID,然后在每个日志行上记录该请求ID,这样您可以稍后通过该ID轻松地对这些日志进行grep找到所有相关的行。

如果您认为将该ID添加到每个日志语句非常繁琐,那么您并不孤单 – 使用映射诊断上下文 (MDC)使Java日志框架变得透明(至少log4j和logback具有此function)。

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

一个requestID怎么样?

我们使用以下模式:

<实例>: <计数器>

由以下变量组成:

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

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

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

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

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

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

一个可能的解决方案,让你的错误页面包含一个’发送电子邮件到任何’链接。 当用户点击此电子邮件时,电子邮件的正文可能会以一些空白行开头,后跟以下内容:

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

错误详情

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

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

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

对于日志记录策略,您可以查看日志记录最佳实践的讨论。

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

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

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

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

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

随着时间的推移,系统管理员将知道如何处理每种exception并相应地继续。

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

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

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

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

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