第1章:日志系统概述
1.1 日志的重要性
日志这东西,说白了就是系统的黑匣子。我在刚入行的时候,有个前辈跟我说过一句话,我至今记得:「没有日志的系统,就是一头蒙着眼睛拉磨的驴——你永远不知道它什么时候会撞墙。」
为什么我这么强调日志?原因很简单。你想想看,万一哪天线上出了故障,服务器响应变慢了,用户投诉了,你手上只有一堆看不懂的内存转储,那基本就抓瞎了。日志就是你的第一手现场证据。
我个人习惯把日志的重要性归结为两个层面:
| 层面 | 具体价值 | 我见过的典型场景 |
|---|---|---|
| 业务保障 | 交易链路追踪、用户行为审计、异常报警 | 有一回电商大促,支付成功率突然掉了,全靠日志倒查出一段空指针异常 |
| 开发维护 | bug复现、性能分析、安全取证 | 记得某个中间件OOM,日志里满屏的"OutOfMemoryError",问题一目了然 |
一句话:日志是系统的眼睛。眼睛瞎了,手脚再利索也没用。
1.2 日志分类
日志不是一锅粥,得分类管理。我见过不少项目,所有日志往一个文件里怼,结果排查问题时跟大海捞针似的。那样效率太低了。
按用途分,日志大致可以分为这几类:
- 业务日志:记录业务流程的关键节点。比如用户注册、下单、支付成功/失败。这些日志一般是给产品和运营看的。
- 监控日志:系统健康状态的快照。CPU、内存、GC、QPS、延迟,这类数据用来做报警和容量规划。
- 审计日志:谁在什么时候干了什么事。合规要求,不能丢。
- 调试日志:开发阶段用的,框架默认输出的那些 DEBUG 级别的信息。线上的话,我建议慎开。
嗯,这里要注意:分类清楚了,存储和索引才好做。别把业务日志和调试日志混在一起写,否则后面建索引的时候你会哭的。
1.3 常见日志框架
市面上的日志框架,说实话,来来去去就那么几个。我挑几个我真正用过的跟大家聊聊。
| 框架 | 特点 | 适合场景 | 我个人吐槽 |
|---|---|---|---|
| Log4j | 老牌、配置灵活、支持多种输出 | 传统Java项目 | 版本升级太折腾,Log4j2才算是真改进 |
| Logback | 性能好、原生支持SLF4J、自动重载 | Spring Boot项目默认 | 很稳定,我基本上所有的微服务项目都在用 |
| SLF4J | 统一门面、不干活只绑桥 | 与Logback配合使用 | 做框架开发时,必用SLF4J |
| java.util.logging | JDK自带、零依赖 | 小工具、学习demo | 功能太弱,线上项目我几乎不用 |
避坑指南:我曾经在一个分布式项目里,同时依赖了Log4j和Logback,结果classpath里的绑定冲突了,日志直接不输出。排查了整整半天,最后发现是某个第三方库阴戳戳地引入了Log4j。所以,统一门面很重要,SLF4J是最好的选择。
下面这张图,是我自己总结的日志系统整体框架,从产生到输出,各个角色之间的关系画得一目了然。
1.4 框架选择建议
选框架这事,其实不复杂。我个人总结了三条原则:
- 门面先行:不管底层用啥,上层先绑定SLF4J。这样以后换框架,只改pom.xml,不改业务代码。
- 性能为主:高并发场景,Logback和Log4j2都行。如果追求极致性能,Log4j2的异步日志会更有优势。我记得有一次压测,把Logback换成Log4j2的异步模式,吞吐量直接提升了30%。
- 运维友好:Logback支持自动重载配置文件,改完日志级别不用重启。这个功能我在排查线上问题的时候经常用,超级方便。
警告:千万别在线上用 System.out.println() 来打日志。第一,性能差,同步阻塞IO;第二,没有分级,没法按级别过滤;第三,线上日志文件你能找到吗?我曾经接手过一个项目,代码里全是 System.out,生产上出了bug,连个排查线索都没有。那叫一个痛苦。
嗯,这一章的内容就先到这。日志系统是整个存储和索引优化的基石,地基打牢了,后面怎么优化你心里都有数。