一、导入

  Logback作为目前一个比较流行的日志框架,我们在实际项目经常使用到该框架来帮助我们打印日志,以便我们可以更快速地获取业务逻辑执行情况、定位系统问题。

  常用的日志打印一共有5种级别控制,优先级情况为:【TRACE】<【DEBUG】<【INFO】<【WARN】<【ERROR】。

  【TRACE】:trace是一种很低的日志级别,一般不会使用。目前,我只有在SpringBoot的启动之中,略微发现一些它的影子,表示的就是默认不打印的日志。

  【DEBUG】:debug是一种调试程序的日志级别,一般用于程序开发过程中打印一些调试日志、运行信息,可以比较随意的使用。

  【INFO】:info是用来输出程序的一些关键信息,强调业务逻辑的运行过程信息,不能随便打印。

  【WARN】:warn是用于输出一些警告提示信息,一般是系统进入到一种可恢复的状态时打印的信息,警告但不是严重错误。

  【ERROR】:error是系统已经发生错误的事件,比如发生了异常,但是不想影响系统的正常运行。可以打印一些错误信息,提示开发者关注或者定位问题。

  日志是打印在日志文件之中的,如果大量的打印会造成日志文件的骤增导致磁盘空间快速增长。但是,排查问题的时候,我们都尽可能希望日志级别可以足够的细致。没有问题的时候,我们希望日志文件可以尽量减少磁盘的占用。

  所以,如果我们可以做到动态地去控制日志级别,实现动态打印日志,那就可以完美解决上诉的需求。

二、敲代码

  

  1.先来个不同日志级别的打印类。

  每个打印类都只做一件事,判断一下当前级别,然后打印一行日志。(实际上,logback里面已经帮我们做了判断,我们在这里只是为了代码规范,减少日志拼接再打印的消耗,所以提前做了日志级别判断)

  TRACE级别:

package cn.lxw.trace;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* @Title:
* @ClassName: cn.lxw.trace.TraceLogger.java
* @Description:
*
* @Author: luoxw
* @Date: 2021/8/3 19:13
*/
public class TraceLogger {
private static final Logger logger = LoggerFactory.getLogger(TraceLogger.class); /**
* 功能描述: <br>
* 〈Print trace-level log〉
* @Param: []
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:12
*/
public static void printLog(){
if(logger.isTraceEnabled()) {
logger.trace("print trace log");
}
} }

  DEBUG级别:

package cn.lxw.debug;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* @Title:
* @ClassName: cn.lxw.debug.DebugLogger.java
* @Description:
*
* @Author: luoxw
* @Date: 2021/8/3 19:12
*/
public class DebugLogger {
private static final Logger logger = LoggerFactory.getLogger(DebugLogger.class); /**
* 功能描述: <br>
* 〈Print debug-level log〉
* @Param: []
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:12
*/
public static void printLog(){
if(logger.isDebugEnabled()) {
logger.debug("print debug log");
}
} }

  INFO级别:

package cn.lxw.info;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* @Title:
* @ClassName: cn.lxw.info.InfoLogger.java
* @Description:
*
* @Author: luoxw
* @Date: 2021/8/3 19:13
*/
public class InfoLogger {
private static final Logger logger = LoggerFactory.getLogger(InfoLogger.class); /**
* 功能描述: <br>
* 〈Print info-level log〉
* @Param: []
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:12
*/
public static void printLog(){
if(logger.isInfoEnabled()){
logger.info("print info log");
}
} }

  WARN级别:

package cn.lxw.warn;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* @Title:
* @ClassName: cn.lxw.warn.WarnLogger.java
* @Description:
*
* @Author: luoxw
* @Date: 2021/8/3 19:13
*/
public class WarnLogger {
private static final Logger logger = LoggerFactory.getLogger(WarnLogger.class); /**
* 功能描述: <br>
* 〈Print warn-level log〉
* @Param: []
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:12
*/
public static void printLog(){
if(logger.isWarnEnabled()) {
logger.warn("print warn log");
}
} }

  ERROR级别:

