【发布时间】:2010-09-07 12:11:10
【问题描述】:
我想知道日志记录代码应该放在哪里。例如,我的存储库是否应该记录它自己的错误?或者我应该从 UI/控制器记录所有错误?有没有关于这个的一般设计原则,或者有没有人链接到一篇好文章或类似的东西。
【问题讨论】:
标签: design-patterns language-agnostic logging exception-handling
我想知道日志记录代码应该放在哪里。例如,我的存储库是否应该记录它自己的错误?或者我应该从 UI/控制器记录所有错误?有没有关于这个的一般设计原则,或者有没有人链接到一篇好文章或类似的东西。
【问题讨论】:
标签: design-patterns language-agnostic logging exception-handling
记录和追踪是 (IMO) 一门艺术,知道记录什么以及在哪里需要经验。
我发现学习日志记录艺术的最佳(最差?)方法是体验尝试诊断伪劣日志记录问题的痛苦!
我只能给你一些建议:
良好日志记录的关键是考虑如果出现问题将如何使用日志消息,相反,不良日志记录最糟糕的事情是你会只有当您遇到问题并且您没有足够的信息时才意识到这一点!
始终考虑日志消息对正在阅读它的人所说的内容,例如:
HRESULT 和 GetLastError 结果(如果有的话),这样它才有用处。一个常见的错误是在记录时没有考虑需要哪些信息,但是您还应该仔细考虑何时将记录一条消息 - 如果在正常操作下频繁记录一条消息,那么在最好的情况是它的有用性值得怀疑,最坏的情况是日志消息可能会产生误导。
此外,请确保您可以识别记录消息的内容。如果您在日志中看到的只是一个多次出现在您的代码库中的字符串(或者更糟的是根本没有!)那么您将需要推理和狡猾地找出该日志消息的来源(并且没有知道消息来自何处,您就几乎没有希望理解它)
不要将日志记录与错误处理混淆。错误处理是响应和解决错误的行为(例如向用户显示消息),日志(通常)仅在出现问题且原因不明时使用。
例如:如果用户尝试打开一个不存在的文件,那么如果错误得到了正确处理(通过告诉用户找不到该文件),那么就不需要记录该错误。
(可能的例外是,如果您想要统计错误发生的频率或其他信息 - 这又要考虑如何使用日志记录。)
一般来说,正确处理错误比记录日志更可取,但是良好的错误处理比良好的日志记录更困难 - 在这些情况下,需要日志中提供的额外信息。
您也不应该将 logging 与 auditing 混淆(尽管在许多系统中两者是重叠的)。
你可以记录太多的唯一方法是:
日志的存在纯粹是为了诊断问题的原因(不要将日志与审计混淆) - 如果您没有任何问题,那么没有人会查看您的日志,并且不会造成任何伤害!直到您遇到问题,在这种情况下,您需要尽可能多的信息。
如果您对是否记录某些内容有疑问,请记录它。
说了这么多,我觉得有必要澄清一下异常的日志记录。
一般来说,您应该只记录一次异常(在处理它的地方)。不要试图记录您稍后抛出给调用者的异常“以防万一”调用者没有正确记录异常 - 所发生的一切是您最终会在它通过时多次记录相同的异常从层到层(我已经看到它发生了,很难看到实际发生了多少错误)。
记录错误是调用者的责任 - 唯一可能的异常可能是在系统边界(例如 Web 服务)之间传递,在这种情况下无法传输所有错误详细信息。
例如,如果您正在编写基于服务器的应用程序,那么您的日志文件需要在服务器上,系统管理员可以在服务器上读取它们 - 但是如果客户端上可能发生错误(例如在 JavaScript 中),那么您的日志记录代码需要在 JavaScript 中。解决方案?您的 JavaScript 日志记录需要将自身提交到服务器(ala log4js)
不用担心你应该和不应该把日志放在哪里——只要把它放在需要的地方。
【讨论】:
一般来说,最好在您拥有所有必要信息的地方记录事情。为了使您的应用程序更简单,最好不要传递数据,以便您可以将其记录到其他地方。 (例外似乎是一个例外 - 对不起双关语:-) - 但它们的主要目的不是记录,这只是一个可能的副作用。)
没有必要将日志记录限制到体系结构的特定模块/层(除了一些特殊情况,例如不应该记录任何内容的设备驱动程序,或不得对环境做出假设的应用程序库)。
请注意,即使在同一个应用程序中,不同的日志消息也可能有不同的用途:
现代日志框架(例如 Log4J 系列)允许非常灵活地处理来自应用程序不同部分的不同类型(级别)的消息。不过,在向代码中添加大量日志消息之前计划好您的日志记录方案是一个好主意。 IE。您计划在应用程序的哪些部分登录什么类型的消息,以及您将如何使用这些消息?您需要多少和什么样的日志目标(控制台、文件、数据库)?
【讨论】:
我觉得 Microsoft 架构指南很好读。 http://msdn.microsoft.com/en-us/library/ff650706.aspx
日志记录是所有层的交叉关注点
【讨论】:
到目前为止,我使用了“黑盒”策略。每段代码(函数或/和类)在许多方面都有自己的责任:输入测试、做它应该做的事情、错误处理、记录信息。因此,如果您的代码位于业务层,它应该抛出业务错误,并记录业务信息
【讨论】:
我认为在应用程序中非常重要的常见错误处理。
来自JavaWorld,以下是常见错误处理必不可少的原因:
膨胀的日志:每个catch块都包含一个日志语句,导致源代码污染导致日志条目臃肿冗余。
冗余实现:相同类型的错误具有不同的表示,这使得处理方式变得复杂。
封装损坏:来自其他组件的异常被声明为方法签名的一部分,打破了接口和实现之间的明确划分。
Noncommittal 异常声明:方法签名被泛化为抛出 java.lang.Exception。这样,可以确保客户端对方法的错误语义没有任何线索。
【讨论】: