当前位置: 首页 > 工具软件 > go-spring > 使用案例 >

springboot logback-spring.xml 整合apollo实现动态配置日志级别

曹经业
2023-12-01

平时项目记录日志记录打印SQL,打印MQ日志,日志量比较大,一般用INFO,但是项目刚上线,不太稳定一般需要用DEBUG记录详细日志,或者由于项目出现问题,需要调整到DEBUG,查看详情,所以需要支持动态调整日志级别. 

1.配置logback-spring.xml

2.配置application.yml

3.配置apollo参数

4编写apollo变化触发类

5.编写日志测试类

6.测试

1.配置logback-spring.xml

  配置日志级别log.level ,参数log.level.com.sun.springboot来源于apollo参数

  <springProperty scope="context" name="log.level" source="log.level.com.sun.springboot"/>

 配置logger,日志级别来自上面定义的参数log.level

 <logger name="com.sun.springboot.controller" level="${log.level}"/>

2.配置application.yml
 apollo:
   bootstrap:
     #在应用启动阶段是否向Spring容器注入被托管的properties文件配置信息
     enabled: true
     eagerLoad:
     #将Apollo配置加载提到初始化日志系统之前
        enabled: true

3.配置apollo参数

   log.level.com.sun.springboot  info

4编写apollo变化触发类

package com.sun.springboot.controller;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * 自动刷新apollo配置
 */
@Slf4j
@Component
public class LogLevelChanged implements ApplicationContextAware {
    private Logger logger = LoggerFactory.getLogger(LogLevelChanged.class);

    private ApplicationContext applicationContext;
    private String prefix = "log.level.";

    @ApolloConfigChangeListener(value = {"application"})
    public void onChange(ConfigChangeEvent changeEvent) {
        log.info("================Apollo 自动刷新值 开始 ===========================");

        Map<String, String> logMap = new HashMap<>();
        for (String changeKey : changeEvent.changedKeys()) {
            changeKey = changeKey.trim();
            ConfigChange configChange = changeEvent.getChange(changeKey);
            String oldValue = configChange.getOldValue();
            String newValue = configChange.getNewValue();

            if (changeKey.startsWith(prefix)) {
                logMap.put(changeKey.substring(prefix.length()), newValue);
            } else {
                continue;
            }
            log.info("changedKey:【{}】,oldValue=【{}】, newValue:【{}】", changeKey,

            oldValue, newValue);
        }

        changeLogLevel(logMap);
        log.info("================Apollo 自动刷新值 结束 ===========================");
    }

    private void changeLogLevel(Map<String, String> logMap) {
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        for (String key : logMap.keySet()) {
            ch.qos.logback.classic.Logger logbackLogger = lc.getLogger(key);
            logbackLogger.setLevel(Level.toLevel(logMap.get(key)));
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws          BeansException {
        this.applicationContext = applicationContext;
    }
}

5.编写日志测试类

package com.sun.springboot.controller;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Objects;

@RestController
@RequestMapping(value = "log")
public class LogController {
    private static Logger logger = LoggerFactory.getLogger(LogController.class);

    /**
     * 获得日志所在包的日志级别
     *
     * @param pack 所在包的日志级别
     * @return
     */
    @RequestMapping(value = "getLevel")
    public String getLevel(String pack) {
        Logger logger = LoggerFactory.getLogger(LogController.class);
        // 第一步:获取日志上下文
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        // 第二步:获取日志对象 (日志是有继承关系的,关闭上层,下层如果没有特殊说明也会关闭)
        ch.qos.logback.classic.Logger log = lc.getLogger(pack);
        Level level = log.getLevel();
        String result = "";
        if (Objects.isNull(level)) {
            result = String.format("package:%s,level:%s", pack, "null");
        } else {
            result = String.format("package:%s,level:%s", pack, level.toString());
        }

        // 第三步:修改日志级别
        logger.debug("===== 我是 debug  =====");
        logger.info("===== 我是 info  =====");
        logger.error("===== 我是 ERROR  =====");
        return result;
    }
}

6.测试

  6.1先修改 log.level.com.sun.springboot 为debug

  6.2  访问接口:http://localhost:6012/log/getLevel?pack=com.sun.springboot.controller

  返回:package:com.sun.springboot.controller,level:DEBUG

logback-spring.xml 

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="20 seconds">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <springProperty scope="context" name="log.level" source="log.level.com.sun.springboot"/>

    <property name="LOG_HOME" value="F:/logs-spring"/>
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/debug/debug.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>16</MaxHistory>
            <!--日志文件切割大小-->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>16</MaxHistory>
            <!--日志文件切割大小-->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/warn/warn.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>24</MaxHistory>
            <!--日志文件切割大小-->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
    </appender>
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/error/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>32</MaxHistory>
            <!--日志文件切割大小-->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>
    <logger name="com.sun.springboot.controller" level="${log.level}"/>
    <!-- 日志输出级别 -->
    <root level="INFO">
        <!-- 控制台输出 -->
        <appender-ref ref="STDOUT"/>
        <!--<!– 文件输出 –>-->
        <appender-ref ref="ERROR"/>
        <appender-ref ref="INFO"/>
        <appender-ref ref="DEBUG"/>
        <appender-ref ref="WARN"/>
    </root>
</configuration>

参考:springboot apollo 自动刷新_重度孤独症患者的博客-CSDN博客

logback java动态配置【动态修改日志级别,动态修改appender】_keep-go-on的博客-CSDN博客_java 动态修改日志级别

 类似资料: