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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux逐行扫描,FFmpeg怎么区分识别视频是逐行扫描还是隔行扫描

最近遇到要识别隔行扫描的视频加以特殊转码处理的问题。google了一番以后找到两个解决的方式&#xff0c;记录一下。方法一&#xff1a;使用隔行扫描检查滤镜idet区分隔行扫描和逐行扫描ffmpeg -filter:v idet \ -frames:v 100 \ -an \ -f rawvideo -y /dev/null \ -i 351.mp4 …

JDBC学习笔记 day1

JDBC的基本概念&#xff1a; JDBC就是java database connectivity&#xff0c;即java数据库连接。 JDBC主要完成的几个任务分别为 与数据库建立一个连接  向数据库发送SQL语句  处理数据库返回的结果JDBC的作用&#xff1a; 将java程序语言编写出来的程序&#xff0c;与数据…

稀疏矩阵的转置c语言程序,程序有问题求大神,稀疏矩阵转置

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include #define N 100typedef int DataType;typedef struct{int i,j;DataType v;}TriTupleNode;typedef struct{TriTupleNode data[N];int m,n;int t;}TriTupleTable;void TransMatrix(TriTupleTable *b,TriTupleTable *a);void …

jsf组件不显示_JSF组件库–质量不只是零缺陷

jsf组件不显示自从我上次查看三个主要JSF组件库的质量以来已经有一段时间了。 在2009年12月&#xff0c;我开始比较RichFaces&#xff0c;Primefaces和ICEfaces的整体软件质量 。 从那时起&#xff0c;事情发生了变化&#xff0c;从现在开始&#xff0c;我想重新评估和更新它。…

linux安装mysql(shell一键安装)

1. 相关文件&#xff08;install_mysql.sh、my.cnf、mysqld相关内容在文中最后面&#xff09; 2. 将上面的文件上传到linux服务器某一目录下 3.给install_mysql.sh赋执行权限 # chmod x instll_mysql.sj 4. 执行install_mysql.sh # ./install_mysql.sh 5. 验证 6. install_mysq…

c语言编译时检查逻辑错误吗,C语言陷阱与技巧20节,自定义“编译时”assert方法,在代码编译阶段检查“逻辑”错误...

在C语言程序开发中&#xff0c;程序员写代码时应该考虑的“面面俱到”&#xff0c;这样才能写出功能稳定的程序。例如&#xff0c;在实现 open() 函数时&#xff0c;先完成它的功能固然是重要的&#xff0c;但是程序员还需要考虑各种“意外”&#xff0c;比如下面这种情况。假设…

springboot 多个sevice类实现同一接口的调用

参考页面&#xff1a;http://blog.csdn.net/xiao190128/article/details/54890759/&#xff1b;感谢分享 service 是有用的相当于 xml配置中得bean id service 也可以不指定 不指定相当于 bean id com. service.service 就是这个类的全限定名,表示给当前类命名一个别名&a…

影场与属性访问器界面

卡尔迪亚&#xff08;Carl Dea&#xff09;最近跟踪了我的一篇名为“ 保存内存”的博客文章&#xff01; 为属性使用阴影字段 。 在他的博客中&#xff0c;他建议使用一个称为“属性访问器”的接口来消除使用阴影字段所需的大量样板代码。 卡尔还提到他尚未用大量数据测试他的方…

[ZJOI2012]数列

超级水的题还wa了一次 首先很容易发现其实就只有两个值并存 然后 要注意把数组初始化啊。。。可能后面有多余的元素&#xff08;对拍的时候由于从小到大就没跑出错&#xff09; #include <bits/stdc.h> using namespace std; int a[170],b[170],a1[170],a2[170],x1[170],…

在c语言中,可以使用动态内存分配技术定义元素个数可变的数组,C语言复制在线考题1精选.doc...