package cn.lxw.error;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* @Title:
* @ClassName: cn.lxw.error.ErrorLogger.java
* @Description:
*
* @Author: luoxw
* @Date: 2021/8/3 19:13
*/
public class ErrorLogger {
private static final Logger logger = LoggerFactory.getLogger(ErrorLogger.class); /**
* 功能描述: <br>
* 〈Print error-level log〉
* @Param: []
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:12
*/
public static void printLog(){
if(logger.isErrorEnabled()) {
logger.error("print error log");
}
} }

  2.将这些日志打印封装到一个方法中。

    /**
* 功能描述: <br>
* 〈print log with different logger levels.〉
* @Param: []
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:11
*/
private static void printLog() {
TraceLogger.printLog();
DebugLogger.printLog();
InfoLogger.printLog();
WarnLogger.printLog();
ErrorLogger.printLog();
}

  3.写一个随机返回日志级别的方法

    private static Level getRandomLevel(){
Level[] levelArr = new Level[]{Level.TRACE,Level.DEBUG,Level.INFO,Level.WARN,Level.ERROR};
int index = (int) (Math.random() * 10) % 6 + 1;
if(index > levelArr.length - 1){
index = 0;
}
return levelArr[index];
}

  4.核心修改来了,动态调整日志级别。这里主要是获取日志的上下文对象,是从ILoggerFactory转化来的,因为我们的日志上下文LoggerContext实现了ILoggerFactory接口。这里我的做法是获取所有的日志类,然后遍历出符合我们包名或者类名的条件,然后遍历设置对应的日志级别。

    /**
* 功能描述: <br>
* 〈refresh the level setting of the logger context〉
* @Param: [loggerPackage, loggerLevel]
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:11
*/
private static void refreshLoggerLevel(String loggerPackage, Level loggerLevel) {
// #1.get logger context
ch.qos.logback.classic.LoggerContext loggerContext = (ch.qos.logback.classic.LoggerContext) LoggerFactory.getILoggerFactory();
List<ch.qos.logback.classic.Logger> loggerList = loggerContext.getLoggerList();
// #2.filter the Logger object
List<Logger> packageLoggerList = loggerList.stream().filter(a -> a.getName().startsWith(loggerPackage)).collect(Collectors.toList());
// #3.set level to logger
for (ch.qos.logback.classic.Logger logger : packageLoggerList) {
logger.setLevel(loggerLevel);
}
}

  5.开始测试。开启一个定时线程池,然后打印日志,获取随机的一个日志级别,然后刷新日志上下文(设置日志级别)。下一个任务执行时间,继续重复上诉操作,观察变化。

    /**
* 功能描述: <br>
* 〈dynamic setting of Logback level start here.〉
* @Param: [args]
* @Return: {@link Void}
* @Author: luoxw
* @Date: 2021/8/3 19:06
*/
public static void main(String[] args) {
// you should know that the logger-level priority:
// trace < debug < info < warn < error // At first,define a scheduled thread.
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(() -> {
// Secondly, print log.
printLog();
// get logger-package and logger-level here(you can fetch the config from database or config-center)
// Thirdly, get logger level which is configured by you.
Level randomLevel = getRandomLevel();
System.out.println("logger level next time is : " + randomLevel);
// Finally,refresh the logger level which package is LOGGER_PACKAGE
refreshLoggerLevel(LOGGER_PACKAGE,randomLevel);
}, 2, 2, TimeUnit.SECONDS);
}

  6.查看日志,符合预期。通过该调整,可以实现我们需要的功能操作。

20:16:04.360 [pool-1-thread-1] DEBUG cn.lxw.debug.DebugLogger - print debug log
20:16:04.364 [pool-1-thread-1] INFO cn.lxw.info.InfoLogger - print info log
20:16:04.366 [pool-1-thread-1] WARN cn.lxw.warn.WarnLogger - print warn log
20:16:04.367 [pool-1-thread-1] ERROR cn.lxw.error.ErrorLogger - print error log
logger level next time is : WARN
20:16:06.137 [pool-1-thread-1] WARN cn.lxw.warn.WarnLogger - print warn log
20:16:06.137 [pool-1-thread-1] ERROR cn.lxw.error.ErrorLogger - print error log
logger level next time is : WARN
20:16:08.138 [pool-1-thread-1] WARN cn.lxw.warn.WarnLogger - print warn log
20:16:08.138 [pool-1-thread-1] ERROR cn.lxw.error.ErrorLogger - print error log
logger level next time is : DEBUG
20:16:10.138 [pool-1-thread-1] DEBUG cn.lxw.debug.DebugLogger - print debug log
20:16:10.138 [pool-1-thread-1] INFO cn.lxw.info.InfoLogger - print info log
20:16:10.138 [pool-1-thread-1] WARN cn.lxw.warn.WarnLogger - print warn log
20:16:10.138 [pool-1-thread-1] ERROR cn.lxw.error.ErrorLogger - print error log
logger level next time is : ERROR
20:16:12.137 [pool-1-thread-1] ERROR cn.lxw.error.ErrorLogger - print error log

三、总结

  这个动态日志打印其实不难,只是网络上的资料太少,需要自己翻阅一些源码,找到里面核心的内容,然后通过一些框架提供的类按照我们的需求进行自定义。源码还是要多看的,学会其中思想,从实际出发,解决项目问题。好了,今天分享到这,谢谢大家的观看!

  项目地址:https://github.com/telephone6/java-collection/tree/main/frame/logback

