一、Log4j2简介
log4j2是log4j1.x的升级版本,它提供很多Logback的特性,而且修复了Logback架构上的问题,具体请参考log4j2官网【Log4j – Apache Log4j 2】
二、Log4j2与slf4j
谈到log4j2如何使用,不得不提到slf4j。slf4j是一个门面框架,其实现了log4j、log4j2、logback等日志框架的整合。在实际的项目开发中,可能用到不止一个日志框架,因此slf4j提供了一套api接口,开发者只需要调用slf4j的api接口,而不用关心具体日志是由log4j2还是logback等日志框架实现的,slf4j与log4j2的关系如下:
三、slf4j+log4j2的使用(IDEA)
1、log4j2相关jar包
# 普通java项目
log4j-core-xx.jar
log4j-api-xx.jar
# 开发web项目额外依赖
log4j-web-xx.jar
# 适配slf4j日志门面框架只需依赖
log4j-slf4j-impl-xx.jar
# 适配commons-logging框架
log4j-jcl-xx.jar
# log4j1.2版本的升级,替换原有的log4j1.x的jar
log4j-1.2-api-xx.jar
2、构建工程
新建一个maven工程,添加log4j2适配slf4j的依赖包log4j-slf4j-impl
<properties>
<log4j.version>2.14.1</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
只需要引入这个一个依赖后会自动引入slf4j-api和log4j-core、log4j-api等相关jar包
新建一个类,这里创建为com.demo.log.LogDemo
package com.demo.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogDemo {
private static final Logger LOGGER = LoggerFactory.getLogger(LogDemo.class);
public static void main(String[] args) {
LOGGER.error("hello log4j2"); // 这里要用error,否则其他低等级的日志可能打印不出来
}
}
编译运行之后控制台会输出日志信息
22:56:55.809 [main] ERROR com.demo.log.LogDemo - hello log4j2
到这里,已经调用了slf4j的api接口,最终通过log4j2将日志信息打印到控制台。而之前也说过slf4j是门面框架,那么它是怎么适配日志框架的呢?
其实,slf4j是通过静态方法获取logger
private static final Logger LOGGER = LoggerFactory.getLogger(LogDemo.class);
我们跳转进入slf4j的源码可以发现LoggerFactory 类内调用getILoggerFactory()方法,而getILoggerFactory()方法调用StaticLoggerBinder.getSingleton().getLoggerFactory()获取日志
// LoggerFactory 类内调用getILoggerFactory()方法
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
// getILoggerFactory()方法调用StaticLoggerBinder.getSingleton().getLoggerFactory();
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == 0) {
Class var0 = LoggerFactory.class;
synchronized(LoggerFactory.class) {
if (INITIALIZATION_STATE == 0) {
INITIALIZATION_STATE = 1;
performInitialization();
}
}
}
switch(INITIALIZATION_STATE) {
case 1:
return SUBST_FACTORY;
case 2:
throw new IllegalStateException("org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
case 3:
// 通过StaticLoggerBinder进行适配
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case 4:
return NOP_FALLBACK_FACTORY;
default:
throw new IllegalStateException("Unreachable code");
}
}
进入StaticLoggerBinder可以发现new Log4jLoggerFactory();最终适配到log4j2框架
public final class StaticLoggerBinder implements LoggerFactoryBinder {
public static String REQUESTED_API_VERSION = "1.6";
private static final String LOGGER_FACTORY_CLASS_STR = Log4jLoggerFactory.class.getName();
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
private final ILoggerFactory loggerFactory = new Log4jLoggerFactory();
private StaticLoggerBinder() {
}
public static StaticLoggerBinder getSingleton() {
return SINGLETON;
}
public ILoggerFactory getLoggerFactory() {
return this.loggerFactory;
}
public String getLoggerFactoryClassStr() {
return LOGGER_FACTORY_CLASS_STR;
}
}
适配关系如下
四、遗留问题——关于log4j2的配置
22:56:55.809 [main] ERROR com.demo.log.LogDemo - hello log4j2
看到上面的日志输出,就有至少两个问题:
1、为什么日志输出到控制台,如何输出到文件中?
2、日志的格式为什么是这样的?
请看下一节更新
参考:log4j2官方文档