C语言复制在线考题1精选窗体顶端《C语言程序设计208304》综合测试返回测验列表大项 1 / 2 - 单项选择题60.0/ 70.0 分本大题共35道&#xff0c;每题2分&#xff0c;共计70分&#xff0c;答错、不答均不得分。题目 1 / 552.0/ 2.0 分有字符数组 a[80]和 b[80]&#xff0c;则正确…

信管家源代码c语言,用队列实现按层次创建二叉树的源代码,最好是C语言

满意答案Dcool2016.08.27采纳率&#xff1a;58% 等级&#xff1a;9已帮助&#xff1a;416人队列&#xff1f;&#xff1f;你每输入一个节点将其存入队列中&#xff0c;再输入它的左孩子&#xff0c;它的左孩子也会入队&#xff0c;我们取的时候应先取该节点的左孩子&#xf…

jboss4 java_JBoss核心Java Web服务

jboss4 java这篇博客文章涉及Web服务。 好吧&#xff0c;更确切地说&#xff0c;它处理JBoss上的“普通” java Web服务。 这意味着我们将创建一个没有任何其他框架&#xff08;例如CXF&#xff0c;Axis等&#xff09;的Web服务。 JBoss它自己提供对Web服务的支持。 因此&#…

Java中的注解是如何工作的?

自Java5.0版本引入注解之后&#xff0c;它就成为了Java平台中非常重要的一部分。开发过程中&#xff0c;我们也时常在应用代码中会看到诸如Override&#xff0c;Deprecated这样的注解。这篇文章中&#xff0c;我将向大家讲述到底什么是注解&#xff0c;为什么要引入注解&#x…

android 广告弹出层,安卓广告活动弹窗控件 android-adDialog

软件介绍android-adDialog&#xff0c;一个简单、强大的广告活动弹窗控件。显示一个默认广告弹窗&#xff0c;支持单广告活动、多广告活动&#xff0c;当弹窗显示多广告是默认显示底部小圆圈&#xff0c;当显示单活动时默认不显示底部小圆圈&#xff1b;默认支持弹窗从上&#…

面试技巧

本人是一名95后的老奶奶了&#xff0c;是一名彻头彻尾的程序媛&#xff0c;这是本人的第一篇博客&#xff0c;只是随笔&#xff0c;写写自己的心得而已&#xff0c;写的不好勿喷&#xff01;&#xff01;&#xff01; 学习计算机大概已经四年了&#xff0c;在这期间接触过各种计…

(企业 / 公司项目)如何使用分布式任务调度框架Quartz集成 和 SpringBoot自带的定时任务集成?

SpringBoot自带的定时任务 首先在你的微服务项目中创建一个新的模块&#xff0c;定时调度模块 pom.xml里面关联公共模块common的依赖其他不需要改变 然后启动类别删&#xff0c;启动项目是否报错&#xff0c;写一个简单的测试类访问路径是否成功 package com.jiawa.train.bat…

在Spring中配置多个View解析器

1.简介 在Spring中&#xff0c;提供了View Resolver来使用模型中可用的数据来解析视图&#xff0c;而无需与JSP&#xff0c;Velocity或Thymeleaf等View技术紧密绑定。 Spring可以根据需要轻松灵活地配置一个或多个View Resolver 。 2. Spring MVC应用程序流程 在继续理解多个V…

android 知识体系

转载于:https://www.cnblogs.com/mamamia/p/8567570.html

android webview webp,iOS WebView中使用webp格式图片的方法

webp格式图片webp格式图片是google推出的&#xff0c;相比jpg png有着巨大的优势&#xff0c;同样质量的图片webp格式的图片占用空间更小&#xff0c;在像电商这样图片比较多的App中&#xff0c;使用webp格式图片会很有优势。引言很早之前&#xff0c;我们的项目中就已经采用了…

呵呵!Function构造函数

今天准备吐槽一下Function构造函数。 我们知道&#xff0c;不管是函数声明还是函数表达式都是基于词法作用域的&#xff0c;明白这点在闭包中十分重要&#xff0c;譬如&#xff1a; var aglobal; function foo(){var alocal;return function(){console.log(a);} } foo()(); …