spring-boot-demo icon indicating copy to clipboard operation
spring-boot-demo copied to clipboard

多项目 日志动态精确 控制

Open lxk696 opened this issue 6 years ago • 20 comments

目标: 1、项目提供restful接口,动态 修改 线上项目的日志级别,动态 生成添加 新的包路径logger 记录包日志 (支持log4j2,logback). 2、可以动态指定 某个用户的 userId ,让该用户所有操作行为日志全为debug(可指定)级别,且把该日志全单独写入一个独立文件,可以根据userId 查询某用户所有操作日志(有页面可以操作) 3、一个请求中,异步任务也需能支持日志动态改变,需设置线程池支持。 4、多个项目,使用共享redis 支持。一处操作,所有关联项目都同时同步 更改日志的操作

lxk696 avatar May 24 '19 15:05 lxk696

https://tech.meituan.com/2017/02/17/change-log-level.html 美团有实现一部分,但不完整

lxk696 avatar May 24 '19 16:05 lxk696

大佬,有兴趣整整试试。 有兴趣的话,联系下我qq 69671710 ,我自己偶尔弄弄玩,可以简单跑起来了,但很多不完善。 弄了半年,都拖着没个下文。。。

lxk696 avatar May 24 '19 16:05 lxk696

动态修改日志级别的话,我记得 spring-boot-starter-admin 配合 actuator 就可以做到。不过针对 userId 的还没遇到过,我已经加到新功能列表了,当然更加期待您的PR~~ 十分感谢 @lxk696

xkcoding avatar May 27 '19 00:05 xkcoding

spring-boot-starter-admin 我有看过点,感觉没 美团 描述的功能那么深入实用。 可能是我了解不深。

我这周 把 动态日志 相关的单独整理出成一个demo 项目,到时发你。

共同学习,有很多问题 还要请教你,感谢你才是

lxk696 avatar May 28 '19 12:05 lxk696

ok,等你整理出来,我看看给整合到这儿来,这个issue,后期整完了再关,再次感谢

xkcoding avatar May 29 '19 01:05 xkcoding

不好意思,最近几天忙忘记了。。

lxk696 avatar Jun 05 '19 16:06 lxk696

https://gitee.com/huayu696/logmm.git 码云的地址。 页面还没整理完。 测试案例使用 postman测试 test/resources/log_test.postman_collection.json

待解决问题

1:

把当前需跟踪的用户 id 配置进 日志上下文中,配合log4j2.xml 的
DynamicThresholdFilter 和 Routing 可以用ctx 取出上下文,且可以 以用户id为维度, 动态控制用户日志,及打印的日志文件名 。 如跟踪用户的userId=33 ,则把跟踪日志单独写入 trace/33.log 下。没找到解决方案。

2:

支持同时跟踪多个用户。 因为现在 log4j2 的 DynamicThresholdFilter 使用动态 KeyValuePair 键值会报错,没找到解决方案。

3:

aop 代理 ,线程,线程池 对动态日志的支持 线程池需使用阿里巴巴的线程池,待测试

4:

多项目支持 初始化redis缓存,缓存中放入各项目Logger列表; 查询:后台管理(admin)项目从缓存中获取各项目Logger列表; 修改:后台管理(admin)项目发布日志级别调整信息,像各项目推送日志级别(或用户跟踪)调整信息。收到信息后,调整日志级别,更新项目Logger列表。 使用共享redis可支持,待测试 log/log.jsp 页面操作暂未完成

lxk696 avatar Jun 05 '19 16:06 lxk696

希望大佬解决这些难点把 。 我现在只做了 log4j2的。 参考的比较多的是 阿里巴巴的,和log4j2官网的。

lxk696 avatar Jun 05 '19 16:06 lxk696

@lxk696 十分感谢,我会抽时间整理,后续整理完会在这个issue下回复

xkcoding avatar Jun 12 '19 09:06 xkcoding

感谢大佬!ヾ( ̄▽ ̄)

lxk696 avatar Jun 13 '19 12:06 lxk696

大佬,你最近是太忙了吗?还是忘了这回事了啊。。ヘ(_ _ヘ)

lxk696 avatar Sep 19 '19 14:09 lxk696

忘记啦。。。。十分抱歉哈! :cold_sweat:

