最近提的 PR 都有关于 Log 的 comment,不能忍,以下内容总结整理自明佳的 Comment 和网络资料,只是为了以后提 PR 之前过来扫一眼,尽量避免 Log 上的疏忽,不一定适用于所有人。
在程序中的适当位置打 Log 的重要性就不用多说了,很多人应该都体会过线上有 Bug 却由于没有打 log 而不好 troubleshooting 的经历。
相关文档(康桑哈密达)
SLF4J VS Log4J
有很多关于打 Log 的第三方库,也没有多研究过,接触过的就是 SLF4J 和 Log4J 了,不过墙裂建议用 SLF4J,使用占位符 {} 真的比加号拼接字符串可读性提高N倍啊!!!
感受一下<( ̄︶ ̄)>
// SLF4J, good
log.error("Invest loan failed, loan Id: {}, error: {}", loanId, errorMsg);
// Log4J, bad
log.error("Invest loan failed, loan Id:" + loanId + " error: " + errorMsg);
当然,SLF4J 还有其他的优点,比如不用字符串拼接,节省了创建 String 对象所耗费的资源之类的。不过我最看重的就是可读性高了。
Logging Level
- ERROR - 记录一些比较严重的错误,比如一些严重异常,数据库链接不可用等等
- WARN - 记录一些系统可以容忍的异常,或者是一些警示信息。比如:”Current data unavailable, using cached values”。
- INFO - 记录一些比较重要的操作,能反映程序运行状态的。比如:”[Who] booked ticket from [Where] to [Where]”
- DEBUG - 一些帮助调试的信息
- TRACE - 嗯,这个级别俺也没用过。
Pay attention
Log 信息首字母大写
这点完全是为了看上去舒服,至于到底需不需要大写,见仁见智吧~,不过我还是要注意一下,要大写。// good log.error("Invest loan failed, loan Id: {}, error: {}", loanId, errorMsg); // bad log.error("invest loan failed, loan Id: {}, error: {}", loanId, errorMsg);避免 Log 中的 NullPointerException
如果像下面这样记 Log,要注意确保 loan 不会为null, 不然打 Log 时抛个 NPE,想想就蛋疼。log.info("Invest loan : {}", loan.getId());Log 的信息简洁有用
Log 的内容一定要是有用的,能反映出程序的运行状态,能帮助定位错误。// good log.info("Invest loan with id:{}", loanId); // bad log.info("Invest loan");记录某些方法的入参和出参
记录方法的入参和出参,也可以帮助我们定位问题。特别是调用提供接口给其他系统调用的时候,记录入参可以帮助分辨到底是谁的锅🌚。public String printDocument(Document doc, Mode mode) { log.debug("Entering printDocument(doc={}, mode={})", doc, mode); String id = //Lengthy printing operation log.debug("Leaving printDocument(): {}", id); return id; }
合适的记录异常
大家都知道要在记录程序运行中抛出的异常,但有的时候方式可能是不对的。try{ throw new NullPointerException("Just for test"); } catch (Exception e){ log.error(e); //A log.error(e, e); //B log.error("" + e); //C log.error(e.toString()); //D log.error(e.getMessage()); //E log.error(null, e); //F log.error("", e); //G log.error("{}", e); //H log.error("{}", e.getMessage()); //I log.error("Error reading configuration file: " + e); //J log.error("Error reading configuration file: " + e.getMessage()); //K log.error("Error reading configuration file", e); //L }在上面 12 种打印异常的方式中,只有 G 和 L是正确的。A 和 B 在使用 SLF4J 时会编译不通过, 其他的几种要么不会打印异常堆栈,要么会打印出不正确的信息。比如,E 的方式只会打印”Just for test”的信息,而不会打印异常类型和异常堆栈。在 SLF4J 中,第一个参数是文本信息,简单描述一下异常;第二个参数要传异常本身,而不是
e.getMessage()或e.toString(),这样才能打印出异常堆栈,方便定位问题。
希望可以消灭和 Log 有关的 Comment。
欢迎指正错误,欢迎一起讨论~(≧▽≦)/~。