log4j2动态指定log输出路径superdiamond+log4j2+spring

使用log4j2.xml进行logger输出配置时,在property标签中可以定义一些变量来配置log文件的基础路径。但是工程环境是相当复杂的,如开发环境、测试环境、灰度环境、以及正式环境,由于种种原因每个环境下的log home文件地址都有差别,这就非常难为负责发包的同事了,如果工程少还好,但是对于分布式微服务等系统,每次修改配置文件打包简直就是噩梦了。
至此,有些童鞋就有疑问了,上述问题解决方案完全可以通过maven war plugin来解决啊,编译时动态指定package.environment来使用不同的log4j2.xml配置文件。是的,这种方案是可以解决不同环境不同配置文件的问题,但是环境是相当复杂的,比如我们线上服务器log文件要输出至共享存储挂载点,顾名思义多台服务器同一服务输出的日志文件在同一个存储区内。我们上面通过maven war plugin打包得到的log4j2.xml配置文件在部署至每台服务器时,其日志输出路径是一致的。这样多台服务器输出日志至同一文件是会有问题的,所以maven war plugin并不能解决我们的终极问题。

上面我们说过log4j2.xml是可以配置property标签的,如果这些变量的值本身就是动态的,不就能解决问题了吗。非常感谢log4j2.xml支持jvm、系统环境变量的使用。改造的基本思路如下图:


superdiamond配置中心,负责配置每个服务的loghome路径配置,其中包括一部分动态参数区,比如:/data/{ip}/pear/v1/cache-server-default
服务自身需在spring容器加载完成后reload log4j2配置,这主要是因为superdiamond依赖于spring容器,spring placeholder 需要将diamond配置作为properties属性。
1. 实现ApplicationListener接口onApplicationEvent方法,并在spring容器加载时加载该bean;
2. 获取diamond中loghome的配置路径,并解析其中的{ip}参数,将最终生成的日志路径reallogpath设置进jvm变量中;
3. 重载log4j2.xml配置。

CustomerLog4j2Initializer 实现ApplicationListener接口代码如下:
@Override
public void onApplicationEvent(ApplicationEvent event) {
		LOGGER.info("CustomerLog4j2Initializer onApplicationEvent");
		// 容器启动完成之后load  
            if (event instanceof ContextRefreshedEvent) {  
            if (((ContextRefreshedEvent) event).getApplicationContext().getParent() == null) {
            	LOGGER.info("CustomerLog4j2Initializer , reloading log4j2");
            	
                try {
					reloadLog4j2();
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
                
                LOGGER.info("CustomerLog4j2Initializer , reloaded log4j2 successful");
            }  
        }
}
使用diamond获取配置,并动态解析路径并存储jvm变量,完成log42配置重载代码如下:
private PropertiesConfiguration prop = PropertiesConfigurationFactoryBean.getPropertiesConfiguration();
	
	/**
	 * 重新加载log4j2配置文件
	 * @throws FileNotFoundException
	 * @return void
	 */
	private void reloadLog4j2() throws FileNotFoundException{
		LOGGER.info("reloadLog4j2 , load log4j2 properties");
		
		String realLogPath = "";	//最终日志存放的真实路径
		
		//获取diamond配置中心中配置的日志路径
		realLogPath = prop.getString("logpath",DEFAULT_LOGPATH);
		
		//解析日志存放路径中的变量,替换ip
		realLogPath = realLogPath.replace("{ip}", packageIp());
		
		//获取log4j配置文件路径,如无配置则默认加载classpath:log4j2.xml
		String location = prop.getString("log4j2Filepath",DEFAULT_LOG4J2_FILEPATH);
		
		LOGGER.info("reloadLog4j2 , location:"+location+",realLogPath:"+realLogPath);
		
		//将日志存放路径设置至jvm变量中,供log4j配置文件中加载
		System.setProperty("reallogpath", realLogPath);
		
		//重新加载log4j2配置文件
		String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
		if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) {
			LOGGER.info("reloadLog4j2 , LoggerContext.reconfigure--start");
			
		    File file = ResourceUtils.getFile(resolvedLocation);
			LoggerContext context =(LoggerContext)LogManager.getContext(false);  
			context.setConfigLocation(file.toURI());
			LOGGER.info("reloadLog4j2 , LoggerContext.setConfigLocation:"+file.toURI());
			//重新初始化Log4j2的配置上下文  
			context.reconfigure();  
			
			LOGGER.info("reloadLog4j2 , LoggerContext.reconfigure--finished");
		}
		else {
			//暂不支持非xml配置
		}
		
	}
log4j2.xml配置文件配置如下:
	<properties>
		<!-- <property name="LOG_HOME">/data/pear/v1/third-server</property> -->
		<property name="LOG_HOME">${sys:reallogpath}</property>
		<!-- 日志备份目录 -->
		<property name="STATIC">${LOG_HOME}/static</property>
		<property name="ERROR">${LOG_HOME}/ERROR</property>
		<property name="INFO">${LOG_HOME}/INFO</property>
		<property name="MONITORING">${LOG_HOME}/monitoring</property>
	</properties>
问题:
1. log4j2.xml默认在classpath下会默认加载配置,此时使用了${sys:reallogpath}变量会导致log4j2装载错误,出现异常信息。
解决方法:将log4j2.xml文件放至其它目录,如classpath:log/log4j2.xml,在重载log4j2配置时设置configLocation至此文件即可。
2. 此实例仅适用于log4j2,log4j装载过程有区别。
3. log4j2.xml配置文件中使用${sys:reallogpath}变量,也可以通过jvm启动参数来指定变量的值,此方式改造更简单,但缺点显而易见。
4. 如何实现diamond配置修改loghome配置后动态重载log4j2.
解决思路:实现diamond接口ConfigurationListener的configurationChanged方法,在configurationChanged方法中监听loghome配置项的修改,发生修改则重载log4j2。


  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

li317059250

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值