前言
最近遇到日志打印异常的问题,设置好的日志输出级别不生效,在本地直接在代码里写个Main函数测试没问题,上Linux出现日志输出等级不生效,我设置的error等级,却把info日志给输出了。项目使用logback日志输出框架,最后发现原来是日志冲突,项目包含log4j+slf4j的日志框架,故需要将相关jar包排除即可。 提示:以下是本篇文章正文内容引用
https://www.cnblogs.com/FlyAway2013/p/10691936.html
https://zhuanlan.zhihu.com/p/101104008
https://www.jianshu.com/u/52c6d746bd8e
http://www.slf4j.org/manual.html (slf4j官网)
一、日志的作用
日志文件用来记录系统操作事件,主要用来快速定位问题的根源、追踪程序执行的过程、追踪数据的变化、采集运行环境数据。日志主要分为事件日志和消息日志。
程序上线后,一旦发生异常,首先要弄清楚当时发生了什么错误。进行了什么操作,环境是否受影响,数据产生生命变化,是不是可重复发生等,然后再进一步的确定大致是哪个方面的问题。确定是程序的问题后再去重现、研究、提出解决方案。这时,日志就给我们提供了第一手的资料。
日志内容需包含哪些:打印日志的时间戳、日志是哪个类记录的、日志事件的简要说明、事件生产者唯一标识、日志输出级别。
二、日志框架
为了兼容系统中或者依赖的jar包中其他日志框架,最好的方法是使用桥接将其他日志框架桥接到slf4j上,然后使用具体的日志输出框架。如:log4j桥接到slf4j,然后使用logback日志框架输出日志。
1. 直接使用各日志系统
1.1 log4j
maven依赖:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
配置文件:log4j.properties
代码中使用:
private static final org.apache.log4j.Logger logger = org.apache.log4j.LogManager.getLogger(loggerName.class);
1.2 commons-logging ,jcl
maven依赖:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
配置文件:commons-logging.properties
代码中使用:
private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog(loggerName.class);
1.3 log4j2
maven依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
配置文件: log4j2.xml 或 log4j.xml
代码中使用:
private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(loggerName.class);
1.4 logback
maven依赖:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
配置文件: logback.xml
代码中使用:只能使用slf4j的api。
private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(loggerName.class);
1.5 jdk-logging,jul
jdk自带,不用引入jar包。
配置文件: logging.properties
代码中使用:
private static final java.util.logging.Logger LOGGER = java.util.logging.LogManager.getLogManager().getLogger(loggerName.class.getName());
2 使用slf4j日志接口框架
2.1 slf4j-api 的NOP实现
NOP, 也就是No Operation,也就是不做任何操作。不需要引入任何其他jar,配置文件也是无。
2.2 slf4j-api 的logback实现
2.3 slf4j-api 的simple实现
maven依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.12</version>
</dependency>
slf4j-simple 依赖了 slf4j-api。slf4j-simple 通常把日志直接打印到 控制台。
配置:simplelogger.properties 或者通过D系统参数。
2.4 slf4j-api 的JUL实现
maven依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
</dependency
2.5 slf4j-api 的log4j 实现
maven依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
2.6 slf4j-api 的log4j2 实现
maven依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.8.2</version>
</dependency>
log4j-slf4j-impl 依赖了slf4j-api 和 log4j-api, 但是并没有依赖 log4j-core , 因此, 我们需要手动引入 它 。
2.7 slf4j-api 的JCL实现
3 桥接到slf4j
3.1 log4j桥接到slf4j
maven依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.29</version>
</dependency>
3.2 log4j2桥接到slf4j
maven依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.1</version>
</dependency>
log4j-to-slf4j没有log4j-core,如果用到了,需将其导入。
3.3 JCL桥接到slf4j,commons-logging
maven依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
3.4 JUL桥接到slf4j
maven依赖:
dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
代码中需要先执行下面的:
static{
SLF4JBridgeHandler.install();
}
4 其他框架桥接到slf4j,然后使用某个日志框架
4.1 logback
maven依赖:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<!-- log4j 桥接包,slf4j官方实现,另有log4j官方实现,二选一即可 log4j-to-slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
4.2 log4j2
maven依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.12.1</version>
</dependency>
<!-- 以下是桥接包,使用了log4j作为底层实现,
不能再桥接log4j,否则会出现无限递归的情况
(具体原因请关注后续文章) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency><dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
代码中使用:
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(loggername.class);
logger.trace("A TRACE Message");
logger.debug("A DEBUG Message");
logger.info("An INFO Message");
logger.warn("A WARN Message");
logger.error("An ERROR Message");
注意
桥接到slf4j,使用logback输出时,需要将其他的包排掉,但是记得不要排多了,排的是日志框架,日志接口如log4j-core,log4j-api按需保留