当前位置: 首页 > news >正文

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

平时项目记录日志记录打印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 动态修改日志级别

相关文章:

  • 完全背包问题
  • 【python中级】func_timeout程序超时处理
  • JUC 并发编程_锁
  • java基于springboot+vue的高校大学生社团活动管理系统
  • 框架之SpringBoot基础(二)
  • 【小程序】中WXS的语法详解
  • Spring Cloud Gateway - GatewayFilter路由过滤器
  • 猿创征文|大数据之Kafka简介+基操
  • Shiro授权--注解式开发
  • CREO:CREO软件之零件【编辑】之修饰、用户定义特征的简介及其使用方法(图文教程)之详细攻略
  • Java并发 | 12.[方法] interrupt( )打断
  • SpringBoot 事务开发代码及注意事项
  • onnx: step = 1 is currently not supported
  • webpack原理篇(六十五):实战开发一个压缩构建资源为zip包的插件
  • 数学建模学习(97):花授粉算法(FPA)寻优
  • [PHP内核探索]PHP中的哈希表
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 【Amaple教程】5. 插件
  • CSS魔法堂:Absolute Positioning就这个样
  • IDEA常用插件整理
  • JavaScript设计模式之工厂模式
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Python socket服务器端、客户端传送信息
  • Python中eval与exec的使用及区别
  • Spark学习笔记之相关记录
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 设计模式(12)迭代器模式(讲解+应用)
  • 学习Vue.js的五个小例子
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 原生Ajax
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • AI算硅基生命吗,为什么?
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • #NOIP 2014# day.1 T2 联合权值
  • (C++)八皇后问题
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (k8s中)docker netty OOM问题记录
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (一)u-boot-nand.bin的下载
  • (转)可以带来幸福的一本书
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • ******IT公司面试题汇总+优秀技术博客汇总
  • ***利用Ms05002溢出找“肉鸡
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • .Net下的签名与混淆
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • ::什么意思
  • @RequestMapping-占位符映射
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell