我们抛开业务逻辑,仅仅从日志的角度来考虑日志问题。集合最近对项目的日志优化,总结以下几点最佳实践。
Slf4j + logback 打印日志的最佳实践
1,日志级别使用不当
2,谨慎使用e.printStackTrace()
3,使用占位符,而不是字符串拼接
4,尽量打印更少的日志
5,尽量不要在for循环中log日志
下面结合代码,来具体讲解。
Slf4j有四个级别的log level可供选择,级别从上到下由低到高,优先级高的将被打印出来。
Debug:简单来说,对程序调试有利的信息都可以debug输出。
info:对用户有用的信息,比如最常见的打印接口入参和返参。
warn:可能会导致错误的信息,比如某个对象可能为null的场景判断。
error:顾名思义,发生错误的地方,最常见的catch代码块中的日志。
这里以error日志为例,举一个例子,在合适的场合打印合适的日志,是我们日志界的规范。
// ---------------- 1,日志级别使用不当 ----------------
try{
String str = null;
str.length();
} catch(Exception e) {
// 这里不推荐打印info日志
logger.info("注意,这里不要打印info日志,", e);
// 正确的做法
logger.error("注意,这里不要打印error日志,", e);
}
e.printStackTrace()打印的是异常堆栈信息,会占用内存空间。正确的姿势是把日志打印到文件中。
// ---------------- 2,谨慎使用e.printStackTrace() ----------------
try{
String str = null;
str.length();
} catch(Exception e) {
// 谨慎使用e.printStackTrace()
e.printStackTrace();
}
Slf4j打印日志使用了占位符,避免了字符串拼接操作。字符串拼接最大的弊端,就是需要new新的字符串对象,增加了内存的开销。
// ---------------- 3,使用占位符,而不是字符串拼接 ----------------
String str = null;
String str2 = "五千年文明史";
try{
str.length();
} catch(Exception e) {
// 不推荐的做法,尤其是拼接的 字符串较多时,对性能有影响
logger.error("str:" + str + ", str2:" + str2, e);
// 正确的做法
logger.error("str:{}, str2:{}", str, str2, e);
}
日志打印,要坚持一个原则:尽量打印更少的日志。
因为磁盘空间也是有限的,如果磁盘空间不足,会直接导致应用程序的崩溃。
好的做法是:不要打印无用的日志,不要重复打印日志,尽量不要在for循环中打印日志。
// ---------------- 4,尽量打印更少的日志 ----------------
String str1 = null;
String str2 = null;
String str3 = null;
try{
// 错误的做法
logger.info("str1:{}", str1);
logger.info("str1:{}", str1);
logger.info("str1:{}", str1);
// 正确的做法
logger.info("str1:{}, str2:{}, str3:{}", str1, str2, str3);
str.length();
} catch(Exception e) {
logger.error("str:{}", str, e);
}
一般来说,for循环中的log日志,都可以提到for循环外面来打印。因为for循环的对象
是集合,而集合都可以转化成对应的json字符串。
特殊情况,必须要在for循环中打印的,需要评估是否有必要,已经这个日志的量级,看
是否太耗内存。
// ---------------- 5,尽量不要在for循环中log日志 ----------------
try{
List list = new ArrayList<>();
list.add("唐朝");
list.add("宋朝");
list.add("董仲舒");
// 不推荐的做法
for (String str : list) {
logger.info("str:{}", str);
// 业务逻辑代码
}
// 推荐的做法
logger.info("list to json:{}", JSON.toJSON(list).toString());
for (String str : list) {
// 业务逻辑代码
}
} catch(Exception e) {
logger.error("{} error", this.getClass().getSimpleName(), e);
}
如果是其他集合,同理,也可以转化成json字符串,这里不再赘述。