【问题标题】:Sonar complaining about logging and rethrowing the exception声纳抱怨记录并重新抛出异常
【发布时间】:2015-03-23 05:19:50
【问题描述】:

我的程序中有以下代码,在将其与 Maven 集成后,我正在运行 SonarQube 5 对其进行代码质量检查。

但是,Sonar 抱怨我应该记录或重新抛出此异常

我在这里缺少什么?我还没有记录异常吗?

 private boolean authenticate(User user) {
        boolean validUser = false;
        int validUserCount = 0;
        try {
            DataSource dataSource = (DataSource) getServletContext().getAttribute("dataSource");
            validUserCount = new MasterDao(dataSource).getValidUserCount(user);
        } catch (SQLException sqle) {
            LOG.error("Exception while validating user credentials for user with username: " + user.getUsername() + " and pwd:" + user.getPwd());
            LOG.error(sqle.getMessage());
        }
        if (validUserCount == 1) {
            validUser = true;
        }
        return validUser;
    }

【问题讨论】:

  • 也许它抱怨你正在记录一条消息,而不是异常本身,这使你失去了异常的潜在有用堆栈跟踪。无论如何,您绝对应该在这里抛出异常并向用户发出问题信号,而不是像一切正常一样返回相同的东西,就好像用户凭据不正确一样。记录密码也绝对不是一个好主意:主要的安全问题。
  • 您没有在一个语句中记录消息和异常。因此,其他日志条目可能位于服务器日志中的两条消息之间,隐藏了这两条消息的强连接。第一个日志语句可能会引发异常,隐藏第二个日志语句中包含的信息。
  • Sonar 有时会遇到像这里这样的 动态日志消息 的问题。请参阅Java-specific issue: SONARJAVA-3029。 2019 年解决。

标签: java maven exception-handling sonarqube sonarqube-5.0


【解决方案1】:

你应该这样做:

try {
    DataSource dataSource = (DataSource) getServletContext().getAttribute("dataSource");
    validUserCount = new MasterDao(dataSource).getValidUserCount(user);
} catch (SQLException sqle) {
    LOG.error("Exception while validating user credentials for user with username: " +
            user.getUsername() + " and pwd:" + user.getPwd(), sqle);
}

声纳不应该再打扰你了

【讨论】:

  • 如果异常类似于 java.util.concurrent.ExecutionException 并且您真的只想记录原因。我在下面看到关于忽略特定异常的评论!谢谢!
  • 我认为这个声纳投诉太严格了。您可能希望捕获和忽略一些异常,例如,FileNotFoundException 可能会被捕获并记录一条消息,指示未找到该文件,并且在没有它的情况下将继续执行 - 对于这种情况,没有人需要整个堆栈跟踪。然而,除了用 //NOSONAR 标记捕获线之外,没有办法让声纳闭嘴。
  • IMO 也太严格了。我有一个用例,我需要捕获一个异常并抛出另一个只能用消息实例化的第三方库异常,而不是根异常。实际上,我可能会针对该特定案例报告声纳问题...
  • 你能解释一下“这种方式”并告诉我们一些关于为什么的事情吗?这将有助于未来的读者更好地理解 SonarLint 问题背后的原因。
【解决方案2】:

如果您认为可以安全地忽略 SQLException,则可以将其添加到 squid:S1166 规则的例外列表中。

  1. 转到规则-> 搜索 squid:S1166。
  2. 在质量配置文件中编辑例外。
  3. 将 SQLException 添加到列表中。

【讨论】:

  • 这真的很有帮助,尤其是在像 java.util.concurrent.ExecutionException 这样的包装异常的情况下,我真的想要原因而不是这个异常本身。
  • 您还可以更细化并使用 @SuppressWarnings("squid:S1166") 注释您的方法 // [在此处添加一些说明] 这样您就可以保留其他情况的规则。
【解决方案3】:

我偶然发现了同样的问题。我不是 100% 确定我在这一点上是否完全正确,但基本上你应该重新抛出或记录完整的异常。而e.getMessage() 只是给你详细的消息,而不是执行堆栈的快照。

来自Oracle docs (Throwable)

throwable 包含其线程在创建时的执行堆栈的快照。它还可以包含提供有关错误的更多信息的消息字符串。随着时间的推移,一个 throwable 可以抑制其他 throwable 的传播。最后,throwable 还可以包含一个原因:导致构造此 throwable 的另一个 throwable。这种因果信息的记录被称为链式异常设施,因为原因本身可以有一个原因,依此类推,导致异常“链”,每个异常都由另一个引起。

这意味着 abarre 提供的解决方案有效,因为整个异常对象 (sqle) 正在传递给记录器。

希望对您有所帮助。 干杯。

【讨论】:

    【解决方案4】:

    声纳要求你做的是持久化整个异常对象。 你可以使用类似的东西:

        try {
            ...         
        } catch (Exception e) {
            logger.error("Error", e);
        }
    

    【讨论】:

    • 我知道这是一个例子,但为了像我这样的初学者教育,我想补充一点,我们通常不应该捕获异常,而是它的实现之一。
    • 我想要记录和投掷。有什么解决办法吗?
    • @KumaresanPerumal 您可以在记录后添加一个throw 子句(rollbar.com/guides/java/how-to-throw-exceptions-in-java),同时仍在捕获块内
    猜你喜欢
    • 2022-01-12
    • 2017-01-17
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 2012-02-21
    • 2015-11-18
    • 2020-02-15
    相关资源
    最近更新 更多