日志十年演进:从单机grep排障到全链路可观测
发布时间:2026/10/7 17:04:14 作者:尧图编辑部 阅读量:1,286

我刚工作那年带我的老工程师交给我一台旧服务器的账号第一句话不是“先读业务文档”而是“你先把 /var/log/messages 从头到尾翻一遍”。那天下午我对着满屏重复的字符串发了四个小时呆也是从那天起我发现自己和日志的关系注定要比跟业务代码长得多。十来年过去日志从磁盘上的一组文本文件变成了采集器、消息队列、搜索引擎、链路追踪、成本治理甚至 AI 分析的对象。我经历过手工 grep 一台机器排障的年代也踩过 Filebeat 丢日志、ES 磁盘暴涨、SQL Server 日志文件几十个 GB 清不掉的坑最近两年又开始研究怎么让结构化日志和 traceId 贯穿所有服务。这篇文章就是以“日志”为主题的十年回顾适合刚入行的后端、运维、测试同学也适合正在为全链路日志方案发愁的团队。我不会按教科书顺序讲只讲这些年我真实踩过、真实用过、真实想明白的东西。1. 十年前我眼里的日志一台服务器就等于一堆文本文件1.1 那个年代的日志都装在哪里2014 年左右的服务器日志几乎没有统一标准。Linux 上无非是 /var/log/messages、/var/log/syslog、/var/log/secure应用自己写的日志就看心情有的在 /opt/app/logs 下按月分目录有的直接往 stdout 打印后靠 nohup 重定向到文件。Web 服务器更典型nginx 的 access.log 和 error.log 是独立的MySQL 也有自己的 error log而 Redis 默认情况下压根不写文件直接输出到 stdout你要是没做重定向重启一次所有日志人间蒸发。你要是问 dlt 日志文件怎么查看内容那个年代同样冷门且麻烦——汽车电子领域常见的一种日志格式得用专门的解析工具读普通文本编辑器打开就是一串带格式的二进制头。包括 Windows 那头要么开事件查看器要么翻 Minidump。总之所有日志都散落在各自的角落里像一屋子没贴标签的抽屉你得凭记忆记住“哪类问题该开哪个抽屉”。这期间还有个很经典的场景就是临时抓会话日志。用 screen 开个长任务怕窗口关了丢输出于是加个screen -L参数让它自动落盘用 SecureCRT 远程操作设备顺手在会话选项里把“日志文件”打开收工后整个操作过程就能导出一份文本。这虽然不优雅但已经是当时普通工程师能用的“日志持久化”方案了。移动开发那头大家用 adb logcat 抓 Android 日志一个 logcat 能同时看到系统、内核和应用日志比 Linux 服务器还要集中一些。1.2 人肉排查大法cat、tail、grep 与管道那会儿排障的标准动作就三板斧先tail -f盯实时输出出了问题用grep -i error xxx.log搜关键词实在找不到就cat -n把整个文件打到屏幕上人肉扫描。有人图省事直接在终端里cat一个几百 MB 的日志文件结果就是终端被刷了几万行。后来大家渐渐学乖了开始用less分页、用grep -n -A 5 -B 5看错误上下文再往后学会了awk统计错误次数、sort | uniq -c数来源 IP。这套方法在那个机器数量 10 台以内、日志量每天几百 MB 的时代其实完全够用。有个很容易被忽视的细节是 cron 日志。很多人以为 crontab 任务执行失败没日志可查其实要么在 /var/log/cron 里有调度记录要么任务的 stdout 输出会被系统通过邮件发给 root。你如果一直没配邮件环境这些输出就会堆积在 /var/spool/mail 里直到某天磁盘告警才发现罪魁祸首是几百 MB 的杂耍输出。正确做法是给每个 cron 任务加上 /tmp/xxx.log 21或者干脆 /dev/null 21让输出有明确去处别让系统替你“收邮件”。踩过这个坑之后我才明白日志落地不是自动发生的得有人明确告诉系统“这些输出存在哪”。1.3 从“临阵磨枪”到“持续留痕”的转折真正让我意识到日志必须提前设计是一次半夜处理线上故障。有个任务每天凌晨跑批凌晨三点客户投诉数据不对我登录服务器发现该任务根本没往任何文件里写日志因为没有重定向所有输出随进程退出全丢光了。我第一次感受到什么叫“日志黑洞”系统没有日志排障就变成了猜测。从那开始我给所有关键脚本和进程都补上了日志输出和文件轮转哪怕只是一个简单的日期分割。后来看到 Visual Studio 的调试信息保存到日志文档同时打印显示、uniapp 在真机上不打印日志信息这类问题我都特别理解——开发环境随手能看到的输出到了生产或打包后不一定还在日志链路必须显式设计不能依赖默认行为。也正是在这个阶段我养成了一条写日志的基本准则日志是给未来的排查者写的不是给现在的控制台看的。2. 集中式采集让日志真正“汇流成河”2.1 Filebeat 这类采集器到底解决了什么服务器从 10 台变成 50 台之后最痛苦的不是日志变大而是“查一遍日志”这个动作的成本变了。以前一台机器ssh 进去 grep 三分钟能出结论现在 50 台机器你得先想清楚去哪台查然后一台一台登进去效率极低。所以我理解中集中式日志的核心价值不是“把日志存到一个地方”而是把“搜索所有服务器日志”的时间从小时级降到秒级。Filebeat 这类轻量采集器就是在那个背景下流行起来的。它的核心机制并不复杂每个文件有一个 harvester 在逐行读取读到的位置由内部 registry 文件记录即使 agent 重启也能从上次的偏移量继续读。更重要的是它能感知文件轮转比如日志系统按小时把 xxx.log 切成 xxx.log.20240101-12采集器会在轮转后自动切换到新文件不会漏读也不会把旧文件重新读一遍。这个能力是很多人忽略的关键——如果你在自己的业务代码里手工维护“上次读到哪一行”基本都会在文件轮转、进程重启之后出现重复采集或漏采。采集这种脏活就该让专业采集器干。2.2 采集链路的“三级火箭”设计当年我直接让 Filebeat 把日志送到 Elasticsearch结果日志一多ES 写入扛不住甚至出现采集器把数据吐过去但 ES 拒绝服务的现象。后来逐渐改成标准的“三级火箭”采集端Filebeat 类 agent→ 缓冲队列Kafka→ 消费索引Logstash ES。很多人觉得中间加一层 Kafka 是过度设计但日志流量的特点就是明显的波峰波谷。白天业务高峰每秒几千条请求日志凌晨可能跌到几十条如果没有缓冲削峰ES 的写入线程要么长期闲置要么瞬间被打满 OOM。加入消息队列后采集端只管发送索引端按自己的节奏消费即使下游短时间内故障日志最多在队列里积压不会直接丢失。这阶段还容易踩一个反直觉的坑多行日志的合并。Java 抛异常时堆栈会跨多行如果采集器简单按行发送一条异常就会被拆成几十条“孤儿日志”到了 ES 里想按堆栈搜索就全乱了。标准做法是在采集器里配置多行合并规则例如看到一行不是以时间戳开头的内容就把它和前一条合并成一个事件。这个配置在排查问题时不直接可见但影响巨大——没有它你的异常日志在检索系统里基本是废的。2.3 汇流之后检索和管理都变了日志汇到一个地方之后Nginx 访问日志在 Windows 上要怎么看、redis 日志去哪找这类问题就变成了“去 Kibana 或 Grafana Loki 里搜”。全文检索引擎按字段建倒排索引你输入一串关键词就能把几十台机器的相关日志全部捞出来这种体验上的跨越用过一次就回不去了。但我也很快发现集中采集只是第一步如果没人管“日志该存多久、哪些该采、哪些不该采”索引集群会以惊人速度膨胀。一台中等流量的 web 服务器每天产生的 access log 就能轻松上 GB50 台机器一个月就是 1.5TB 量级这不是普通团队随便扛得住的。于是日志治理的问题从“怎么采”变成了“怎么管”这直接决定了后面几年我对日志生命周期的理解。3. 从“能看见”到“能查出”结构化、TraceId 与日志面板3.1 非结构化日志的尽头是结构化日志在 ES 里做全文检索确实快但用一段时间就会碰到瓶颈日志全是自由文本想按接口路径聚合调用量、按状态码算错误率、按业务标识查某个用户的所有操作正则解析要么性能差要么匹配规则改一次崩一次。这就是为什么后来大家不约而同把日志从“给人看的散文”改成“给机器读的 JSON”。每一条日志带上时间戳、服务名、日志级别、traceId、业务字段检索效率提升了不止一个量级。这里的核心概念就是“日志作用域”。没有作用域的日志就像一堆没有主语的句子“更新失败”到底是谁更新失败哪个订单哪个用户哪个请求触发的一条日志如果回答不了这些问题它在排障时基本只能当背景噪音。所以我们后来给所有系统上了 traceId 或 request_id每进来一个外部请求就生成一个唯一 ID打印到所有关联日志里。排障时拿这个 ID 一查该请求在网关、服务 A、服务 B、数据库中间件里的全链路日志按时间排好序一次性拉出来效率提升不是一点半点。你可以把它理解成快递单号没有单号你的包裹和别人的混在一起根本无法追踪有了单号每一站记录都能串起来。3.2 框架层面的实践Spring AOP 记日志、FastAPI 日志丢失业务侧做统一日志最省事的方案是 Spring AOP。我做过一个模块自定义一个 OpLog 注解挂在 Controller 或 Service 方法上切面统一记录入参、出参、耗时和异常堆栈。好处很明显业务代码无侵入团队其他同事不需要理解日志规范只要加个注解就自动有日志。但坑也藏在里面入参里的密码、身份证号、手机号等敏感字段必须做脱敏否则日志平台本身就成了信息泄漏点高频接口如果每次把完整出入参打成 JSON日志量立刻翻几倍。我的建议是加注解时手动指定哪些字段要记录别傻傻全量打。Python 那边还有个典型问题uvicorn 跑 FastAPI日志莫名其妙丢失。我排查过几次根因往往是三类一是日志配置没有早于 uvicorn 启动前绑定导致 uvicorn 的 access log 还走它自己的 stderr handler二是多 worker 模式下每进程各自输出文件写入互相覆盖三是用了 queue handler 但没有启动后台 listener 线程日志在队列里积压到进程退出直接丢弃。正确做法是先关掉 uvicorn 自带的 access logaccess_logFalse统一交给标准 logging在多进程下用 QueueHandler QueueListener确保日志真正从内存队列写入落盘。这个问题非常典型因为不是“没有日志产生”而是日志链路在配置环节断掉了。移动端那边uniapp 在 release 包不打印日志信息也是这个逻辑——console 输出在打包时可能被裁剪得检查构建配置或直接抓 logcat。3.3 日志面板、任务日志检索与慢查询分析日志集中之后“看日志”不再靠终端面板成了日常入口。Kibana 适合做主搜索和聚合分析Grafana Loki 胜在轻量和与指标监控打通这两天团队里也还有人问“用什么 AI 工具能精准分析日志”我的回答通常是先让日志面板做好检索和统计再把结果交给 AI 总结。别指望 AI 直接生啃原始日志。具体到我经手的系统有两类日志检索需求值得单独说。一类是人社类任务调度比如 XXL-JOB 的任务日志。很多人问“xxljob 日志如何检索”其实调度平台里的“日志”只是执行记录列表真正的执行器日志还是在本机日志文件里。如果你没有把执行器日志接入统一日志平台那只能靠部署平台的历史记录检索基本靠肉眼。接入集中日志后拿 jobId 或任务实例 id 当成 traceId 用一次调度从触发到最终执行的全部输出就能完整捞出来。另一类是数据库慢查询日志。MySQL 开启 slow_query_log 后会在本地产生文件分析要么用 mysqldumpslow 要么用 pt-query-digest。很多人开了慢查询日志却不去看那日志就真的只是磁盘占用定期分析慢日志才能发现那些“单个执行没问题、并发多了就卡死”的 SQL。Redis 也有类似机制用SLOWLOG GET直接查命令延迟比抓日志文件更快。3.4 AI 日志分析能做什么不能做什么这两年 AI 日志分析被炒得很热我也实际试过。给大模型喂一段日志让它总结根因它的确能给出相对靠谱的方向假设尤其是遇到复杂堆栈或跨服务调用时能帮人节省不少阅读时间。但我的经验是AI 适合在“已结构化过滤后的日志子集”上做总结不适合直接在原始全量日志里大海捞针。流程应该是先用正则或日志平台的搜索把错误类型、时间段、相关 traceId 圈出来再把这些已经聚合过的结果交给 AI 生成分析摘要。另外一条底线带敏感字段的日志绝对不能原样送到外部模型最好自建或本地部署模型做脱敏后再分析。AI 的幻觉问题在日志分析场景也很致命它可能把无关字段联想成“潜在根因”所以它的角色是辅助人形成假设而不是替人下结论。4. 日志治理就是“管命”容量、保留期与数据库日志4.1 磁盘爆满的元凶大 LDF、监听日志与 cron 输出日志不治理最先爆的不是查询性能而是磁盘。这个话题的热度从十年前一直持续到现在SQL Server 2008 的日志文件过大怎么删除、Oracle 监听日志怎么清理、Linux 怎么清空日志都是经典热搜。先看 SQL Server。事务日志文件LDF无限膨胀的核心原因是数据库处于 FULL 恢复模式且长时间没有做事务日志备份。事务日志记录了所有增删改的细节不备份就不截断文件像滚雪球一样长大。这个阶段有个典型报错叫“该数据库不可以执行非日志模式的大容量复制请联系数据库所有者(dbo)”听着复杂本质就是恢复模式和相关权限限制了某些大容量操作。正确清理路径是先做一次完整备份和事务日志备份确认日志没有活动部分后再DBCC SHRINKFILE收缩物理文件同时调整备份计划避免再次膨胀。网上很多教程让你直接改成 SIMPLE 恢复模式然后收缩这在一次性救急时可以但对需要时间点恢复的生产库是有隐患的操作前必须权衡清楚。再看 Oracle 10g 监听日志。listener.log 会一直追加时间久了轻松上 GB。问题在于这个文件通常正被监听进程占用你直接rm掉文件句柄还在磁盘空间并不会立即释放最后只能重启监听动静很大。更稳的办法是通过日志轮转或者定期用truncate在“归档—清空”之间保持进程健康。Linux 同理清空一个正在被进程写着的日志文件正确命令是truncate -s 0 /var/log/xxx.log而不是rm因为 rm 后文件句柄还指向旧 inode空间不释放新日志还会继续写到那个“已删除但还被占用”的文件里等你发现磁盘满了再去排查那个文件已经被某个进程偷偷写了几个 GB。银河麒麟 v10 这类国产系统本质上还是 Linux 行为journald 的日志可以用journalctl --vacuum-size500M清理逻辑相同。4.2 哪些日志不能随便清binlog、安全日志与审计记录清日志之前先分清哪些是“垃圾”哪些是“证据”。MySQL 的 binlog 就是个典型。binlog 日志可以删除吗可以但要按数据库自己的规则删不能用 rm 直接删文件。binlog 承载了主从复制和基于时间点恢复的能力你随手删一个可能导致从库同步链路中断或者某次误删数据后没有回放依据。正确做法是设置自动过期策略比如binlog_expire_logs_seconds或者手动PURGE BINARY LOGS TO mysql-bin.000123把旧的批量清掉。手动清理前先确认当前从库已经消费到哪个日志别把从库还没读到的 binlog 清掉。Windows 安全日志也是一样。很多人问“windows 安全日志在哪看”默认在事件查看器的 Windows 日志 - 安全里记录登录成功/失败、文件对象访问等。但默认情况下Windows 安全日志的大小在 20MB 左右满了之后按策略可能覆盖旧事件。如果团队有安全合规要求建议通过 gpedit 设置“日志大小”和“保留天数”并且采用“按需覆盖事件”而不是“一旦满则停止”。文件操作日志则更特殊Windows 10 默认不记录谁改了哪个文件需要先在审核策略里开启“对象访问 - 文件系统”的审核并给具体目录加上审核条目之后的操作才会出现在安全日志里。所以答案反过来很残酷想查看文件操作日志第一步不是查日志而是先确认审核开没开。4.3 保留期策略与自动化日志不是越多越好日志生命周期管理本质是一张权衡表。不能一刀切“全部保留 180 天”也不能“能用就删出事就傻眼”。我现在的常规配置大致如下日志类型常见位置建议保留时长主要风险应用调试日志应用本地 / 采集平台7~30 天磁盘膨胀、检索变慢Web 访问日志nginx/logstash30~90 天容量大但可用于溯源数据库 binlogMySQL data 目录至少覆盖主从延迟窗口 3~7 天删除后无法恢复、复制中断SQL Server 事务日志LDF 文件配合备份节奏自动截断LDF 无限增长安全/审计日志Windows 安全日志90~180 天或按合规要求覆盖丢失即证据缺失业务操作日志应用数据库180 天以上追责时找不到记录自动化上Linux 建议用 logrotate 而不是自己写脚本。一个经典的 nginx 轮转配置是 daily 轮转、保留 30 份、压缩旧文件这样日志文件始终有边界。集中式日志平台里ES 的索引生命周期管理ILM则能根据索引大小或时间自动把旧索引切到冷存储甚至删除配合保留策略形成完整闭环。我自己踩过的最深坑是只配置了日志采集、没配置过期策略半年后 ES 集群磁盘使用率 98%节点全部变成只读导致业务日志再也写不进去。后来我才意识到日志平台的建设采集和清理必须第一天同时规划。5. 排障与溯源那些年我们查过的日志5.1 蓝屏、异常关机与“电脑莫名关机”的完整链路Windows 系统蓝屏之后绝大多数人的第一反应是找人修但如果是你自己管理的机器最该做的就是去看 C:\Windows\Minidump 下的 dmp 文件配合系统事件查看器里的事件 ID。蓝屏日志在哪里看核心其实是两个位置Minidump 里有蓝屏时的内存转储可以用 WinDbg 打开执行!analyze -v能直接定位到崩溃的驱动模块事件查看器里的系统日志会记录重启前的事件。而“电脑莫名关机”这类问题通常先盯 Event ID 41Kernel-Power它表示系统没有经过正常关机流程就断电或重启再配合 Event ID 6008 可以看见意外关机发生的时间。我之前遇到一台服务器半夜总重启排查下来发现是电源模块供电不稳系统事件里反复出现 41而日志本身并不能直接告诉你“电源坏了”它只给了你一个可靠的排查起点。手机端也一样Realme 7 的蓝牙日志要靠开发者模式抓 logcat安卓 DSU 开包进不了系统时多半能从 logcat 里看到超分区挂载失败的关键报错。日志在这些场景里很像飞机上的黑匣子它不阻止事故但让你快速缩小事故的原因范围。5.2 登录日志排查合法巡检自己的服务器日志在安全场景里最常见的用途是登录溯源但有一个前提只能查自己有权管理的机器。比如 Ubuntu 20.04 系统里要查看 /var/log/auth.log 中用户 mage 的成功登录记录直接执行grep Accepted /var/log/auth.log | grep mage能看到登录时间、来源 IP、认证方式想查失败尝试可以换Failed password关键词。Windows 一侧安全日志里 Event ID 4624 表示登录成功4625 表示登录失败通过事件查看器过滤 ID 就能定位异常登录尝试。我自己每月会做一次登录日志巡检重点观察“非常规时间段登录”“异常来源 IP”和“本地账户管理操作”这三类事件。这套方法配合开启审计策略的 Windows 文件操作日志就构成了最基本的运维审计能力。特别要强调这些动作的前提都是合法授权和正当维护日志是用于合规排障与审计的工具而不是绕过边界的手段。5.3 日志往哪走从排错工具到系统的一等公民写了这么多如果让我压缩成一句话我会说日志的地位已经彻底变了。十年前它是排错时的草稿纸现在它是系统的“实时证词”。业务系统的行为日志、安全日志、数据库日志、基础设施日志每一条都在为“当时发生了什么”作证。设计新系统时我会按“未来某天出事故我至少需要哪些日志才能定位”来反推架构而不是等功能上线后再补。至少要保证六要素齐全时间、节点、服务名、关键 ID请求/用户/订单、日志级别、消息正文。有了这六个字段绝大部分排障工作都能在可检索的范围内完成。最后分享一个我坚持了很多年的小习惯给所有重要日志模板加上一个测试用例每次改动日志格式后先确认“凭这条日志能否还原一次完整请求的生命周期”。如果答案是不能就说明日志设计还不完整。日志这东西平时没人夸你做得好事故时能不能靠它在一小时里定位问题才是唯一评判标准。这也是为什么我愿意花这么长篇幅把它从十年前讲到今天。