springboot动态添加log4j2的Appender

使用场景:

一般log4j2的配置都是通过log4j2.xml配置来实现相关的日志操作。
假如项目上使用的的公司封装好的log4j2框架,里面的日志配置都是固定的,如果自己想扩展要么就是升级日志框架(不方便),或者自己重写覆盖log4j2.xml(后续如果升级自己也需要跟着改动)。这里不改动日志框架的前提下,动态添加自己的想要的appender。


代码示例

1.添加appender代码如下,借助springboot的启动事件操作
这里以日志输出到文件添加一个Appender为例

package com.zhoule.demoactuator.log;

import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.appender.rolling.*;
import org.apache.logging.log4j.core.appender.rolling.action.Action;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.filter.ThresholdFilter;
import org.apache.logging.log4j.core.util.Builder;
import org.apache.logging.log4j.core.util.ReflectionUtil;
import org.apache.logging.log4j.core.util.TypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;

import java.io.File;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * ApplicationEnvironmentPreparedEvent 表示环境准备好事件
 */
public class RollingFileAppenderPlugin implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    //appender名称
    private static final String APPENDER_NAME = "rollingFile";

    //log4j2.xml中已经定义好的一个appender
    private static final String ROOT_APPENDER_NAME = "consoleRoot";

    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        generateAppender(event.getEnvironment());
    }

    /**
     * 生成appender
     */
    private void generateAppender(ConfigurableEnvironment environment) {
        String applicationName = environment.getProperty("spring.application.name");
        String basePath = environment.resolvePlaceholders("${rolling-file.appender.base-path:}");
        String maxFileSize = environment.resolvePlaceholders("${rolling-file.appender.max-file-size:20 MB}");
        String maxFileNum = environment.resolvePlaceholders("${rolling-file.appender.max-file-num:50}");
        LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
        Configuration configuration = loggerContext.getConfiguration();
        synchronized (configuration) {
            try {
                if (configuration.getAppender(APPENDER_NAME) != null) {
                    return;
                }
                Builder<RollingFileAppender> builder = null;
                for (final Method method : RollingFileAppender.class.getDeclaredMethods()) {
                    if (method.isAnnotationPresent(PluginBuilderFactory.class) &&
                            Modifier.isStatic(method.getModifiers()) &&
                            TypeUtil.isAssignable(Builder.class, method.getReturnType())) {
                        ReflectionUtil.makeAccessible(method);
                        builder = (Builder<RollingFileAppender>) method.invoke(null);
                        break;
                    }
                }
                if (StringUtils.isBlank(basePath)) {
                    basePath = System.getProperty("user.dir");
                }
                String currentPath = basePath + File.separator + "logs" + File.separator + applicationName;
                List<Field> fields = TypeUtil.getAllDeclaredFields(builder.getClass());
                AccessibleObject.setAccessible(fields.toArray(new Field[]{}), true);
                //必要字段赋值,字段和配置xml里面的属性是对应的
                for (Field field : fields) {
                    if ("name".equals(field.getName())) {
                        field.set(builder, APPENDER_NAME);
                    }
                    if ("fileName".equals(field.getName())) {
                        field.set(builder, currentPath + File.separator + "console.log");
                    }
                    if ("filePattern".equals(field.getName())) {
                        field.set(builder, currentPath + File.separator + "${date:yyyy-MM}" + File.separator + "console-%d{yyyy-MM-dd}-%i.log");
                    }
                    if ("filter".equals(field.getName())) {
                        field.set(builder, ThresholdFilter.createFilter(Level.DEBUG, Filter.Result.ACCEPT, Filter.Result.DENY));
                    }
                    //layout的格式取得是ROOT_APPENDER_NAME里面的
                    if ("layout".equals(field.getName())) {
                        field.set(builder, configuration.getAppender(ROOT_APPENDER_NAME).getLayout());
                    }
                    if ("policy".equals(field.getName())) {
                        field.set(builder, CompositeTriggeringPolicy.createPolicy(
                                OnStartupTriggeringPolicy.createPolicy(1),
                                TimeBasedTriggeringPolicy.newBuilder().build(),
                                SizeBasedTriggeringPolicy.createPolicy(maxFileSize)));
                    }
                    if ("strategy".equals(field.getName())) {
                        field.set(builder, DefaultRolloverStrategy.newBuilder()
                                .withMax(maxFileNum)
                                .withCustomActions(new Action[]{})
                                .withConfig(configuration)
                                .build());
                    }
                    if ("configuration".equals(field.getName())) {
                        field.set(builder, configuration);
                    }
                }
                RollingFileAppender rollingFileAppender = builder.build();
                //启动appender
                rollingFileAppender.start();
                //添加appender
                configuration.addAppender(rollingFileAppender);
                Map<String, LoggerConfig> loggers = configuration.getLoggers();
                Iterator<Map.Entry<String, LoggerConfig>> iterator = loggers.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, LoggerConfig> next = iterator.next();
                    //给logger关联 appender
                    next.getValue().addAppender(rollingFileAppender, null, null);
                }
                //更新 loggerContext
                loggerContext.updateLoggers(configuration);
            } catch (Exception e) {
                Logger logger = LoggerFactory.getLogger(RollingFileAppenderPlugin.class);
                logger.error(e.toString());
            }
        }
    }
}


2.上面的代码类似与log4j2.xml的如下配置

        <!--按照一定规则拆分的日志文件的 appender-->
        <RollingFile name="rollingFile" fileName="${LOG_HOME}/console.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/console-%d{yyyy-MM-dd}-%i.log">
            <!--日志级别过滤器-->
            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
            <!--日志消息格式-->
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" />
            <Policies>
                <!--在系统启动时,触发拆分规则,生产一个新的日志文件-->
                <OnStartupTriggeringPolicy />
                <!--按照文件大小拆分,20MB -->
                <SizeBasedTriggeringPolicy size="20 MB" />
                <!--按照时间节点拆分,规则根据filePattern定义的-->
                <TimeBasedTriggeringPolicy />
            </Policies>
            <!--在同一个目录下,文件的个数限定为 50个,超过进行覆盖-->
            <DefaultRolloverStrategy max="50" />
        </RollingFile>

3.启动类上添加监听类

	public static void main(String[] args) {
		SpringApplication springApplication = new SpringApplication(DemoActuatorApplication.class);
		//添加监听事件
		springApplication.addListeners(new RollingFileAppenderPlugin());
		springApplication.run(args);
	}
好的,我可以为您提供一些关于Spring Boot整合Log4j2的指导。 首先,您需要在Spring Boot项目的pom.xml文件中添加Log4j2相关依赖。以下是一个示例: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> </dependencies> ``` 接下来,您需要在项目中创建log4j2.xml文件。以下是一个示例: ```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> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="console"/> </Root> </Loggers> </Configuration> ``` 在这个示例中,我们定义了一个名为“console”的Appender,用于将日志输出到控制台。我们还定义了一个名为“Root”的Logger,用于将所有日志消息发送到“console”Appender,并将日志级别设置为“info”。 最后,在项目中使用Log4j2日志记录。您可以使用Spring的内置日志记录注解@Log4j2来注释您的类。以下是一个示例: ```java import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller @Log4j2 public class HomeController { @GetMapping("/") public String home() { log.info("Home page accessed"); return "home"; } } ``` 这个示例中,我们使用了Lombok提供的@Log4j2注解来注释HomeController类。然后,我们在home()方法中使用log.info()方法来记录日志消息。 希望这些指导对您有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值