乐趣区

关于java:日志瘦身骚操作从-5G-优化到-1G牛逼

作者:明明如月学长 \
链接:https://juejin.cn/post/711704…

一、背景

在日常开发中,通常为了不便调试、不便查问题,会打印很多 INFO 级别的日志。

随着访问量越来越大,一不小心,某个日志文件一天的 size 就大于了某个阈值(如 5G),于是,收到了优化日志大小的告警,肯定工夫内不优化反馈给你主管,囧 …

日志过大容易导致一些运维操作耗费机器性能,如日志文件检索、数据采集、磁盘清理等。

那么,日志瘦身哪些常见的思路呢?本文联合某个具体案例谈谈我的认识。

举荐一个开源收费的 Spring Boot 最全教程:

https://github.com/javastacks/spring-boot-best-practice

二、日志瘦身方法论

2.1 只打印必要的日志

有时候为了不便测试,长期打印很多 INFO 级别日志。对于这种日志,等我的项目上线前,能够将非必要的日志删除或者调整为 DEBUG 级别。


但有些场景下有些日志可打印为 DEBUG 也可打印为 INFO,打印成 INFO 级别占空间,打印成 DEBUG 级别线上查问题的时候又须要用到,肿么办?

咱们能够对日志工具类进行革新,反对上下文传递某个开关时(失常调用没有这个开关,通过公司的 Tracer 或者 RPC 上下文传递),能够长期将 DEBUG 日志晋升为 INFO 级别。伪代码如下:

if(log.isDebugEnable()){log.debug(xxx);
}else if(TracerUtils.openDebug2Info()){log.info("【debug2info】"+xxx);
}

这样,能够将一些纠结是否要打印成 INFO 日志的 log 打印成 DEBUG 级别,查问题时主动晋升为 INFO 日志。为了防止误会,辨别 DEBUG 晋升 INFO 的日志和一般 INFO 日志,加上 相似【debug2info】日志前缀。

当然,你也能够搞一些其余骚操作,这里只是举个例子,请自行触类旁通。

2.2 合并打印

有些能够合并的日志,能够思考合并。

如在同一个办法前后都打印了 INFO 日志:

INFO [64 位 traceId] XXXService 执行前 size =10 INFO [64 位 traceId] XXXService 执行后 size =4

能够合并成一条:

INFO [64 位 traceId] XXXService 执行前 size =10 执行后 size =4

2.3 简化 & 缩写 & 压缩

某个日志十分有必要,然而打印的对象有些大,如果能够满足问题排查需要的状况下,咱们能够:

(1)抉择只打印其 ID

(2)创立一个只保留关键字段的日志专用对象,转化为日志专用对象,再打印。

(3)能够用缩写,如 write 简化为 w, read 简化为 r, execute 简化为 e 等;比方 pipeline 中有 20 个外围 bean,打印日志时能够应用不同的编号代替 bean 全称,如 S1,S2,尽管没那么直观,但既能够查问题,又升高了日志量。

三、优化案例

3.1 场景形容

一个业务场景波及很多 bean,为了复用一些通用逻辑,这些 bean 都继承自某个抽象类。在抽象类中,定义了执行 bean 前后的一些通用逻辑,如执行前后打印以后 pipeline 中 item 的数量。最初一个 bean 执行完后果转换后须要打印出后果。

3.2 优化剖析

3.2.1 只打印必要日志

(1)因为以后 bean 执行前 相当于前一个 bean 执行后,因而只打印执行后的日志就能够,执行前的 INFO 日志能够删除或者改为 DEBUG(只打印必要日志)

(2)通常问题只呈现在执行前后 size 不统一的状况下,因而执行后打印日志前能够加个判断,如果执行前后 size 雷同则不打印。(只打印必要日志)伪代码如下:

if(sizeBefore != sizeAfter){log.info("service:{}, 前 size:{}, 后 size:{}", getName(),sizeBefore, sizeAfter)
}

举荐一个开源收费的 Spring Boot 最全教程:

https://github.com/javastacks/spring-boot-best-practice

这招成果很显著,因为大多数 bean 的执行前后 size 是雷同的,就不会打印这条日志。而假如之前有 20 个,这条日志就须要打印 20 次,改良后可能只须要打印 2-3 次。

3.2.2 日志合并

(2)为了不便查问题还须要打印执行前的 size,那么将执行前的 size 记录在内存中,打印执行后日志时多打印出执行前的 size。(合并打印)伪代码如下:

log.info("service:{}, 执行前 size:{}", getName(),sizeBefore)

log.info("service:{}, 执行后 size:{}", getName(),sizeBefore, sizeAfter)

合并后

log.info("service:{}, 前 size:{}, 后 size:{}", getName(),sizeBefore, sizeAfter)

3.2.3 日志精简

对于最终后果,将后果对象(如 XXDTO)转化为只包含要害信息,如 id, title 的日志对象(XXSimpleLogDTO),转化为日志对象后再打印。

log.info("resultId:{}",result.getId());

或者

log.info("result:{}",toSimpleLog(result));

3.3 成果评估

该日志一天产生 5 G 左右,这里百分之 80% 左右都是打印执行前后的 size,10% 左右是打印最终后果, 还有一些其余的日志。通过上述办法优化后,每天日志量有余 1G。

在满足排查问题的须要,又实现日志瘦身之间进行了取舍。

四、总结

日志瘦身须要进行衡量,保留排查问题的必要日志状况下尽可能精简。

能够采纳删除不必要日志,合并日志,日志简化等形式进行优化。

咱们还能够进行一些骚操作,反对线上 DEBUG 长期晋升 INFO(当然也能够应用 arthas)来辅助咱们查问题。

你还有哪些不错的日志瘦身技巧?欢送在文章开端评论和我交换。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿 (2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版