Logback 使用TurboFilter实现日志级别等内容的动态修改操作


Posted in Java/Android onAugust 30, 2021

Logback TurboFilter实现日志级别等内容的动态修改

可能看到这个标题,读者会问:要修改日志的级别,不是直接修改log.xxx就好了吗?为何要搞那么复杂呢?所以,先说一下场景

为什么要通过TurboFilter去动态的修改日志级别

我们在使用Java开发各种项目的时候必然的会引入很多框架,这些框架通过堆叠的方式完成所要提供的业务服务(一个服务请求在进入后会在这些框架中兜一圈,然后返回结果),当一个比较底层的框架在处理过程中抛出了异常之后,这个异常会不断的向上传递。

这个时候,有的框架直接throw,继续向上抛,而有的在throw之前还会自己打印一下error日志,这就导致了当出现异常的时候,往往会出现一连串类似的错误日志记录。如果对接了错误日志告警,就会出现重复告警的现象。为了解决类似这样的问题,修改源码重新编译最直接,但是不可取。

所以希望可以有更好的手段去控制这些已经被编码固化的日志打印信息。当我们使用Logback的时候,TurboFilter就是解决该问题的工具之一。

TurboFIlter不同于之前在[《Logback中如何自定义灵活的日志过滤规则》]一文中介绍的那些通过ch.qos.logback.core.filter.Filter接口实现的过滤器。ch.qos.logback.core.filter.Filter实现的过滤器是与Appender绑定的,而TurboFIlter是与日志上下文绑定的,它会过滤所有的日志请求,并且TurboFIlter的方法中提供了丰富的可访问信息用来进行控制和改写。

比如下面的实现,通过继承ch.qos.logback.classic.turbo.TurboFilter类,并重写decide方法,将org.springframework.cloud.sleuth.instrument.web.ExceptionLoggingFilter类中原本要打印的ERROR日志DENY掉(过滤掉),同时以WARN级别打印一封相同的内容,这样就实现了对已定义日志的动态修改。

public class ForceWarnFilter extends TurboFilter {
    @Override
    public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable throwable) {
        if (level == Level.ERROR && logger.getName().equals("org.springframework.cloud.sleuth.instrument.web.ExceptionLoggingFilter")) {
            logger.warn(marker, format, params);
            return FilterReply.DENY;
        }
        return FilterReply.NEUTRAL;
    }
}

为了让上面定义的过滤器生效,需要在logback的配置xml中增加如下配置:

<configuration>
    <turboFilter class="com.didispace.log.filter.ForceWarnFilter" />
    ......
</configuration>

或者也可以在应用主类中增加:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.addTurboFilter(new MyTurboFilter());

更多关于Logback过滤器的内容可参考官方文档

logback动态设置某个类的日志级别

假设一下,现在有这么个情况

你调别人的接口出问题了,但是怎么排查都定位不了原因。只能借助更详细的日志信息,这个时候,又不想把全局的日志级别调低,毕竟调低对并发量大的应用来说,瞬间会涌出很多很多日志信息。

最好的情况就是,只调整出问题的那个类的日志级别。那怎么办呢?

于是就有了下面的方案

定向修改某个class的logger日志级别。

public void testLog(String key, String level, String level2){
        LoggerContext loggerContext= (LoggerContext) LoggerFactory.getILoggerFactory();
        //设置全局日志级别
        ch.qos.logback.classic.Logger logger=loggerContext.getLogger("root");
        logger.setLevel(Level.toLevel(level));
 
        if (!StringUtils.isBlank(level2)) {
            //设置某个类日志级别-可以实现定向日志级别调整
            ch.qos.logback.classic.Logger vLogger = loggerContext.getLogger(key);
            if (vLogger!=null)
                vLogger.setLevel(Level.toLevel(level2));
        }
 
        List<ch.qos.logback.classic.Logger> loggerList = loggerContext.getLoggerList();
        for (ch.qos.logback.classic.Logger logger1 : loggerList){
            log.info(logger1.getName());
        }
    }

比如:

level = ERROR
     level2 = INFO
     key = "com.duy.soo.web.controller.TestController"

表示把全局日志级别设置为ERROR级别,单独把com.duy.soo.web.controller.TestController类的日志设置为INFO级别。

/**
 * @Author changle
 * @Time 17/6/30.
 * @Desc to do
 */
@Slf4j
@Controller
@RequestMapping(value = "/api/test")
public class TestController {
    @RequestMapping("/testDebug")
    @ResponseBody
    public Response<String> testLog(String key){
        //打印日志级别
        String rtn = "this is a INFO";
        log.info(rtn);
        rtn = "this is a ERROR";
        log.error(rtn);
        rtn = "this is a DEBUG";
        log.debug(rtn);
        Response<String> response = Response.ok(rtn);
        return response;
    }
}

