SLF4J是一个非常流行的日志记录外观,但是,就像我们使用的所有库一样,我们有可能以错误的方式或至少以非最佳方式使用它。

在本教程中,我们将列出常见的日志记录错误以及如何使用FindBugs检测到它们。 我们还将在相关时提及PMD和Sonar Squid检查。

我们将使用两个外部的FindBugs插件,它们将日志检测器添加到FindBugs。

第一个是Kengo Toda的SLF4J only插件 ,其中仅包含SLF4J检测器。

第二个插件是流行的FB Contrib ,它包含许多测井仪。

有关如何使用FindBugs插件的信息,请参阅以下文章:

  • [Maven]( https://gualtierotesta.wordpress.com/2015/06/14/tutorial-using-findbugs-with-maven/ )
  • [NetBeans]( https://gualtierotesta.wordpress.com/2015/06/07/findbugs-plugins/ )

注意:在所有示例中,我们将假定以下导入:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

1.记录仪定义

错误的方法:

W1a. Logger log = LoggerFactory.getLogger(MyClass.class);
W1b. private Logger logger = LoggerFactory.getLogger(MyClass.class);
W1c. static Logger LOGGER = LoggerFactory.getLogger(AnotherClass.class);

正确方法:

C1a. private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);
C1b. private final Logger logger = LoggerFactory.getLogger(getClass());

一般规则 :记录器应该是最终的且私有的,因为没有理由与其他类共享或重新分配它。

相反,对于记录器是否应该是静态的,没有普遍的协议。 SLF4J插件支持非静态版本(C1b),而PMD(“ LoggerIsNotStaticFinal”规则)和Sonar(鱿鱼规则S1312)更喜欢静态记录器(C1a),因此这两个选项均应视为有效。

附加信息:

  • [SLF4J常见问题解答]( http://slf4j.org/faq.html#declared_static )
  • [Apache Commons静态日志]( http://wiki.apache.org/commons/Logging/StaticLog )。

请注意:

  • 在静态版本(C1a)中,记录器名称通常使用大写字母作为所有常量字段。 否则,PMD将报告“ VariableNamingConventions”违规行为。
  • 在这两种情况下,建议的名称都是“ logger / LOGGER”而不是“ log / LOG”,因为某些命名约定会避免使用太短的名称(少于四个字符)。 而且log是动词,更适合于方法名。
  • W1c是错误的,因为我们指的是一个类(AnotherClass),它不是定义记录器的类。 在99%的情况下,这是由于从一类到另一类的复制粘贴所致。

相关的FindBugs(SLF4J插件)检查:

  • SLF4J_LOGGER_SHOULD_BE_PRIVATE
  • SLF4J_LOGGER_SHOULD_BE_NON_STATIC
  • SLF4J_LOGGER_SHOULD_BE_FINAL
  • SLF4J_ILLEGAL_PASSED_CLASS

2.格式字符串

错误的方法:

W2a. LOGGER.info("Obj=" + myObj);
W2b. LOGGER.info(String.format(“Obj=%s”, myObj));

正确方法:

C2. LOGGER.info("Obj={}",myObj);

一般规则 :格式字符串(第一个参数)应为常量,没有任何字符串串联。 动态内容(示例中的myObj值)应使用占位符('{}')添加。

动机很简单:无论是否记录消息,我们都应在记录器建立延迟记录消息的创建,具体取决于当前的记录级别。 如果我们使用字符串连接,则无论采用哪种日志记录级别,都会以任何方式构建消息,这会浪费CPU和内存资源。

相关的FindBugs(SLF4J插件)检查:

  • SLF4J_FORMAT_SHOULD_BE_CONST格式应为常数
  • SLF4J_SIGN_ONLY_FORMAT格式字符串不应仅包含占位符

相关的FindBugs(FB Contrib插件)检查:

  • LO_APPENDED_STRING_IN_FORMAT_STRING方法将串联的字符串传递给SLF4J的格式字符串

3.占位符参数

错误的方法:

W3a. LOGGER.info("Obj={}",myObj.getSomeBigField());
W3b. LOGGER.info("Obj={}",myObj.toString());
W3c. LOGGER.info("Obj={}",myObj, anotherObj);
W3d. LOGGER.info("Obj={} another={}",myObj);

正确方法:

C3a. LOGGER.info("Obj={}",myObj);
C3b. LOGGER.info("Obj={}",myObj.log());

一般规则 :占位符应该是对象(C3a),而不是方法返回值(W3a),以便在记录级别分析后推迟对其求值(请参见上一段)。 在W3a示例中,无论日志记录级别如何,都会始终调用方法getSomeBigField()。 出于相同的原因,我们应该避免在语义上与C3a等效的W3b,但是它总是在toString()方法调用中产生。

解决方案W3c和W3d错误,因为格式字符串中占位符的数量与占位符参数的数量不匹配。

解决方案C3b可能在某种程度上具有误导性,因为它包括方法调用,但只要myObj包含多个字段(例如,它是一个大型JPA实体),但我们不想记录其所有内容时,它就很有用。

例如,让我们考虑以下类:

public class Person {
private String id;
private String name;
private String fullName;
private Date birthDate;
private Object address;
private Map<String, String> attributes;
private List phoneNumbers;

它的toString()方法很可能会包含所有字段。 使用解决方案C3a,所有它们的值都将打印在日志文件中。

如果不需要所有这些数据,则定义如下的帮助方法将很有用:

public String log() {
return String.format("Person: id=%s name=%s", this.id, this.name);
}

仅打印相关信息。 此解决方案的CPU和内存也比toString()轻。

有什么关系? 它取决于应用程序和对象类型。 对于JPA实体,我通常在log()方法中包括ID字段(如果需要所有列数据,以便让我在数据库中找到记录),并且可能是一两个重要字段。

毫无疑问,应该记录密码字段和/或敏感信息(电话号码,…)。 这是不使用toString()登录的另一个原因。

相关的FindBugs(SLF4J插件)检查:

  • SLF4J_PLACE_HOLDER_MISMATCH

4.调试消息

重要提示:规则4(请参阅5条规则文章 )指导我们使用受保护的调试日志记录

if (LOGGER.isDebugEnabled()) {
LOGGER.debug(“Obj={}”, myObj);
}

使用SLF4J,如果占位符参数是对象引用(请参阅解决方案C3a / C3b),则可以使用if来避免代码混乱。

因此,使用以下内容是安全的:

LOGGER.debug(“Obj={}”, myObj);

5.例外

适当的异常日志记录是问题分析的重要支持,但很容易忽略它的用处。

错误的方法:

W5a. catch (SomeException ex) { LOGGER.error(ex);}..
W5b. catch (SomeException ex) { LOGGER.error("Error:" + ex.getMessage());}..

正确方法:

C5. catch (SomeException ex) { LOGGER.error("Read operation failed: id={}", idRecord, ex);}..`

一般规则

  1. 不要使用getMessage()(请参阅W5b)而不是完整的异常来删除堆栈跟踪信息。 堆栈跟踪通常包括问题的真正原因,很容易是底层代码引发的另一个异常。 仅记录消息将阻止我们发现问题的真正原因。
  2. 确实在日志消息中显示了重要的信息(供将要分析日志文件的人员使用),该信息显示了一个文本,解释了在引发异常(不是异常种类或诸如“错误”之类的消息)时我们想要执行的操作:我们已经知道有些不良情况发生了)。 我们需要知道的是我们在做什么以及在哪些数据上。

C5示例告诉我们,我们正在尝试读取具有特定ID的记录,该ID的值已与消息一起写入日志。

请注意,C5在格式字符串中使用一个占位符,但是有两个附加参数。 这不是错误,而是一种特殊的模式,SLF4J将其识别为异常记录案例:最后一个参数(在C5示例中为ex)被SLF4J视为Throwable(异常),因此不应将其包含在格式字符串中。

相关的FindBugs(SLF4J插件)检查:

  • SLF4J_MANUALLY_PROVIDED_MESSAGE:消息不应基于异常getMessage()

翻译自: https://www.javacodegeeks.com/2016/02/tutorial-correct-slf4j-logging-usage-check.html

教程:正确的SLF4J日志记录用法以及如何检查它相关推荐

  1. slf4j 记录日志文件_教程:正确的SLF4J日志记录用法以及如何检查它

    slf4j 记录日志文件 SLF4J是一个非常流行的日志记录外观,但是,就像我们使用的所有库一样,我们有可能以错误的方式或至少以一种非最佳方式使用它. 在本教程中,我们将列出常见的日志记录错误以及如何 ...

  2. exception日志 php_PHP中错误与异常的日志记录用法分析

    本文分析了PHP中错误与异常的日志记录用法.分享给大家供大家参考,具体如下: 提到 Nginx + PHP 服务的错误日志,我们通常能想到的有 Nginx 的 access 日志.error 日志以及 ...

  3. slf4j没有在linux中生成日志,slf4j日志记录问题 - 未生成日志文件

    我正在使用slf4j通过java实用程序日志记录.我试图放置logging.properties文件,以便它会被我的web应用程序拾取.以下是我的logging.properties文件怎么样子:sl ...

  4. java 核型技术 卷2 pdf_SpringBoot 的 slf4j日志记录

    需求:项目中我们必然会使用日志记录,哪个日志框架更好用? 1.强烈推荐SLF4J: SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案, ...

  5. 两个组件连线_如何正确的使用日志组件 Log4j、SLF4J、Logback

    来源:http://t.cn/EVpprGI 相信目前大多数情况下,不管是开源框架或是平时工作编码中都离不开一种框架,它就是日志框架,本文了解一下我们常用日志框架的区别及如何正确的使用. 1.Comm ...

  6. 在云环境上使用SLF4J对Java程序进行日志记录

    我开发了一个Java应用,部署到云环境上之后,用postman测试发现不能按照我期望的工作,但是返回的消息对我没有任何帮助. 因为部署在云端的应用很难像本地Java应用一样调试,所以我打算用SLF4J ...

  7. Spring Boot SLF4J日志实例

    From: https://blog.csdn.net/lxh18682851338/article/details/78560295 默认情况下,SLF4j日志记录包含在Spring Boot We ...

  8. 如何在.NET中启用程序集绑定失败日志记录(Fusion)

    如何在.NET中启用程序集绑定失败日志记录(Fusion)? #1楼 如果您已经启用了日志记录,并且在Windows 7 64位上仍然出现此错误,请在IIS 7.5中尝试: 创建一个新的应用程序池 转 ...

  9. springboot开启debug日志_Spring Boot SLF4J日志实例(五十)

    默认情况下,SLF4j日志记录包含在Spring Boot Web应用程序中,只需要启用它就可以了. 注意:查看此Spring Boot Logback XML模板以了解默认的日志记录模式和配置. S ...

最新文章

  1. 如何查看dede版本信息
  2. UI5应用如果出现白屏但是没有任何错误消息打印出来,应该如何处理
  3. struts2中s:select标签在freemarker中的使用
  4. CSS3 2D Transform
  5. 如何做一名优秀的电子工程师[zz]
  6. Matlab-Octave中绘制网格图和等高线:mesh 和 surf
  7. 连线Face++前方团队:COCO夺冠背后的细节,不是拼硬件这么简单
  8. 小云(云层-陈霁)的发展史
  9. Subsequence Count (线段树)
  10. WinForm中的特殊窗体效果:渐变窗口和信息提示窗口
  11. steamcom启动服务:443端口被占用,请关闭占用该端口的进程后再点击启动服务!
  12. 怎么看电脑支持多少兆网速_电脑网速怎么看(电脑怎么看网速多少兆)
  13. vue图片压缩不失真_压缩图片大小(像素)
  14. python transforms_Python transforms.Compose方法代码示例
  15. html5 手绘效果,浅谈基于Canvas的手绘风格图形库Rough.js
  16. 阿里P5的测试开发工程师,都有哪些要求?
  17. 【经验分享】如何使用校园账号登录WOS(Web of Science)
  18. IE6浏览器不支持固定定位(position:fixed)解决方案
  19. java制作我的世界_Minecraft Java版整合包制作教程
  20. qzezoj 1665 虫洞路线

热门文章

  1. LinkedList 的实现原理浅析
  2. Maven精选系列--三种仓库详解
  3. Java 高并发下的实践
  4. JavaFX之TableView的TableRow
  5. C++描述杭电OJ 2016.数据的交换输出 ||
  6. java实现动态验证码源代码——jsp页面
  7. count() * ,1,字段 三兄弟
  8. Linux中打包和解压到的方法
  9. mybatis-plus 错误java.lang.NoClassDefFoundError: org/apache/velocity/context/Context
  10. 数据库表连接总结:等值连接, 自然连接,左外连接,右外连接,内连接,全外连接;