xkcoding avatar Sep 19 '19 14:09 xkcoding

没事,大佬你太忙了,watch 你,邮箱看到你那天天消息。。。

麻烦有时间帮忙看看咯 ヽ(°◇° )ノ

lxk696 avatar Sep 19 '19 15:09 lxk696

hello, @lxk696 十分抱歉,拖更了这么久

我找了一周末资料,感觉这个比较靠谱,http://oct.im/how-to-create-logback-loggers-dynamicallypragmatically.html

主要的方案就是动态地去添加 appender

提供一些思路:

  • AOP 在 @AroundjoinPoint.proceed() 之前根据 user-id 等信息构造 appender,然后调用 appender.start() 启用,在 joinPoint.proceed() 之后调用 appender.stop() 关闭

  • Interceptor preHandle 的时候构造并启用 appender,afterCompletion 的时候关闭 appender

下面是我测试的代码,没有用上面的思路,直接controller暴露接口修改的。

  1. 支持动态更换目录
  2. 动态设置日志级别
@GetMapping("set")
@SuppressWarnings("unchecked")
public String changeLogLevel(String packageName, String level, boolean close) {
    Logger logger = (Logger) TestController.log;
    LoggerContext loggerContext = logger.getLoggerContext();

    Logger packageLogger = loggerContext.getLogger(packageName);
    packageLogger.setLevel(Level.toLevel(level));

    if (!close) {
        FileAppender fileAppender = new FileAppender();
        fileAppender.setContext(loggerContext);
        fileAppender.setName("package");
        String userId = "user-237497819";
        fileAppender.setFile("logs/" + packageName + "/" + userId + ".log");

        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(loggerContext);
        encoder.setPattern("%r %thread %level - %msg%n");
        encoder.start();

        fileAppender.setEncoder(encoder);
        fileAppender.start();

        packageLogger.addAppender(fileAppender);
    } else {
        packageLogger.getAppender("package").stop();
    }

    // 可以省略
    StatusPrinter.print(loggerContext);

    return "success";
}

xkcoding avatar Sep 23 '19 10:09 xkcoding

多谢了,感谢大佬帮忙了。

不过,我原来有考虑过用代码实现,感觉有些不好。 主要是如果用log.xml配置就可以的话更方便, 我写的案例里,可以根据log.xml里的配置来实现一部分,感觉是我 配置文件不会写。。。

lxk696 avatar Sep 24 '19 13:09 lxk696

大佬,你感觉这个 应用到生产环境的价值吗? 我自己感觉还蛮有意思的。。。 就是太水了,弄不来

lxk696 avatar Sep 24 '19 13:09 lxk696

为了支持这些功能,阿里云都写了不少 jar .感觉应该有生产价值的吧, 大佬 可以再完善下的

lxk696 avatar Sep 24 '19 13:09 lxk696

我还想再里面再加个功能。

比如 有时项目里出现异常, 如一个请求来了 从方法A 开始, A-B-C-D-E-F-G-H-返回结果。 此时调用链中比较深的 G方法出异常了。 想解决这个问题,只能靠猜,或者用模拟数据调试大部分流程,这样很麻烦。

我再想能不能,当出异常的时候,在全局异常处理器中,根据堆栈日志,找到每个方法调用链(能实现),找到每个方法的入参名(能实现),找到每个方法的入参值(不能实现),再在全局异常处理器中打印出来。

这样我看到 G方法出异常了,我只要看全局异常日志中 G方法入参是什么, 就大概知道原因了。 这样就省事很多,不用在每个方法里手动打印入参,只在异常时自动打印。

问了些大佬,说用aop,但感觉aop 会需要把所有所有方法包一层,影响性能。

大佬,你有什么思路吗?

lxk696 avatar Sep 24 '19 13:09 lxk696

这个暂时没有想到思路诶,感觉这个调用链好像有点 Sleuth + Zipkin 的意思 - -||

等你找到解决方案的时候,记得在这儿更新下哈~

xkcoding avatar Sep 24 '19 16:09 xkcoding

好的,不过现在公司转型,要学scala spark,很久没看java了,不然一直想把动态日志做完,得抽时间看下log4j2怎么实现的,覆写他源码,我上面说的功能应该很简单就能实现了

lxk696 avatar Sep 25 '19 12:09 lxk696