原标题:技术文 | 日志框架使用技巧分享
日志的意义
对于一个应用程序来说日志记录是具有重要意义的。
日志通常用于线上问题追踪,协助定位业务问题或程序问题,以及基于日志的业务逻辑统计分析等。
java领域存在多种日志框架,目前常用的日志框架包括Log4j1,Log4j2,Commons Logging,Logback等。
slf4j、log4j、logback、log4j2的区别与联系
slf4j
Simple Logging Facade for Java,缩写Slf4j。这是一套日志的接口。本身不包含日志的实现。slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback等)。
log4j
Apache Log4j是一个基于Java的日志记录框架。现在是Apache软件基金会的一个项目。Log4j是几种常见Java日志框架之一,出现年代较早。
logback
logback是由log4j创始人设计的又一个开源日志组件。在性能和架构上较log4j有着很大程度上的改进,并且logback是SpringBoot框架(1.x和2.x)默认集成的日志实现框架。
log4j2
Apache Log4j2是对log4j的升级,它比其前身Log4j1提供了重要的改进。并提供了Logback中可用的许多改进,同时修复了Logback体系结构中的一些固有问题。可以认为log4j2是logback的加强版。
log4j2的配置文件介绍
log4j2的配置文件介绍
Appender
appender是一个管道,负责将日志事件写入到对应的目标载体(保存位置),可以通过配置不同的appender,将日志输出到控制台、文件、数据库、邮件服务器等等。
Logger
logger是程序中的日志收集器,用于收集程序中的日志,简单说logger就是一个路由器,指定类、包中的日志信息流向哪个管道,以及控制他们的流量(日志级别)。
通常来说,一个logger可以对应多个appender,来达到将日志输出到多个目标的目的。
实战应用技巧
01
logger在类中如何定义
使用slf4j的接口获取logger
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
protected Logger logger =
LoggerFactory.getLogger(Const.LOGGER_NAME_OUTPUT);
02
logger的名字与.class有什么区别
常见的logger定义中,getLogger方法的参数通常传入的是xxx.class,
这里的参数也可以传入字符串,
默认的xxx.class相当于xxx.class.getName,实际上相当于以本类的名字作为目标logger的名字。
推荐大家使用字符串常量来设置Logger的名字。
03
logger的访问修饰符
ogger的常见访问修饰符是protected和private,访问修饰符决定了logger可以在什么样的范围内使用。
推荐protected,便于继承,且不影响封装性。
04
日志配置文件中logger与appender的对应关系
业务代码的java类中定义的getLogger(“xxx”),实际上标定了logger的名字叫什么。但是仅仅定义了名字还不够,我们必须将xxx这个logger名字与log4j2配置文件中的Logger定义的名字对应。
完成了这一步操作以后,就达成了代码中的logger标定,与配置文件中的logger定义的连结,再加上Logger与appender的对应关系,实际上就做到了,将指定的日志输出的特定位置的闭环。
05
如何按照模块将日志独立成多个文件
在完成了第4步的操作的基础上,为每个特定模块指定对应的输出文件位置就可以达到我们的目标。
java配置
logger配置
appender配置
06
关于additivity属性的作用
logger配置中可以指定additivity属性,这个属性为true时,输出的日志不仅会在定义的appender中输出,同时将会在console输出一份。
下图中的两个配置是等效的。
07
如何设置定时/定量压缩日志
首先在filePattern中指定压缩日志的路径,并在文件命中使用%d{yyyy-MM-dd}的日期配置。
然后在policies(策略)中指定分割间隔。
TimeBasedTriggeringPolicy中interval代表间隔,它的间隔是%d{yyyy-MM-dd}的最小粒度。
如果想按照小时分割,则可以指定日期格式为%d{yyyy-MM-dd-HH}。
08
日志极限大小的计算
SizeBasedTriggeringPolicy指定了单个日志文件最大的容量。
DefaultRolloverStrategy指定了最多可以生成多少个文件,则最大日志文件大小 = 配置的模块数 * 单个文件最大容量 * 最大文件个数。
这个数量对于运维时具有现实意义,可以避免磁盘空间被占满的问题。
09
日志代码的写入原则
日志的级别区分:
TRACE:非关键信息trace。例如:输出某个变量的值
DEBUG:代码关键中间状态或计算结果/代码关键分支标识debug。例如:过账过程中,数据校验代码验证通过
INFO:业务正常执行完毕/业务阶段性执行完毕info。例如:单据保存执行完毕
WARN:业务异常warn/业务错误error。例如:登录失败/提交过账的单据数据不合业务要求等
ERROR:系统错误error/程序错误error/异常或非法数据error
除了上述情况,在实际代码编写过程中,要求应该对所有代码退出执行的出口输出一条级别合适的日志,用以跟踪的代码执行流程。包括程序正常执行完毕时,出现代码异常或业务异常退出时等。
10
日志输出的技巧
1. 日志可以适当的输出部分运行期间的参数,用来在大量日志中快速区分和定位目标操作。例如出库业务中输出的日志可以将运行期的出库单号作为标识性的日志变量参数,与日志一同输出。
2. 尽量避免空指针,可能出现空指针的地方需要进行提前判断。
3. 日志中拼接字符串的方法,尽量不用+拼接,推荐使用{}占位符。
代码举例
4. 关于循环,使用判断后再循环
代码举例:
核心思想是减少日志输出带来的系统性能消耗。
Log4j2的其他内容
结合ELK框架使用,使日志信息可视化,提供决策支持
ELK框架是ElasticSearch + Logstash + Kibana的缩写。
可以用来实现分布式环境下的日志收集、存储、高效检索、日志统计、日志可视化展示等。
其基本架构可以简化成下面的情况。
当我们按照实战技巧中的操作流程来规范日志输出,每一条日志就变得具有实际意义。
再结合ELK框架的使用,可以帮助我们分析很多场景,继而根据日志来为我们提供决策上的支持。
例如,可以结合tomcat或Nginx的访问日志来判断用户在实际使用时,哪些模块或功能使用频度较高,哪些功能容易出现错误提示等等。
配置文件允许的文件格式
允许的配置文件格式为:xml/json/yaml/properties (推荐)
也可以通过编程方式,创建ConfigurationFactory和配置实现。(不推荐)
配置文件加载顺序
Log4j能够在初始化期间自动配置。当Log4j启动时,它将定位所有ConfigurationFactory插件,并按从高到低的加权顺序排列它们。Log4j包含四个ConfigurationFactory实现:一个用于JSON,一个用于YAML,一个用于properties,还有一个用于XML。
Log4j将以下列顺序加载配置文件:
Log4j将检查“log4j.configurationFile”系统属性(系统环境变量设置)。如果已设置,则将尝试使用匹配文件扩展名的ConfigurationFactory加载配置。
如果没有设置系统属性, 则properties ConfigurationFactory将试图在classpath中查找log4j2-test.properties文件作为配置文件。
如果没有找到这样的文件, YAML ConfigurationFactory将试图在classpath中查找log4j2-test.yaml或log4j2-test.yml文件作为配置文件。
如果没有找到这样的文件, JSON ConfigurationFactory将试图在classpath中查找log4j2-test.json或log4j2-test.jsn文件作为配置文件。
如果没有找到这样的文件, XML ConfigurationFactory将在classpath中查找log4j2-test.xml。
如果test文件无法定位, properties ConfigurationFactory将试图在classpath中查找log4j2.properties文件作为配置文件。
如果无法找到properties文件, YAML ConfigurationFactory将在classpath中查找log4j2.yaml或log4j2.yml文件作为配置文件。
如果无法找到YAML文件, JSON ConfigurationFactory将在classpath中查找log4j2.json或log4j2.jsn文件。
如果JSON文件无法找到, XML ConfigurationFactory将尝试在classpath上查找log4j2.xml。
如果无法找到配置文件,则使用 DefaultConfiguration。这将导致日志输出到控制台。
总结
在写日志的时候,需要谨记日志会充斥在大量的其他日志中,并且会有多线程导致的日志输出不连续的情况。
输出的日志需要服务于我们自身。这就要求每一条日志要有一些特异性,能够区别于其他日志,并能够迅速从大量数据中检索得到所需要的日志。
同时要求日志本身能够有效反映出程序的运行情况,对排查错误和维护程序起到作用。
参考文献
Log4j2官方网站:
http://logging.apache.org/log4j/2.x/manual/index.html
关于ELK参考官方网站:
https://www.elastic.co/cn/products/elasticsearch
作者:李斌
校对&编辑:elaine
责任编辑: