设想一个场景:十年前排查线上问题,第一反应是ssh登到机器上,cd到/var/log,tail -f或者grep一把梭。今天大家遇到故障,多半是打开日志平台,输入关键字、选好时间范围,几秒钟出结果。这种变化背后,是整个日志体系在采集、传输、存储、分析、治理几个层面的十年演进。这篇文章不聊虚的,只讲这十年里日志技术栈怎么变、如今的采集链路怎么搭稳、日志满了怎么清、排查问题有哪些实用套路,以及这些年我自己踩过的坑和总结的操作经验。无论你是运维、后端、测试还是安全相关岗位,只要日常跟日志打交道,这篇内容应该都能给你一些直接能用的东西。
1. 日志体系这十年:从“翻文件”到“可观测性”
1.1 单机时代:日志就是一堆没人管的文本文件
十年前大部分项目的日志策略非常简单:应用在服务器上往本地文件写日志,运维靠logrotate做轮转,排查问题靠人肉登录。我还记得当时为了查一个接口偶发报错,先后登录了六台应用服务器,挨个grep ERROR /opt/app/log/xxx.log | tail -1000,靠肉眼对比时间点附近的上下文。运气好半小时搞定,运气不好日志轮转了或者被覆盖了,就只能猜。
那个时代的主要矛盾是:日志只有一份,却要满足所有人的排查需求。后端要看、运维要看、偶尔测试也得看。文件权限、磁盘空间、日志格式,没人统一管。最惨的一次是某个服务写日志写得太疯狂,半天把磁盘写满,应用直接挂掉。当时处理方式也粗暴:删log文件,重启应用。但删完发现进程还占着文件句柄,磁盘空间根本释放不了,只能先kill再重启。
这些痛点逼着大家往两个方向想:一是能不能让日志集中存放,二是能不能让日志别再成为事故的源头。前者催生了集中日志方案,后者催生了后面完善日志治理的执念。
1.2 集中采集时代:syslog-ng 这类服务成了标配
日志集中化最早大规模落地的方式,就是syslog。Linux服务器、网络交换机、防火墙设备大多原生支持syslog协议,只要配一个中央日志服务器,设备把日志通过UDP或TCP发过去就行。我记得当时用syslog-ng搭交换机日志服务,配置不算复杂,但有个很实际的坑:UDP默认不保证可靠,网络抖动就会丢日志,后来全改成TCP传输才稳定下来。
syslog-ng相对rsyslog,优势在于过滤规则灵活、支持多目标转发,在日志量不大、格式以文本为主的时代非常合适。那时候所谓“日志分析”,基本就是日志服务器上grep + awk + sort三件套,按IP、按时间、按关键字统计。做安全审计时,把交换机日志、防火墙日志、服务器登录日志集中到一起,出问题好歹有地方查了。
但集中采集只是第一步,格式不统一的问题很快暴露出来:同一个时间字段,有人写2025-01-01 12:00:00,有人写01/Jan/2025:12:00:00 +0800;IP格式、URL转义、状态码含义各有各的写法。纯文本时代,分析靠肉眼和正则,效率很低。这也为后面全文检索引擎的入场埋下了伏笔。
1.3 存储与分析演进:从文本文件到搜索引擎再到列式存储
集中日志之后,检索需求越来越强。ELK(Elasticsearch + Logstash + Kibana)在那个时间点出现,几乎是精准踩中了痛点:Logstash做采集解析,Elasticsearch做全文索引,Kibana做可视化。第一次用Kibana输入一个关键字、几分钟出结果的体验,确实比登录几十台机器grep舒服太多。
再往后,ClickHouse和Loki两个方向也发展起来。ClickHouse用列式存储和SQL语法处理海量日志,查询分析能力极强,适合对时序日志做聚合统计。Loki则另辟蹊径,只存索引不存原文,日志原文留在压缩文件里,配合标签检索,成本低很多。到了这个阶段,日志已经不只是“排障用的文本”,而是和指标、链路追踪并列的可观测性三大支柱之一。日志要能回答的问题也从“出了什么错”扩展到“为什么慢”、“哪里异常”、“用户行为路径是什么”,存储和查询引擎也随之分化。
2. 采集链路怎么搭才稳:filebeat 实战与避坑
2.1 选型逻辑:为什么轻量采集端逐渐成为主流
说到现在的日志采集,绕不开两个名字:Logstash和Filebeat。早期ELK方案里大家喜欢全用Logstash:部署一个采集端,filter里做正则解析、字段切分,输出到ES。用过的人都知道Logstash能吃资源,默认堆内存512MB起步,业务稍微复杂能吃到1GB以上。在每台业务机器上都部署Logstash,成本实在高。
Filebeat的思路完全不同:它是一个极轻量的采集Agent,常驻内存大概几十MB,只负责读文件、把内容原样或简单处理后转发出去,不做重解析。所以现在的主流架构基本是:Filebeat采集文件 -> 发到Kafka/RabbitMQ缓冲 -> 后端的Logstash或Fluentd做解析 -> 写入ES或ClickHouse。好处很直观:业务机上只放一个低消耗的采集端,解析逻辑集中到管道后端,出了问题方便统一修改。
从热词里还能看到不少人在搜“filebeat日志采集”,确实很多团队正在从“自己写脚本收集日志”切换到Filebeat。我的建议是,单机日志量不大、团队没有专门日志平台的时候,直接上Filebeat加一个ES就能跑;如果每天日志量上亿条,再考虑引入Kafka缓冲和ClickHouse。
2.2 Filebeat 配置实操:多行合并与输出链路
Filebeat的核心配置文件filebeat.yml,最基础的部分是input和output。下面这个配置是我在实际项目里用得比较顺手的简化版:
filebeat.inputs: - type: log enabled: true paths: - /data/app/logs/*.log fields: app: payment-service env: prod fields_under_root: true multiline: pattern: '^\d{4}-\d{2}-\d{2}' negate: true match: after timeout: 5s output.kafka: hosts: ["kafka1:9092", "kafka2:9092"] topic: "app-logs" partition.round_robin: reachable_only: true required_acks: 1这里最值得展开的是multiline配置。Java异常栈、Python的Traceback都是多行日志,如果按行拆开采集,一条报错会被拆成十几条碎片,后期检索非常痛苦。上例的pattern表示“一条新日志以日期开头”,negate: true表示不匹配该模式的行不算新日志,match: after则是把不匹配的行合并到上一条日志后面。timeout参数也很关键,设置了5秒,防止最后一条日志迟迟等不来后续行导致缓存不释放。这里踩过的坑是:如果日志里在同一行内恰好有异常栈的关键字,正则会误判,所以尽量用日志行首的可疑时间戳做断行标记。
output到Kafka时,required_acks: 1配合Kafka可以做到写入不丢。如果直接输出到ES,可以这样:
output.elasticsearch: hosts: ["es1:9200", "es2:9200"] index: "app-logs-%{+yyyy.MM.dd}"索引按天分,方便按日期删除和迁移,也是我一直推荐的惯例。
2.3 采集可靠性:Filebeat的注册表机制与丢日志的真相
Filebeat最让我放心的一点是它维护了一个registry文件,记录了每个日志文件当前读到的偏移量。采集端重启后,它会按registry记录的offset继续读,而不是从头重新发一遍。所以正常情况下,Filebeat能做到at-least-once语义:日志不丢,但可能重复。重复的问题由下游去重或通过写入时的时间戳+ID处理。
配置里容易忽略的参数有两个。一个是queue.mem.events,控制内存队列中可缓存事件数,默认4096。日志量突然飙升时,如果输出端Kafka或ES撑不住,事件会积压在内存队列,积压太多可能触发背压或丢弃。另一个是close_inactive,默认5分钟,意思是文件超过5分钟没有新日志就关闭读取句柄。这个参数对长尾日志服务很关键,但设置太短可能在高频小日志场景下频繁开关文件。我通常保留默认值,只有对“低频但必须及时采集”的日志,才调小到1分钟。
我遇到过一个真实事故:某服务重启后把之前日志文件轮转了,Filebeat这边的路径正则*.log同时匹配到了轮转文件和新文件,结果同一条日志被两个input读到,均匀发到ES导致索引里数据翻倍。排查半天才反应过来,是路径通配符写得太宽。后来统一改成明确的主日志文件名,比如app.log,轮转文件放子目录,问题就没再出现。这类细节在官方文档里不太会被强调,但实际运维中很重要。
3. 日志分析和检索:从抓耳挠腮的 grep 到类 SQL 查询
3.1 检索工具选型:Elasticsearch、Loki 与 ClickHouse 怎么选
日志存下来之后,检索体验直接决定这套系统是“好用”还是“没人用”。目前主流的三类方案各有定位。
Elasticsearch是全文检索之王,Kibana里写KQL查关键字极其顺手,适合“根据某个关键字从海量日志中找相关记录”这类场景。缺点是索引开销大,存储成本高,热数据一多就要上冷热分层。
ClickHouse是分析型数据库,适合对日志做聚合统计,比如“统计每个接口过去24小时的错误率趋势”、“统计某IP的访问次数”。写SQL比KQL更灵活,基于列存储的压缩比也让成本低很多。缺点是点查单条日志的场景不如ES直观。
Loki是轻量方案,只索引标签,不索引日志内容,日志原文长期存对象存储。成本最低,适合K8s环境里容器日志的快速检索,但对内容全文搜索会很慢。选择逻辑可以简化成:预算充足、重检索选ES;重统计分析选ClickHouse;追求低成本、只按标签过滤选Loki。
3.2 MySQL 慢查询日志:定位慢SQL的完整操作
热搜词里“慢查询日志”出现频率很高,实际操作中很多后端同学对慢查询日志又爱又恨。MySQL开慢查询日志有两种方式:临时开关和写配置文件。
临时开启只对当前会话有效,适合应急:
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2; SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';要长期生效,需要在my.cnf里配置:
slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 2 log_queries_not_using_indexes = 1long_query_time = 2表示超过2秒的SQL才记录,单位是秒,支持小数。log_queries_not_using_indexes建议打开,很多全表扫描的SQL单次执行可能很快,但频繁执行就是灾难。分析慢查询文件,我习惯先用自带的mysqldumpslow做粗筛:
mysqldumpslow -t 10 /var/log/mysql/mysql-slow.log这个命令按执行时间列出top10。如果需要更细的维度统计,比如同一类SQL的累计执行次数、锁等待时间,用pt-query-digest更好:
pt-query-digest /var/log/mysql/mysql-slow.log > slow_report.txt一个常见的坑是:log_queries_not_using_indexes会记录很多低耗时但没走索引的SQL,慢查询文件膨胀得极快,必须配好轮转和保留天数。
3.3 xxl-job 日志怎么检索:调度日志与执行日志的区别
用xxl-job做分布式任务调度的团队很多,搜索“xxljob日志如何检索”的频率也高。xxl-job的日志分两层:第一层是调度中心的调度日志,记录任务触发时间、调度结果、执行器返回信息,在xxl-job后台“调度日志”页面能看到,支持按Job ID、触发时间查询。第二层是执行器端的执行日志,记录任务内部代码打出的日志,后台在“调度日志-操作-执行日志”里也能看到,但底层其实是执行器把日志文件内容上传回调度中心。
实操时要留意的点是:执行器日志的保存路径由xxl.job.executor.logpath指定。如果执行器所在机器磁盘紧张,厚厚的任务日志也会成为隐患。xxl-job后台有自动清理过期日志的功能,建议按“保留最近7天”来配。检索方面,如果调度日志查不到内容,先确认执行器是否正常注册,再看执行器机器上的logback/Log4j配置是否被覆盖,禁用掉了xxl-job的日志文件输出。这个问题我排查过两次,最终都定位到是负责的同事自定义了logback配置,把xxl.job.executor.logpath指向的目录漏掉了。
3.4 adb logcat 抓日志与 uvicorn 日志丢失问题
移动端定位问题,adb logcat是绕不开的工具。几个高频操作:
# 按时间格式打印全部日志 adb logcat -v time # 过滤指定TAG adb logcat -v time -s TAG_NAME:D # 抓取崩溃日志 adb logcat -b crash -v time # 同时输出到文件,方便后续分析 adb logcat -v time > logcat.log # 清空日志缓冲区,便于复现后重抓 adb logcat -c注意-v time只是显示格式,真正过滤要靠-s加TAG和优先级。实测中,抓系统级问题(比如蓝牙、Wi-Fi)要先清除缓冲区再复现,否则混入大量旧日志干扰判断。另外日志缓冲区大小有限,不同厂商默认值也不一样,遇到日志被截断的情况,可以加大缓冲:
adb logcat -G 64M后端方向,FastAPI搭配Uvicorn的部署模式很流行,但“uvicorn fastapi日志丢失”这个痛点也很典型。默认情况下Uvicorn会打印自己的access log和ERROR log,但如果你的业务代码里用了Python的logging模块,通过logging.getLogger("uvicorn")拿到logger,不配置handler、不设置level,输出就可能丢失。正确姿势是在启动入口统一配置:
import logging import uvicorn logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s" ) logger = logging.getLogger("app")关键点有三个:一是basicConfig要放在logger使用之前执行,否则配置不生效;二是业务logger的name不要和uvicorn重复,避免传播链混乱;三是尤其要检查propagate属性,子logger默认会把日志向上传播到根logger,如果某处设了propagate = False同时又没挂handler,日志就会在黑洞里消失。这类问题不能说Uvicorn有bug,更多是Python logging配置习惯不严谨积累出来的。
4. 日志清理与空间治理:系统日志、binlog、数据库日志一次讲清
4.1 磁盘总是被打满:我见过最常见的四种死法
日志导致磁盘打满,基本逃不出四种情况:第一,应用日志文件夹没有任何轮转策略,单个文件无限增长;第二,logrotate配置写了但权限不正确,轮转根本没执行;第三,应用代码在异常分支里疯狂写日志,死循环一般地输出;第四,数据库开着slow log或者audit log,文件增长又快又猛。
印象最深的一次,是某服务在极端场景下进入“ERROR -> 重试 -> 再ERROR”的循环,日志正确率极高,每小时写出5GB文本文件。那台机器60GB数据盘两天就被填满。事后检查,logrotate配了,但文件属主和应用进程不同,每天轮转时因权限报错,应用因为文件被占用的问题轮转也一直失败。所以我现在定了一条规矩:任何日志清理策略上线后,必须第二天人工确认一次轮转结果,看昨天的归档文件是否真的生成了。
4.2 Linux系统日志清理:journalctl 与 logrotate 的正确用法
如果系统用的是systemd,日志会统一进journal。查看占用空间和执行清理是高频操作:
journalctl --disk-usage journalctl --vacuum-size=500M journalctl --vacuum-time=7d更合理的做法是改journald配置文件,限制上限,避免每次手工来一次:
# /etc/systemd/journald.conf SystemMaxUse=500M MaxRetentionSec=7day改完记得重启服务:
sudo systemctl restart systemd-journald传统/var/log下的文件清理,重点看logrotate配置。以应用日志为例:
/data/app/logs/app.log { daily rotate 14 compress missingok notifempty copytruncate }copytruncate这个选项值得多说一句:它先复制日志文件再清空原文件,应用进程不需要重新打开文件句柄。代价是复制和清空之间可能有少量日志丢失。对日志强一致性有要求的场景,可以用create方案加SIGHUP通知应用重新打开日志文件,但前提是应用支持。compress选项建议开着,文本日志压缩率很高,能省一多半空间。
热搜词里还有“Linux清空日志log命令”,这个要看清楚,直接> /var/log/xxx.log虽然能腾空间,但进程持有句柄时,空间不会真的释放。正确做法是logrotate或者找到持有句柄的进程重启/重载。用lsof | grep deleted能找出被删除但仍占用空间的日志文件,这个命令在排查空间问题时要常用。
4.3 binlog 日志可以删除吗?先说结论再给方案
MySQL的binlog是二进制日志,作用有两个:主从复制和基于时间点的数据恢复。所以“binlog日志可以删除吗”这个问题,答案是不能直接删文件,但必须制定清理策略。
最省心的方式是配置自动过期:
expire_logs_days = 7 # MySQL 8.0及以上推荐用秒配置 binlog_expire_logs_seconds = 604800需要手动清理时,用SQL命令而不是rm:
-- 删除某个binlog文件之前的日志 PURGE BINARY LOGS TO 'mysql-bin.000012'; -- 删除某个时间点之前的日志 PURGE BINARY LOGS BEFORE '2025-01-01 00:00:00';这里有个特别重要的避坑点:执行PURGE之前,先确认从库的同步状态。如果主库清理了从库还没拉取的binlog,从库就会中断复制且无法恢复。查询方法是:
SHOW SLAVE STATUS\G;重点看Master_Log_File和Read_Master_Log_Pos,确保要清理的位置小于从库已经拉取的位置。另外,binlog文件占空间太多时,先检查是不是有长事务没提交。长事务会阻止binlog purge让文件堆积,这个比单纯清理更值得关注。
4.4 SQL Server 日志文件过大与 Oracle 监听日志清理
SQL Server的日志文件(.ldf)过大,本质上是因为事务日志没有及时备份被截断。SQL Server 2008上经典处理是:
USE your_db; BACKUP LOG your_db WITH TRUNCATE_ONLY; DBCC SHRINKFILE (your_db_log, 1);但新版SQL Server已经移除了TRUNCATE_ONLY,更标准的做法是:先做一次完整备份,然后单独备份事务日志,再收缩。恢复模式改成“简单”可以避免日志无限增长,但会牺牲时间点恢复能力,生产环境要谨慎评估。
Oracle的监听日志是另一个常见的空间杀手,监听日志文件listener.log在Oracle 10g之后默认启用,只增不减。清理前可以临时关闭日志记录,避免再写入:
lsnrctl set log_status off然后删除或清空log文件,再开回来:
lsnrctl set log_status onOracle的ADR诊断目录(diag目录)下trace文件夹里会积累海量trc文件,也建议配合定时任务按天数清理:
find /u01/app/oracle/diag -name "*.trc" -mtime +30 -delete4.5 Windows 事件日志、蓝屏日志与移动端蓝牙日志
Windows下查日志最常见的是事件查看器,但命令行方式更适合批量操作。设置事件日志保留上限和天数,用wevtutil:
wevtutil sl Application /rt:true /ab:true /ms:20480000其中/ms指定日志文件最大字节数,比如20480000约20MB。/rt和/ab分别表示“按时间保留”和“按字节保留”,两者同时开启时,系统会以先达到的条件为准。
蓝屏日志是排查莫名死机的关键,热搜词里“电脑莫名关机”“蓝屏日志在哪里看”都是常见诉求。Windows蓝屏后一般有两个地方留痕迹:一是在%SystemRoot%\MINIDUMP目录下的小内存转储文件(比如Mini091234-01.dmp),二是在事件查看器里看“系统”日志里的事件ID 41(Kernel-Power)和6008(意外关机)、BugCheck事件。拿到dmp文件后,用WinDbg打开,执行!analyze -v可以看到崩溃的具体驱动和堆栈。对于普通用户,至少可以先在事件查看器中确认蓝屏代码,再到微软官网查对应的BugCheck解释。
移动端日志方面,热搜词里的“realme 7蓝牙日志”这类问题,通用解法是:开发者选项里打开“蓝牙HCI日志”开关,抓取HCI日志;同时用adb logcat -s Bluetooth过滤蓝牙模块的日志。这类日志对于分析蓝牙连接不稳、配对失败很管用,但不同厂商开关位置不完全一样,大体都在开发者选项的“调试”分类下。
5. 日志溯源与安全应急:登录日志、异常关机与攻击处置
5.1 Ubuntu 下通过 auth.log 做登录溯源
安全应急场景下,最常查的就是登录日志。Ubuntu系统里/var/log/auth.log记录了所有认证相关事件,包括ssh登录、sudo授权、用户新增。要溯源某个用户(比如输入里提到的“mage”)的登录历史,可以这样:
grep "mage" /var/log/auth.log | grep "Accepted" grep "mage" /var/log/auth.log | grep "Failed"Accepted password for mage表示该用户的成功登录,Failed password for mage表示失败尝试。只看这两类还不够,系统级用户登录历史还可以用:
last -a lastlog who /var/log/wtmp/var/log/wtmp存的是成功登录的历史,/var/log/btmp存的是失败登录的历史。如果怀疑用户被创建为后门,还要查:
grep "useradd" /var/log/auth.log grep "sudo: mage" /var/log/auth.logsudo记录同样重要,能看到该用户执行过哪些特权命令。有一次排查被入侵的机器,就是靠auth.log里的sudo记录发现异常时间段执行了/etc/shadow读取命令。这个思路值得记下来:日志溯源不能只盯着成功登录,还要连带看登录后执行了哪些操作。
5.2 Windows 异常关机与安全日志排查
Windows“电脑莫名关机”的原因大致分三类:硬件电源问题、驱动崩溃导致蓝屏、系统更新或计划任务触发的重启。排查时先看事件查看器“系统”日志,重点筛选几个事件ID:
| 事件ID | 含义 | 常见说明 |
|---|---|---|
| 41 | Kernel-Power | 系统异常断电/崩溃,未正常关机 |
| 6008 | 意外关机 | 上次关机是意外的 |
| 1001 | BugCheck | 蓝屏事件,关联dmp文件 |
| 1074 | 系统关机/重启 | 记录了哪个进程或用户触发的 |
结合这几个事件和蓝屏dmp文件,基本能判断是硬件还是驱动层面。如果4624登录事件暴增且指定账户多次,那就是另外的安全问题了,需要检查安全日志。
Windows安全日志里,登录成功和失败对应事件ID分别为4624和4625。导出安全日志配合分析,管理员权限下可以:
wevtutil epl Security C:\tmp\sec.evtx拿到evtx文件后,再用事件查看器或工具分析。日常排查时,我习惯用PowerShell快速统计失败登录次数最多的账户:
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625} -MaxEvents 1000 | Group-Object #{Message} | Sort-Object Count -Descending | Select-Object -First 10安全日志保留天数也可以通过wevtutil sl Security /rt:true /ms:104857600这类方式调整,建议生产环境至少保留90天,便于攻击溯源。
5.3 针对恶意域名攻击的日志溯源与处置流程
如果系统遭受恶意域名引发的持续攻击,处置不能只靠封IP,要建立完整流程。结合输入里的场景,我把一个相对完整的处置路径整理如下:
第一步是确认和阻断。在网络层,把恶意域名在DNS过滤设备、防火墙上加入黑名单,禁止内网设备解析和访问;在主机层,通过hosts文件或者安全Agent禁止域名解析,同时更新防火墙出站规则。这一步要快,先止血。
第二步是寻找攻击痕迹。通过日志溯源判断攻击入口。主要看几类日志:Web访问日志中访问该恶意域名的记录、DNS解析日志中内网设备对该域名的解析记录、防火墙会话日志里与该域名IP的通信记录、应用日志里可疑的菜刀/命令执行特征。溯源思路是“由域名到IP,由IP到会话,由会话到进程,由进程到文件”。
第三步是加固和防御升级。WAF/IDS规则要做到针对该恶意域名的C2通信特征做正则匹配和封锁,主机侧清理可疑启动项、计划任务、Webshell文件。这里要特别强调的是:攻击者往往会留后门,只删Webshell不找后门等于白搞。要排查持久化痕迹,比如新增用户、新增SSH公钥、异常服务、计划任务。
第四步是长期监控。恶意域名攻击经常反复出现,处置完后要建立专项监控规则,持续检测同类域名注册、相同通讯特征、类似攻击路径。定期复盘日志,确认是否还有漏网流量。日志留存时间要足够长,最好与安全事件响应要求对齐。整个过程必须记录完整处置台账,包括时间、域名、IP、处置动作和负责人员,这对后期复盘是不可或缺的证据链。
5.4 日志驱动的 AI 根因定位:什么条件才不是空谈
近两年越来越多的团队尝试用AI从海量日志中做根因定位。但这类方案落地的前提,是把日志质量做到位。至少需要三样东西:一是日志结构化,不能一坨文本,要有明确的字段比如timestamp、trace_id、level、service、message;二是链路关联,通过trace_id把一次请求在多台机器上的日志串起来,否则AI分析出再多元凶也无从串联;三是基线数据,AI需要知道“正常长什么样”,才能判断当前的异常是不是根因。
另外,日志量越大,“AI根因定位”越有价值,但也不能指望模型直接给答案。比较现实的做法是:先用聚类算法把相似异常日志聚成几类,再按时间线、影响范围、异常分数排序,给人工排查缩小范围。这个思路在硬件验证领域有人用UVM日志来做,在服务端可观测性领域也有类似实践。它不替代人,而是把人从“面对几百万行日志逐条grep”变成“看十几条聚类的异常摘要”,效率提升是很实在的。
6. 日志治理的几条底线与个人经验
6.1 日志轮转、保留与告警:先定策略再写代码
日志治理这件事,本质上是给日志定规矩。我的底线建议是三条:第一,所有日志文件必须有轮转策略,要么logrotate要么框架级别的滚动,不允许出现无限增长的日志文件;第二,必须有保留周期和配套清理,按天分片的索引、按时长的journal、按文件数的rotate,至少要有一层兜底清理;第三,磁盘使用率和日志采集状态必须纳入监控告警。
落到实处时,有几个容易被忽视的细节:logrotate配置里su root adm这种权限指令要加上,避免 cron 轮转时因权限失败;journald 的SystemMaxUse要实际生效,而不是只改不改;Filebeat的registry文件要纳入备份范围,一旦逻辑盘损坏,registry丢失会导致采集断点错乱;多实例应用日志必须带上实例标识和trace_id,否则排查时不同机器日志根本无法关联。
6.2 这些年实操下来最想提醒新人的三件事
第一件事,日志的时间字段一定要带时区并且统一成标准格式。混用本地时间和UTC、字符串和时间戳,会让任何后续分析都变成灾难。我现在写日志规范时,第一行就是“所有时间统一ISO8601,带时区偏移”。
第二件事,日志不是写给别人看的,是写给未来的自己排查用的。关键日志不要惜字如金,上下文信息,比如请求ID、用户ID、参数摘要、耗时,尽量都打出来。但敏感数据别打,手机号、身份证、密码绝不能进日志,这是安全底线。
第三件事,日志系统本身也要监控。我见过太多人把日志平台搭完就撒手不管,等到磁盘满了才发现采集早就停了,什么日志都没留下。给日志平台所在的磁盘、ES分片健康状态、Filebeat运行状态都配好告警,比给业务日志写一万条日志规范都管用。
最后分享一个小技巧:我每到一个新环境,第一件事就是检查每天的日志是否真的成功轮转,以及日志目录的磁盘占用变化趋势。这个习惯帮我避开了至少十次“日志把磁盘写满”的隐患。日志这个事,从来没有“配好就不用管”的时候,它需要像对待核心数据一样持续关注。