背景
打印日志的大坑。很多同事不打印堆栈信息直接这么写
log.error("exception occur! param1:{},param2:{}", param1, param2);
或
log.error("exception occur! param1:{}", e.getMessage());
或
log.error("exception occur! param1:{}", e.toString());
这真的是个大坑,没有堆栈信息有时候很难排查问题。
首先 getMessage()
是异常的信息,只是很简短的信息,比如 /by zero
这个就是除零异常 getMessage()
得到的。
其次,e.toString()
会让人以为返回了完整的堆栈信息(以字串形式),但其实不是,返回的跟 getMessage()
几乎是一样的。
toString() 的源码
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
return (message != null) ? (s + ": " + message) : s;
}
public String getLocalizedMessage() {
return getMessage();
}
public String getMessage() {
return detailMessage;
}
可以看到 getMessage()
和 e.toString()
其实区别要么是完全一样,要么是前面加了个类名和冒号和空格(s + ": ")
解决
一定要杜绝上面的写法。虽然lombok的 @Slf4j 提供的log,其打印日志的方法比较蛋疼,如果要打印 异常e就没法使用占位符 {},但是我们可以使用拼接的方式,参数多的时候用String.format 也是可以的
正例
log.error("exception occur! tenantId:" + tenantId, e);
// 或者
log.error(String.format("exception occur! tenantId:%s",tenantId), e);
注意,使用 String.format()
的时候,如果占位符 %s
的数量和填充进去的参数的数量不一致会发生运行时异常,这个比较坑。
补充细节:
一定要注意,如果参数数量不一致,会有提醒的。如下的黄底提醒
如果用log,参数不匹配,也会有黄底警告:
补充
打印日志用英文,比较节省,另外也不怕乱码。注意别用了中文逗号!
我觉得可能 log 缺少一个方法,比如
log.info("abc,param1:{},param2:{}", e, param1, param2);
由于缺少这个方法,所以如果想要打印 异常e 的堆栈就得放弃使用 {} 这种占位符