SpringBoot集成Log2j4指定外部配置文件&源码解读

文章探讨了SpringBoot程序如何在启动时加载Log4j2配置文件,以及在权限受限的环境下,为何既加载了jar包内的配置又尝试使用外部配置。作者揭示了初次加载和配置重载的机制,并建议使用-Dlog4j.configurationFile来指定外部配置以避免权限问题。
摘要由CSDN通过智能技术生成

目录

一、背景

二、问题排查

三、SpringBoot下Log4j2加载配置文件优先级。

1.初次加载

2.配置重加载

3.结论

四、SpringBoot启动加载log4j2.xml过程源码解读

1.首次加载

2.springboot重加载


一、背景

程序读取外部log4j2.xml配置文件方式为启动命令添加了--logging.config=/path/log4j2.xml,因系统安全整改,将/var/log/目录改为了700,程序使用非root启动时log4j2报错无法在/var/log目录下创建日志文件。经排查发现jar包的classpath目录下指定的日志文件位置在/var/log下,但是外部配置文件指定的日志文件在该系统用户下具有创建文件权限。按之前的理解通过logging.config指定了外部配置文件后jar包内的配置文件会失效,那为什么程序还是去读取了jar包内的配置文件导致在没有权限的目录下尝试创建日志文件呢。

二、问题排查

修改jar包内的配置文件,将日志输出路径改为该系统用户可以创建文件的/opt/log目录,修改外部配置文件,将日志输出路径改为该系统用户可以创建文件的/opt/log2目录。启动程序后发现,在/opt/log以及/opt/log2目录下都生成了日志文件,但是/opt/log目录下的日志文件并不会产生日志,只有/opt/log2目录下的日志文件(也就是外部配置文件指定的目录)会产生日志,且外部配置文件可以控制程序的日志级别。带着这个问题查看springboot加载log4j2并读取log4j2.xml过程的源码。

三、SpringBoot下Log4j2加载配置文件优先级。

1.初次加载

springboot程序启动的类初始化阶段会触发log4j2初次加载配置文件,即不受springboot配置的影响,一定会加载的,其加载顺序如下。(这里只说明在不同目录下加载log4j2.xml配置文件的顺序,不说明其他后缀的配置文件加载顺序)

-Dlog4j.configurationFile=/path/log4j2.xml  >  jar包内classpath下log4j2.xml

参数说明:

-D:添加在启动命令的虚拟机参数位置,代表设置虚拟机环境变量。必须使用该方式。

特别说明一下在背景中提到的--logging.config参数,它是配置在java启动命令的程序参数位置,也就是会通过main方法传递过来的,一般springboot的一些配置是通过这种形式传递的,例如:--spring.config.location配置指定springboot的配置文件位置,那么为什么不能通过--log4j.configuration的方式配置log4j2的配置文件位置呢,因为他的加载是在类的初始化阶段进行的,此时spring容器还尚未加载完成,且log4j源码中也体现了是从jvm环境变量中读取的该配置项。

详细的java启动参数的说明可以参考一下文章:

https://www.cnblogs.com/haycheng/p/12781261.html

2.配置重加载

log4j2的配置文件重加载发生在springboot的监听器中,它触发log4j2重加载配置文件,是加载logging.config配置的。

3.结论

通过以上两点就解释了问题排查中讲到的程序即加载了jar包内的log4j2.xml也加载了--logging.config指定的log4j2.xml,那么我们在springboot中使用log4j2且想指定外部配置文件时最好使用-Dlog4j.configurationFile的这种方式,让程序在初次加载时就指定外部配置文件,这样程序就不会加载jar包内的配置文件并创建对应的日志文件了(虽然也不往其中输出日志,但目录和文件毕竟会创建,当程序权限不足时就会报错)。

四、SpringBoot启动加载log4j2.xml过程源码解读

1.首次加载

SpringApplication类中定义了静态的Log对象,因此在加载SpringApplication类时会触发Log类的加载及初始化操作,而不是等到执行run方法,这也就是为什么说log4j2首次加载配置文件时spring容器还未加载完成。

springboot使用jcl(Jakarta Commons Logging)日志门面,其中LogFactory为jcl的包下的类,其通过spring-jcl引入。

进入LogAdapter#createLog,createLog为Function类型,查看何时给其赋值。

 在LogAdapter的静态代码块中通过几个Present判断为createLog复制,可以看出这里为选择一种具体的日志实现的适配器。

 查看这几个Present如何来的。通过查看不同日志类型的类是否可以被加载来判断程序使用哪种日志框架,该案例中选择的是log4j 2.x + slf4j的实现。

进入createLog定义的Function,即Log4jAdapter::createLog,Log4jAdapter为LogAdapter的内部类。

调用Log4jLog类的构造方法,Log4jLog为LogAdapter的内部类。其中LogManager为log4j-api包内的类,其通过spi机制找到org.apache.logging.log4j.core.impl.Log4jProvider

 

2.springboot重加载

  • 29
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是Spring Boot集成log4j2输出日志文件的步骤: 1. 在pom.xml文件中添加log4j2的依赖 ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> ``` 2. 在src/main/resources目录下创建log4j2.xml文件,并配置输出文件的路径、格式等信息。以下是一个示例配置文件: ``` <?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <RollingFile name="RollingFile" fileName="logs/log4j2.log" filePattern="logs/log4j2-%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <DefaultRolloverStrategy max="10"/> </RollingFile> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="RollingFile"/> </Root> </Loggers> </Configuration> ``` 3. 在Spring Boot的启动类中添加注解@EnableAsync和@ImportResource,开启异步调用和导入log4j2.xml配置文件。 ``` @SpringBootApplication @EnableAsync @ImportResource(locations = {"classpath:log4j2.xml"}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 4. 在需要输出日志的类中,使用log4j2的日志记录器进行日志输出。以下是一个示例: ``` import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class SampleClass { private static final Logger logger = LogManager.getLogger(SampleClass.class); public void doSomething() { logger.info("This is a sample log message."); } } ``` 这样就完成了Spring Boot集成log4j2输出日志文件的配置。希望对你有帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值