日志框架LOG4J2系列一——入门

一、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的关系如下:

日志框架LOG4J2系列一——入门_第1张图片

三、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


    2.14.1


    
        org.apache.logging.log4j
        log4j-slf4j-impl
        ${log4j.version}
    

只需要引入这个一个依赖后会自动引入slf4j-api和log4j-core、log4j-api等相关jar包

日志框架LOG4J2系列一——入门_第2张图片

日志框架LOG4J2系列一——入门_第3张图片

新建一个类,这里创建为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系列一——入门_第4张图片

四、遗留问题——关于log4j2的配置

22:56:55.809 [main] ERROR com.demo.log.LogDemo - hello log4j2

看到上面的日志输出,就有至少两个问题:

1、为什么日志输出到控制台,如何输出到文件中?

2、日志的格式为什么是这样的?

请看下一节更新

参考:log4j2官方文档

Log4j – Log4j 2 Web Applications

你可能感兴趣的:(日志框架,java,log4j2,slf4j,后端,maven)