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

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

slf4j 记录日志文件

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

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

相关文章

Leetcode 146. LRU 缓存机制

原题链接 题解&#xff1a;双链表哈希表 class LRUCache { public:struct Node {int key, val;Node *left, *right;Node(int _key, int _val): key(_key), val(_val), left(NULL), right(NULL) {}}*L, *R;unordered_map<int, Node*> hash;int n;void remove(Node* p) {…

Leetcode 28. 实现 strStr()

原题链接 解&#xff1a;KMP算法 class Solution { public:int strStr(string s, string p) {if (p.empty()) return 0;int n s.size(), m p.size();s s, p p;vector<int> next(m 1);for (int i 2, j 0; i < m; i ) {while (j && p[i] ! p[j …

jsf和jsp_带有JSF,Servlet和CDI的DynamicReports和JasperReports

jsf和jsp在此示例中&#xff0c;我将展示如何将DynamicReport和JasperReports与Servlet和CDI集成。 工具&#xff1a; TIBCO Jaspersoft Studio-6.0.4。最终版 Eclipse Luna服务版本2&#xff08;4.4.2&#xff09;。 WildFly 8.x应用程序服务器。 这是Eclipse上项目层次结…

接口隔离原则_设计模式的三大分类及六大原则

设计模式(Design pattern)代表了最佳的实践&#xff0c;通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。设计模式分为三大类&…

Leetcode 24. 两两交换链表中的节点

原题链接 题解&#xff1a; 1.头部会改变创建虚拟头结点 2.前两个点定义为a,b&#xff0c;c 3.p指向b,a指向c,b指向a ; p指向本段最后一个结点。 class Solution { public:ListNode* swapPairs(ListNode* head) {auto dummy new ListNode(-1);dummy->next head;for (a…

spring aop不执行_使用Spring AOP重试方法执行

spring aop不执行我的一位博客关注者发送了一封电子邮件&#xff0c;要求我显示“ Spring AOP的RealWorld用法”示例。 他提到&#xff0c;在大多数示例中&#xff0c;都演示了Spring AOP在日志记录方法进入/退出或事务管理或安全性检查中的用法。 他想知道Spring AOP在“针对…

LeetCode 09. 回文数

原题链接 class Solution { public:bool isPalindrome(int x) {if(x<0)return false;if(x>0 && x<10)return true;long long temp 0;int xx x;while(x!0){int n x % 10;temp temp * 10 n;x /10;}if(temp xx)return true;else{return false;}} };

python 获取文件名_真实需求 | Python+os+openpyxl 批量获取Excel的文件名和最大行数...

1. 提出需求 这已经不知道是粉丝问我的第几个办公自动化的问题了&#xff0c;并且这些问题都是大家在学习和工作中碰到过的真实问题场景。其实从下图中已经可以很明确的看出别人的需求了&#xff0c;我这里就不用在赘述了&#xff0c;下面直接上思路吧&#xff01;2. 解题思路为…

LeetCode 03. 无重复字符的最长子串

原题链接 解题思路: (双指针扫描) O(n)&#xff0c;双指针主要作用是维护一段区间 定义两个指针 i,j(i<j)&#xff0c;表示当前扫描到的子串是 [i,j] (闭区间)。扫描过程中维护一个哈希表unordered_map<char,int> hash&#xff0c;表示 [i,j]中每个字符出现的次数。…

python元组取值_Python基础之元组

元组初识元组的认识首先&#xff0c;我们来认识一下元组&#xff1a;# 定义一个元组uesr_tuple ("zhangsan", "lisi", "wangwu")# 定义一个空元组empty_tuple ()元组的作用和定义通过前面的学习&#xff0c;我们知道&#xff0c;列表通常用来存…

junit5和junit4_JUnit 5 –下一代JUnit的初步了解

junit5和junit42月初&#xff0c; JUnit 5&#xff08;又名JUnit Lambda&#xff09;团队发布了一个alpha版本。 由于JUnit 4是我工具箱中使用最多的项目之一&#xff0c;因此我认为值得一看下一个主要版本。 我试用了最新版本&#xff0c;并记下了我在这里发现值得注意的更改…

