关于Java日志的体系,由于老四自己也没建立好这方面的比较清晰的体系,老四还会在单独写一篇文章详细的讲讲这方面的东西,主要包括Javaweb体系的日志如何建立,Log4J到底是怎么回事相关等。
1.[强制] 应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
1 2 3 |
import org.slf4j.Logger; import org.slf4j.LoggerFactory; private static final Logger logger = LoggerFactory.getLogger(Abc.class); |
老四附言:
关于门面模式,也叫作外观模式,具体可以参考一下老四写的《浅析设计模式第十二章之外观模式》。如果初接触日志体系的话可能会有点懵逼,我们先来了解一下SLF4J(Simple Logging Facade for Java)的概念:
Java的简单日志门面(SLF4J)作为各种日志框架(例如java.util.logging,logback,log4j)的简单外观或抽象,允许最终用户在部署时插入所需的日志框架。再结合外观模式,其实SLF4J不只是一个门面而不是一个具体的日志执行体系,他负责将你系统里面嵌入的各个日志体系整理好,在你调用的时候帮助你选择相应的日志来执行程序,这样一来无论你怎样切换你的日志体系都不会影响你业务场景的对日志的调用。如孤尽示例那样,我们可以把Log4j的配置文件放到resources中,类就会自动加载了。
2.[强制] 日志文件推荐至少保存15天,因为有些异常具备以”周”为频次发生的特点。
老四附言:
这个东西就跟自己的业务场景以及项目、运维管理的规定来就好了,时间长了,每个企业都有自己的异常规律和日志体系习惯的。
3.[强制] 应用中的扩展日志(如打点、临时监控、访问日志等)命名方式:
- appName_logType_logName.log。logType: 日志类型,推荐分类有stats/monitor/visit等;
- logName: 日志描述。这种命名的好处: 通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。
正例: mppserver应用中单独监控时区转换异常,如: mppserver_monitor_timeZoneConvert.log。
说明: 推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。
老四附言:
4.[强制] 对trace/debug/info级别的日志输出,必须使用条件输出形式或者使用占位符的方式。
说明: logger.debug(“Processing trade with id: ” + id + “and symbol: ” + symbol);如果日志级别是 warn,上述日志不会打印,但是会执行字符串拼接操作,如果symbol是对象,会执行toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。
正例(条件):
1 2 3 |
if (logger.isDebugEnabled()) { logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); } |
正例(占位符 ):
1 |
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol); |
老四附言:
—-关于java中占位符使用的一点点简单说明: 占位符是一个非常类似于在String的format()方法中的”%s”用法,它会在运行时被某个提供的实际字符串所替换。这样乐意降低代码中字符串连接次数,而且还节省了新建String对象,例如孤尽正例中那样的字符串连接。我们都知道String对象是不可修改的,况且他们还快乐的生活在一个String池子中,但是它们消耗堆内存并且多数时间不被拿来使用,这个就很气人了。所以我们可以通过使用SLF4J,在运行时延迟字符串的建立,只有需要的String对象的时候才被建立。或者使用条件语句。
—-Log4J定义了8个级别的log,优先级从高到低依次为:
- off: 关闭日志记录
- fatal: 严重的错误事件,会导致程序退出、终止
- error: 不影响程序继续执行的错误事件,同城打印逻辑错误或者异常信息。
- warn: 表名潜在的可能不太正确的错误信息,一般做提示日志。
- info: 粗粒度级别的表示程序的执行过程,一般打印程序的执行信息或者生产环境可以当做证据的重要信息提示。
- debug: 细粒度级别的表示程序的执行过程,一般打印程序的调试信息,一般用于开发过程中,生产环境不建议打印此级别的日志。
- trace: 比debug粒度更细,一般用于打印系统信息,如果是系统重构,开发的时候我们一般会把日志级别设置到trace级别。
- all: 打开所有日志记录。
Log4j建议只使用四个级别,优先级从高到低分别是error(默认)、warn、info、debug。
5.[强制] 避免重复打印日志,浪费磁盘空间,务必在log4j.xml中设置additivity=false。
正例:
1 |
<logger name="com.taobao.dubbo.config" additivity="false"> |
老四附言:
additivity可以翻译为多余性,具体的、更多的关于additivity属性的了解可以参考大神博客并发编程网相关的介绍-《Log4j 2 官方文档》多余性(Additivity)。
6.[强制] 异常信息应该包括两类信息: 案发现场信息和异常堆栈信息。如果不处理,那么通过关键字throws往上抛出。
正例:
1 |
logger.error(各类参数或者对象 toString + "_" + e.getMessage(), e); |
老四附言:
如果对象过大的话要考虑设计精简的bean的toString结构信息,保留重要字段。
7.[推荐] 谨慎地记录日志。生产环境禁止输出debug日志;有选择地输出info日志; 如果使用warn来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。
说明: 大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请思考: 这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
老四附言:
很有道理,老四刚接触企业级的项目时就是经常写调试日志,写着写着就提交了,然后就把服务器磁盘撑爆了,然后找了好久的问题才发现。亲身经历告诉你此条的建议级别不是推荐,而是强制!!!!
8.[推荐] 可以使用warn日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。如非必要,请不要在此场景打出error级别,避免频繁报警。
说明: 注意日志输出的级别,error级别只记录系统逻辑出错、异常或者重要的错误信息。
老四附言:
所谓的保留证据一定要在系统设计的时候尽量考虑出来,这样的话日志体系就会逐渐的丰富起来,就会知道哪里需要设计日志输出以便于将来的业务处理。一个字,积累经验。
我年纪还轻,阅历不深的时候,我父亲教导过我一句话,我至今还念念不忘。”每逢你想要批评任何人的时候,”他对我说,”你就记住,这个世界上所有的人,并不是个个都有过你拥有的那些优越条件。”
更博不易,如果觉得文章对你有帮助并且有能力的老铁烦请赞助盒烟钱,点我去赞助。抱拳。