SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,而是通过Facade Pattern提供一些Java logging API,实际上,SLF4J所提供的核心API是一些接口以及一个LoggerFactory的工厂类。在使用SLF4J的时候,不需要在代码中或配置文件中指定你打算使用那个具体的日志系统。应该如下面代码这样写,好处是如果后面想要换具体的日志框架是,记日志代码的地方不用变动。
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;private static Logger logger = LogManager.getLogger(Xxx.class);
log4j2、logback都只是slf4j的实现框架。
二、log4j2的具体使用集成log4j2日志框架需要注意的问题:
直接引入log4j2的依赖的话,会报如下的错。
Caused by: org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4jat org.apache.logging.slf4j.Log4jLoggerFactory.validateContext(Log4jLoggerFactory.java:49)at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:39)at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:30)at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:54)at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:30)at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:363)at org.apache.commons.logging.LogAdapter$Slf4jAdapter.createLocationAwareLog(LogAdapter.java:130)at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:91)at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67)at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59)at org.springframework.boot.SpringApplication.
在创建Spring Boot工程时,我们引入了spring-boot-starter,其中包含了spring-boot-starter-logging,该依赖内容就是Spring Boot默认的日志框架Logback,所以我们在引入log4j2之前,需要先排除该包的依赖,再引入log4j2的依赖。
log4j2的配置文件示例如下:
<?xml version="1.0" encoding="UTF-8"?>
application.yml中引入该配置文件, classpath相当于resources文件夹:
logging: config: classpath:log/log4j2.xml #配置日志文件路径 file: name: demo #设置日志的文件名称
其中重要的配置片段:
也就是日志存储的路径和日志文件名称不能写死了,需要根据微服务不同的工程来动态的指定。
如果想要读取微服务工程的spring.application.name作为logPath(日志存储的路径),logging.file.name作为logName(日志文件的名称)。
问题是如何在加载application.yml文件后,在加载日志配置文件log4j2.xml之前读取并设置进去。
使用MDC存储上面说的k-v键值对,配合监听sprign的事件,微服务工程启动后,加载好application.yml时,会自动广播事件。
MDC:
public class MDC { static MDCAdapter mdcAdapter;
MDCAdapter实现类:
import org.slf4j.MDC;import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;import org.springframework.context.ApplicationEvent;import org.springframework.context.event.GenericApplicationListener;import org.springframework.core.Ordered;import org.springframework.core.ResolvableType;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.MutablePropertySources;import org.springframework.core.env.PropertySource;import org.springframework.util.StringUtils;import java.util.HashMap;import java.util.Map;public class LogMDCListener implements GenericApplicationListener { private static final String APPLICATION_CONFIG_NAME = "configurationProperties"; private static final String LOG_NAME = "logging.file.name"; private static final String LOG_PATH = "spring.application.name"; private static final Map
LogMDCListener配置给spring的事件监听:
resources/meta-INF/spring.factories配置如下。
org.springframework.context.ApplicationListener=com.ken.common.web.log.LogMDCListener
给LogMDCListener 配置合适的order:
LoggingApplicationListener部分代码如下。
public class LoggingApplicationListener implements GenericApplicationListener { public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20; private int order = DEFAULT_ORDER; @Overridepublic int getOrder() {return this.order;}
LoggingApplicationListener的order为Ordered.HIGHEST_PRECEDENCE + 20,所以想要LogMDCListener在LoggingApplicationListener之前执行,就得配置合适的order,order值越小,优先级越高,所以配置Ordered.HIGHEST_PRECEDENCE + 19。
参考的工程:https://gitee.com/wlkken/ken_framework_pom
参考课程:https://www.bilibili.com/video/BV1hQ4y1z78B?p=20