一、导入

  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. 【题解】Luogu p2016 战略游戏 (最小点覆盖)

    题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能 ...

  2. noip2011 总结

    铺地毯 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺 ...

  3. Vue(9)购物车练习

    购物车案例 经过一系列的学习,我们这里来练习一个购物车的案例   需求:使用vue写一个表单页面,页面上有购买的数量,点击按钮+或者-,可以增加或减少购物车的数量,数量最少不得少于0,点击移除按钮,会 ...

  4. python用random模块模拟抽奖逻辑(print修改end参数使打印结果不分行)

    import random   #引入random模块,运用random函数list_one=["10081","10082","10083" ...

  5. 关于React Native常用技巧

    Doctor命令检查所需环境 @2019年11月18日,React Native v新增了一个环境检查和诊断命令行,可以帮助新手修复环境,输出环境依赖报告. 先建好的一个React Native项目, ...

  6. 『心善渊』Selenium3.0基础 — 22、使用浏览器加载项配置实现用户免登陆

    目录 1.浏览器的加载项配置 2.加载Firefox配置 3.加载Chrome配置 1.浏览器的加载项配置 在很多情况下,我们在登录网站的时候,浏览器都会弹出一个是否保存登录账号的信息.如果我们选择保 ...

  7. Git常用命令超级详细(全网最详细)

    1.新建代码库 1.1在当前目录新建一个 Git 代码库 $ git init 1.2新建一个目录,将其初始化为 Git 代码库 $ git init [project-name] 1.3下载一个项目 ...

  8. AcWing 239. 奇偶游戏

    小A和小B在玩一个游戏. 首先,小A写了一个由0和1组成的序列S,长度为N. 然后,小B向小A提出了M个问题. 在每个问题中,小B指定两个数 l 和 r,小A回答 S[l~r] 中有奇数个1还是偶数个 ...

  9. JS中的单例模式及单例模式原型类的实现

    单例模式 单例模式的定义: 保证一个类只有一个实例,并提供一个访问它的全局访问点 通过一个简单的例子来了解单例模式的作用: class Div { constructor() { return doc ...

  10. springCloud学习05之api网关服务zuul过滤器filter

    前面学习了zuul的反向代理.负载均衡.fallback回退.这张学习写过滤器filter,做java web开发的对filter都不陌生,那就是客户端(如浏览器)发起请求的时候,都先经过过滤器fil ...