python进阶装饰器_老生常谈Python进阶之装饰器

函数也是对象要理解Python装饰器&#xff0c;首先要明白在Python中&#xff0c;函数也是一种对象&#xff0c;因此可以把定义函数时的函数名看作是函数对象的一个引用。既然是引用&#xff0c;因此可以将函数赋值给一个变量&#xff0c;也可以把函数作为一个参数传递或返回。同…

LeetCode 02.两数相加

原题链接 解题思路&#xff1a; 本题可以使用模拟法&#xff0c;从链表的结点中提取出val逐个相加&#xff0c;没有值取0。并且记录进位&#xff0c;每个节点只保留个位数&#xff0c;所以需要使用sum与10取模&#xff0c;如果最高位存在进位则需要在最后添加一个val为1的节点…

apache ignite_从In Memory Data Grid,Apache Ignite快速入门

apache igniteIMDG或内存数据网格不是内存中关系数据库&#xff0c;NOSQL数据库或关系数据库。 它是另一种软件数据存储库。 数据模型分布在单个位置或多个位置的许多服务器上。 这种分布称为数据结构。 这种分布式模型被称为“无共享”架构。 IMDG具有以下特征&#xff1a; 所…

bvp解算器是什么_那些学习了编程的中学生,为什么会更可能成功?

来源 | 异步当你看到这个题目&#xff0c;或许会想&#xff0c;这不是搞笑吗&#xff1f;众所周知&#xff0c;高等数学是编程的基础和前提&#xff0c;而说起程序编写员&#xff0c;在普通人眼里就是数学学霸的代名词&#xff0c;人们往往会把它和那些数学天才的名字联系在一起…

Leetcode 08. 字符串转换整数 (atoi)

原题链接 1.字符 0~~~~~9 分别对应整数 48~~~~~57 2.先过滤空白 3.确定前面所带的符号 4. long long res 0; res res * 10 str[k] - 0; 可以通过此方法从左到右高位逐个累加。 class Solution { public:int myAtoi(string str) {long long res 0;int k 0;while…

maven与spring_与Spring和Maven签约首个SOAP服务

maven与spring1.简介 在本教程中&#xff0c;我们将学习使用JAX-WS&#xff0c;Spring和Maven实施合同优先的SOAP服务应用程序。 这是使用合同优先还是代码优先方法的更多设计决定。 在开发基于SOAP的Web服务应用程序时使用应用合同优先的方法最显着的好处是&#xff0c;可以在…

如何维持手机电池寿命_充电小知识:你知道如何正确充电吗?这几种充电方式最损害电池...

目前基本上大部分人都至少有一部智能手机&#xff0c;智能手机基本上都需要每日一充&#xff0c;你的充电方式会不会损伤电池呢&#xff1f;有部分消费者认为要等到手机电量耗尽后再充电&#xff0c;还有人认为手机充电要充至100%才能拔下来&#xff0c;有人觉得充电宝等产品给…

【开放集检测】OpenGAN: Open-Set Recognition via Open Data Generation 论文阅读

文章目录 英语积累为什么使用GAN系列网络进行开放集检测摘要1. 前言2. 相关工作开集检测基于GAN网络的开集检测基于暴露异常数据的开集检测 3. OpenGAN3.1 公式建模3.1.1 二分类方法存在问题如何解决 3.1.2 使用合成数据存在问题如何解决 3.1.3 OpenGAN3.1.4 模型验证 3.2 先前…

LeetCode 27.移除元素

原题链接 /** lc appleetcode.cn id27 langcpp** [27] 移除元素标签&#xff1a;拷贝覆盖主要思路是遍历数组nums&#xff0c;每次取出的数字变量为num&#xff0c;同时设置一个下标ans在遍历过程中如果出现数字与需要移除的值不相同时&#xff0c;则进行拷贝覆盖nums[ans] n…