【Logback日志级别】动态调整Logback的日志级别的更多相关文章

  1. log4j日志打印级别动态调整

    1,为什么日志打印级别要动态调整? 随着项目越来越大,访问量也越来越高,遇到问题时想要排查,可是日志一打开却刷的太快太快,不好排查问题,有的时候甚至因为短时间打印日志太多,严重影响了性能,这个时候日志 ...

  2. 动态调整日志级别思路&实现

    引言 上篇文章 性能调优--小小的 log 大大的坑 已将详细的介绍了高并发下,不正确的使用日志姿势,可能会导致服务性能急剧下降问题.文末也给各位留下了解决方案--日志级别动态调整. 本文将详细介绍& ...

  3. logback日志级别动态切换的终极方案(asm使用)

    背景 一切皆有因果,所有事情,都有事件驱动.本方案的日志级别切换是由这样的背景下产生的: 单个生产环境上,有几百近千个微服务 日志级别切换不重启服务,要求即时生效果 由业务开发人员去修改代码或增加相关 ...

  4. springboot中动态修改logback日志级别

    springboot中动态修改logback日志级别 在spring boot中使用logback日志时,项目运行中,想要修改日志级别. 代码如下: import org.slf4j.Logger; ...

  5. 动态调整Log4j日志级别

    log4j2.xml配置文件中支持配置monitorInterval参数,检测到配置改变后重新加载,达到动态调整日志级别的效果. 故调整日志级别无须手动重启服务. log4j2.xml配置文件示意: ...

  6. Log4cpp配置文件及动态调整日志级别的方法

    一.log4cpp概述 Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下: 提供应用程序运行上下文,方便跟踪调试: 可扩展的.多种方式记录日志,包括命令 ...

  7. NoSql存储日志数据之Spring+Logback+Hbase深度集成

    NoSql存储日志数据之Spring+Logback+Hbase深度集成 关键词:nosql, spring logback, logback hbase appender 技术框架:spring-d ...

  8. java的几个日志框架log4j、logback、common-logging

    开发工作中每个系统都需要记录日志,常见的日志工具有log4j(用的最多),slf4j,commons-loging,以及最近比较流行的logback 以前只是在项目中用log4j,更多的是参考下配置文 ...

  9. 通过URL方式动态修改logback level级别

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; import ...

随机推荐

  1. 「10.12」木板(数学)·打扫卫生(神仙DP)

    A. 木板 一个很简单的数学题,简单推一下就好,路丽姐姐教你学数学. 将式子化出我们发现只需求出$i\times i/n$的个数 那么我们将$n$质因数分解,可知因子个数 为了整除$n$,令$i==\ ...

  2. WPF中选择文件和选择文件夹的方法

    最近从winform转WPF,遇到了各种各样的问题.然而网上的关于WPF的资料少之又少,甚至连基本的文件选择操作,百度搜索的首页都没有一个比较好的方法.所以,踩了几个坑之后,我把我得到的方法分享给大家 ...

  3. Vue(1)Vue安装与使用

    前言 Vue(读音/vjuː/,类似于view) 是一套用于构建前后端分离的框架.刚开始是由国内优秀选手尤雨溪开发出来的,目前是全球"最"流行的前端框架.使用vue开发网页很简单, ...

  4. 动态路由及RIP协议

    动态路由及 RIP协议 目录 一.动态路由协议 1.1.定义 1.2.特点 1.3.动态路由协议概述 1.4.度量值 1.5.收敛 1.6.静态路由和动态路由的比较 二.动态路由协议的分类 2.1.距 ...

  5. 【C语言】整型在内存中的存储

    整型在内存中的存储 1.整型的归类 char short int long 以上都分为有符号(signed)与无符号(unsigned)的类型 2.原码.反码和补码 2.1 定义 计算机在表示一个数字 ...

  6. Vue3全家桶升级指南二ref、toRef、toRefs的区别

    ref是对原始数据的拷贝,当修改ref数据时,模板中的视图会发生改变,但是原始数据并不会改变. toRef是对原始数据的引用,修改toRef数据时,原始数据也会发生改变,但是视图并不会更新. 在vue ...

  7. 13、ssh跳板机

    13.1.前提条件: 1.跳板机服务器和其它服务器建立了ssh秘钥登录: 2.目前的环境: (1)各服务器上都建立了lc用户,并给于sudo (lc ALL= NOPASSWD:ALL )权限,lc就 ...

  8. 使用VS2017开发APP中使用VUE.js开发遇到打包出来的android文件 在低版本的android(4.3)中无法正常使用

    使用VS2017开发VUE的APP应用遇到的问题集合 1,  打包出来的apk文件在Android 6.0版本以上手机可以正常打开,在Android 4.3版本手机上无法打开 原因:一开始猜测是不是V ...

  9. SonarQube插件

    关于插件我本身使用不多,如果看不惯英文界面,那么就先装个中文插件吧. 或者上微软的官方网站进行下载 将下载的插件上传到自己的sonarqube的服务的机器上,放置插件目录下,重启sonarqube即可 ...

  10. docker 搭建 redis 集群(哨兵模式)

    文件结构 1. redis-sentinel 1-1. docker-compose.yml 1-2. sentinel 1-2-1 docker-compose.yml 1-2-2 sentinel ...