如此一来,除了com.duy.soo.web.controller.TestController类以外的其他类,都只输出ERROR日志,而TestController类能输出INFO日志信息。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Java/Android 相关文章推荐
手把手教你用SpringBoot将文件打包成zip存放或导出
Jun 11 Java/Android
Java内存模型之happens-before概念详解
Jun 13 Java/Android
spring项目中切面及AOP的使用方法
Jun 26 Java/Android
如何给HttpServletRequest增加消息头
Jun 30 Java/Android
Java比较两个对象中全部属性值是否相等的方法
Aug 07 Java/Android
零基础学java之方法的定义与调用详解
Apr 10 Java/Android
Java 多态分析
Apr 26 Java/Android
Android 界面一键变灰 深色主题工具类
Apr 28 Java/Android
解决Springboot PostMapping无法获取数据的问题
May 06 Java/Android
Android Gradle 插件自定义Plugin实现注意事项
Jun 16 Java/Android
Spring Cloud OpenFeign模版化客户端
Jun 25 Java/Android
SpringBoot接入钉钉自定义机器人预警通知
Jul 15 Java/Android
Java SSM配置文件案例详解
Aug 30 #Java/Android
java调用Restful接口的三种方法
Aug 23 #Java/Android
JVM钩子函数的使用场景详解
Java中CyclicBarrier和CountDownLatch的用法与区别
Aug 23 #Java/Android
SpringBoot整合Mybatis Generator自动生成代码
Aug 23 #Java/Android
Java面试题冲刺第十九天--数据库(4)
Java获取e.printStackTrace()打印的信息方式
Aug 07 #Java/Android
You might like
上海无线电三厂简史修改版
2021/03/01 无线电
php 执行系统命令的方法
2009/07/07 PHP
linux使用crontab实现PHP执行计划定时任务
2014/05/10 PHP
在Ubuntu 14.04上部署 PHP 环境及 WordPress
2014/09/02 PHP
Yii2中hasOne、hasMany及多对多关联查询的用法详解
2017/02/15 PHP
PHP获取HTTP body内容的方法
2018/12/31 PHP
CSS+Table图文混排中实现文本自适应图片宽度(超简单+跨所有浏览器)
2009/02/14 Javascript
jquery select(列表)的操作(取值/赋值)
2009/08/06 Javascript
SeaJS入门教程系列之SeaJS介绍(一)
2014/03/03 Javascript
特殊情况下如何获取span里面的值
2014/05/20 Javascript
jQuery ui 利用 datepicker插件实现开始日期(minDate)和结束日期(maxDate)
2014/05/22 Javascript
jQuery源码分析之jQuery中的循环技巧详解
2014/09/06 Javascript
jQuery实现首页图片淡入淡出效果的方法
2015/06/10 Javascript
jquery实现图片上传之前预览的方法
2015/07/11 Javascript
jQuery中ajax的load()与post()方法实例详解
2016/01/05 Javascript
再次谈论React.js实现原生js拖拽效果引起的一系列问题
2016/04/03 Javascript
详解ECMAScript6入门--Class对象
2017/04/27 Javascript
JS实现从对象获取对象中单个键值的方法示例
2019/06/05 Javascript
JavaScript 扩展运算符用法实例小结【基于ES6】
2019/06/17 Javascript
node 解析图片二维码的内容代码实例
2019/09/11 Javascript
vue-iview动态新增和删除的方法
2020/06/17 Javascript
ajax jquery实现页面某一个div的刷新效果
2021/03/04 jQuery
[01:15:44]首部DOTA2纪录片今日23时全网上映
2014/03/19 DOTA
[55:44]完美世界DOTA2联赛决赛 FTD vs Phoenix 第二场 11.08
2020/11/11 DOTA
使用Python抓取模板之家的CSS模板
2015/03/16 Python
Python异常的检测和处理方法
2018/10/26 Python
python3.6 tkinter实现屏保小程序
2019/07/30 Python
python实现网站微信登录的示例代码
2019/09/18 Python
html5贪吃蛇游戏使用63行代码完美实现
2013/06/25 HTML / CSS
HUGO BOSS美国官方网上商店:世界知名奢侈品牌
2017/08/04 全球购物
美国首屈一指的礼品篮供应商:GiftTree
2018/01/06 全球购物
企业总经理岗位职责
2014/02/13 职场文书
环保建议书作文
2014/03/12 职场文书
2015年城乡环境综合治理工作总结
2015/07/24 职场文书
学校团代会开幕词
2016/03/04 职场文书
KVM基础命令详解
2022/04/30 Servers