避免 printStackTrace();改用记录器调用
Posted
技术标签:
【中文标题】避免 printStackTrace();改用记录器调用【英文标题】:Avoid printStackTrace(); use a logger call instead 【发布时间】:2012-05-15 16:43:24 【问题描述】:在我的应用程序中,我正在通过 PMD 运行我的代码。它向我显示了这条消息:
。
这是什么意思?
【问题讨论】:
另见When to log a stacktrace for a caught exception 【参考方案1】:这意味着你应该使用像logback或log4j这样的日志框架,而不是直接打印异常:
e.printStackTrace();
您应该使用此框架的 API 记录它们:
log.error("Ops!", e);
日志框架为您提供了很大的灵活性,例如您可以选择是否要登录到控制台或文件 - 或者如果您发现某些消息在某些环境中不再相关,则可以跳过它们。
【讨论】:
【参考方案2】:如果您在异常情况下调用printStackTrace()
,则跟踪将写入System.err
,并且很难将其路由到其他地方(或过滤它)。建议您不要这样做,而是使用日志框架(或多个日志框架的包装器,如 Apache Commons Logging)并使用该框架(例如 logger.error("some exception message", e)
)记录异常。
这样做可以让您:
一次将日志语句写入不同的位置,例如控制台和文件 按严重性(错误、警告、信息、调试等)和来源(通常基于包或类)过滤日志语句 无需更改代码即可对日志格式产生一定影响 等【讨论】:
【参考方案3】:生产质量计划应使用多种日志记录替代方案之一(例如 log4j、logback、java.util.logging)来报告错误和其他诊断。这有很多优点:
日志消息转到可配置的位置。 最终用户看不到消息,除非您配置日志记录以便他/她看到。 您可以使用不同的记录器和记录级别等来控制记录的记录量少或多。 您可以使用不同的附加程序格式来控制日志记录的外观。 您可以轻松地将日志输出插入到更大的监控/日志框架中。 以上所有操作都可以在不更改代码的情况下完成;即通过编辑已部署应用程序的日志记录配置文件。相比之下,如果您只使用 printStackTrace,部署者/最终用户几乎没有任何控制权,并且日志消息可能会丢失或在不适当的情况下显示给最终用户。 (没有什么比随机堆栈跟踪更能吓到胆小的用户了。)
【讨论】:
【参考方案4】:在 Simple 中,e.printStackTrace() 不是一个好习惯,因为它只是将堆栈跟踪打印到标准错误。因此,您无法真正控制此输出的去向。
【讨论】:
【参考方案5】:几乎每个日志框架都提供了一种方法,我们可以在该方法中将可抛出对象与消息一起传递。喜欢:
public trace(Marker marker, String msg, Throwable t);
它们打印可抛出对象的堆栈跟踪。
【讨论】:
这没有回答问题。【参考方案6】:让我们从公司概念谈起。日志为您提供灵活的级别(请参阅Difference between logger.info and logger.debug)。不同的人希望看到不同的级别,例如 QA、开发人员、业务人员。但是 e.printStackTrace() 将打印出所有内容。另外,如果这个方法会被调用,同样的错误可能会打印多次。那么贵公司的 Devops 或 Tech-Ops 人员可能会发疯,因为他们会收到相同的错误提醒。
我认为更好的替代品可能是log.error("errors happend in XXX", e)
这也会打印出比 e.printStackTrace() 更容易阅读的全部信息
【讨论】:
【参考方案7】:主要原因是 Proguard 会从生产环境中移除 Log 调用。因为通过记录或打印 StackTrace,可以通过例如 Logcat Reader 应用程序在 android 手机中查看它们(堆栈跟踪或日志中的信息)。因此,这对安全性来说是一种不好的做法。此外,我们不会在生产过程中访问它们,最好从生产中删除。由于 ProGuard 移除所有 Log 调用而不是 stackTrace,所以最好在 catch 块中使用 Log,并让 Proguard 将它们从生产中移除。
【讨论】:
以上是关于避免 printStackTrace();改用记录器调用的主要内容,如果未能解决你的问题,请参考以下文章
执行几个 mongoose 查询:如何改用 Promise?
Yii2 RESTful API,带有数据访问对象而不是活动记录