日志查看与分析基础:日志级别、关键字段、常见日志格式解析

做密文检索排查,第一件事就是翻日志。没有日志,你就像蒙着眼睛修机器。但我发现很多新手拿到日志就懵,密密麻麻的文本不知道看哪里。

其实日志没那么玄乎。你只需要搞清楚三个东西:日志级别、关键字段、格式。搞懂了,排查效率至少翻一倍。我自己刚入行时,花了一周才找到的 bug,现在半小时就能定位——差别就在会不会看日志。

日志级别:先筛掉噪音

日志级别是个金字塔。越往上,问题越严重,数量越少。你想想看,线上一个服务一秒输出几万条 DEBUG,你一条条看,那不疯了吗?

一般密文检索系统会定义这几个级别:

级别 含义 典型场景
DEBUG 调试用,开发环境才开 打印请求参数、中间变量
INFO 关键流程步骤 检索请求到达、结果返回
WARN 可能有问题但没挂 缓存穿透、重试次数超限
ERROR 功能异常,需要人工介入 查询超时、解密失败
FATAL 系统级崩溃,无法恢复 内存溢出、磁盘写入失败

我有个习惯:排查时先 grep "ERROR" 或 "FATAL",缩小范围。如果 ERROR 太多,再降级看 WARN。曾经有个同事,线上挂了半天,他还在 DEBUG 日志里翻来翻去——其实错误日志早就打印了,只不过被他忽略了。嗯,这就是不设级别筛选的代价。

注意:生产环境不能开 DEBUG!一来日志量爆炸,二来可能泄露敏感数据(比如密文原文)。我自己就踩过坑,DEBUG 里打印了用户明文密码,结果被安全部门通报整改。

关键字段:一眼锁定问题

光看级别还不够。你要从日志行里快速抓取几个关键信息。我一般会看这几个字段:

  • 时间戳 —— 问题发生的时间点,精确到毫秒。跨服务排查时,靠它对齐上下游。
  • 线程名 —— 密文检索大多是异步多线程,不同线程处理不同请求。看线程名能区分并发调用。
  • 日志级别 —— 上面讲过了。
  • 类名/方法名 —— 知道是在代码哪个位置触发,快速定位源代码。
  • 消息内容 —— 具体描述,比如 "decrypt failed: illegal key size"。
  • 异常堆栈 —— ERROR 级别才带,告诉你从哪行代码开始报错。

举个例子,我排查过一个问题:用户密文检索一直返回空结果。看日志发现一条 INFO:

2025-03-28 14:23:45.678 [pool-3-thread-5] INFO  c.m.crypto.SearchService - search completed, total: 0

线程名是 "pool-3-thread-5",说明是线程池里的任务。total:0 表示检索到了数据但匹配数为0。再往前翻 DEBUG 日志,发现 "ciphertext decode failed"——解码都失败了,后面当然查不到。这就是关键字段串联起来的威力。

小技巧:日志里不要只看文字,也要看数字。比如 "retry: 3/5",说明重试了三次,网络或者服务端有问题。我遇到过一个 bug,就是因为重试次数耗尽才报 ERROR,但旁人只看了 ERROR 消息,没注意到前面的重试记录。

常见日志格式:看懂每一行

你在不同地方看到的日志格式五花八门,但万变不离其宗。常见的有三种:

格式 示例 优缺点
标准文本
(SLF4J/Log4j)
2025-03-28 14:23:45.678 [main] ERROR com.my.SearchService - timeout 人眼可读,但解析困难,字段靠空格分隔
JSON 结构化
(Logstash/Flume)
{"time":"2025-03-28T14:23:45.678","level":"ERROR","thread":"main","class":"com.my.SearchService","message":"timeout"}
机器解析友好,可灵活加字段,但阅读性稍差
自定义格式 [2025-03-28 14:23:45] E [SearchService] query failed, requestId=abc123 团队约定即可,但工具支持不统一

我个人更推荐 JSON 格式。为什么呢?因为可以用 jq 命令直接过滤,比如 jq 'select(.level=="ERROR" and .message | test("decrypt"))'。一条命令就把所有解密相关的错误日志拎出来,快得很。传统文本格式你要用 awk、grep 组合,写起来麻烦还容易漏。

不过话说回来,格式只是皮囊,真正要看的是里边的字段。不管什么格式,只要你能快速提取上面说的那几个关键字段,就够用了。

日志分析流程:怎么快速定位

光说不练假把式。我总结了一个简单流程,配合下面的图更方便理解:

  1. 按级别过滤 —— 先 grep ERROR/FATAL,没有就去掉级别看 WARN。
  2. 按时间范围切片 —— 选问题发生前后10分钟的日志。
  3. 按请求ID或线程名分组 —— 找到属于同一个请求的所有日志。
  4. 从下往上读异常堆栈 —— 看到第一行自己写的代码。
  5. 对照上下游日志 —— 如果涉及 RPC,翻调用链,看对端返回了什么。

这个流程我用了好几年,基本没翻过车。下图展示的就是这个逻辑:

日志分析流程 原始日志 级别筛选 时间切片 请求ID/线程分组 异常堆栈分析 上下游对照 先找ERROR/FATAL 减少无用信息量 定位精确时间段 避免跨天滑动 异常堆栈从下往上看 找到业务代码入口

按这个流程走,基本上不会漏掉关键线索。我在处理一个密文检索超时问题时,就是靠时间切片,发现每天凌晨2:03准时 ERROR——后来排查到是定时任务导致缓存失效,同时大量查询涌入。没有时间切片,这问题可能要查一两天。

核心总结:日志分析不是靠眼力,是靠方法。掌握级别过滤、关键字段提取、格式适配三步,再配上上面的流程,绝大多数密文检索问题都能在15分钟内定位。不信你下次遇到问题试试,保证比硬翻快得多。