干运维和系统管理这些年,我越来越觉得日志系统才是故障排查的第一现场。很多时候你对着一个现象瞎猜半天,不如老老实实打开日志文件往前翻几页,线索自己就蹦出来了。日志系统看似只是“记录”,但真正会用的人能从一堆时间戳里还原出完整的事故链:谁在什么时候登录过、系统是正常关机还是被硬生生掐断的、哪个服务在崩溃前一秒写了什么遗言。这篇是系列的第13章,我把这些年用日志做故障排查的经验做一次系统梳理,覆盖从Linux常用日志体系、auth.log登录溯源、异常关机排查,到日志膨胀后的磁盘清理,最后再用iuv5g这类设备的日志定位思路收个尾。无论你手里是Ubuntu 20.04、银河麒麟V10,还是别的什么发行版,这套方法论基本通用。
1. 日志系统不是“日志文件”,是一整套链路
很多刚接触Linux的朋友以为日志就是 /var/log 下那一堆文本文件,其实那只是最后一站。现代Linux发版里,日志从产生、收集、处理到落盘,是一条完整的链路,理解这条链,排查时才知道该去哪个环节翻东西。
1.1 syslog、journald与/var/log的协作关系
从CentOS 7和Ubuntu 15.04之后的时代开始,systemd-journald成了日志采集的主角。内核、服务、登录认证进程产生的日志会先在内存和 /var/log/journal/ 里形成二进制日志,通过 journalctl 查看。痛点是二进制格式不适合传统工具,而且重启后容易丢记录,所以现在主流做法是让journald按服务单位把日志转交给syslog(rsyslog或syslog-ng),由syslog按规则写进 /var/log/ 下的纯文本文件。
这两层关系用一句话概括:journald负责“快照式现场”,syslog负责“归档式留痕”。排查时先 journalctl -u 服务名 看最近发生了什么,如果发现现场不够,再去 /var/log/syslog、/var/log/messages 或 /var/log/auth.log 里按时间范围捞。别把两者对立起来,它们是互补的。
常见日志文件的用途,我整理了一张表,几乎每次排查都能用到:
| 文件路径 | 记录内容 | 常见用途 |
|---|---|---|
| /var/log/auth.log | 登录认证、sudo提权、ssh公钥认证等 | 追踪谁登录过、谁执行了提权 |
| /var/log/syslog | 系统整体运行日志,含cron、daemon消息 | 通用排查起点 |
| /var/log/kern.log | 内核日志,含驱动、硬件错误 | 排查内核panic、设备异常 |
| /var/log/boot.log | 启动过程日志 | 定位开机卡住的位置 |
| /var/log/dmesg | 内核环形缓冲区内容 | 硬件识别、启动早期信息 |
| /var/log/wtmp | 成功登录的账户历史记录(二进制) | last命令的数据源 |
| /var/log/btmp | 失败登录的记录(二进制) | 暴力破解分析 |
| /var/log/lastlog | 每个用户最近一次登录时间 | who/whoami类查询 |
1.2 日志轮转和持久化,先保住磁盘再谈排查
日志系统做得再好,不轮转照样出事。默认情况下logrotate每天、每周或按大小触发,把 auth.log 切成 auth.log.1,再往上压成 .2.gz。很多人排查时只看 auth.log 当前文件,结果发现关键记录被轮转走了,白忙一场。
我建议拿到一台服务器先做三件事:第一,检查journald日志上限。
bash复制journalctl --vacuum-size=500M # 只保留500MB日志
journalctl --vacuum-time=7d # 只保留最近7天
第二,确认logrotate配置确实在跑。看 /etc/logrotate.d/rsyslog 内容,确认 rotate 7 这类保留份数合理。第三,如果机器经常异常关机,journald的持久化目录可能损坏,排查前先 journalctl --verify 看有没有坏块,必要时删掉重建。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. auth.log溯源实战:从“用户mage成功登录”这一行挖出完整过程
有一次接到一个排查需求:在Ubuntu 20.04系统里,要查看 /var/log/auth.log 溯源出用户 mage 的成功登录。听起来很简单,就是 grep mage /var/log/auth.log,但真正做过溯源的人会告诉你,难点不在找到那行字,而在把那一行放回到整个攻击链里看。
2.1 登录成功日志的字段拆解
在Ubuntu 20.04上,一条典型的ssh成功登录记录长这样:
code复制May 26 09:12:33 hostname sshd[2345]: Accepted publickey for mage from 192.168.10.88 port 54210 ssh2
May 26 09:17:04 hostname sshd[2388]: pam_unix(sshd:session): session opened for user mage by (uid=0)
先拆字段:May 26 09:12:33 是时间,hostname 是主机名,sshd[2345] 是进程名和PID,Accepted publickey 是认证方式,mage 是登录账户,192.168.10.88 port 54210 是来源IP和端口。第二行说明PAM成功打开了会话,意味着用户真正进入了系统。
排查时不能只看ssh那一行。“Accepted”只代表认证通过,“session opened”才代表能干活了,两者之间隔着PAM的账户、密码、资源限制等检查。如果第一行有而第二行没有,说明卡在PAM阶段,可能是家目录权限不对,也可能是/etc/nologin或配额问题。
2.2 从登录记录逆向还原登录链路
拿到一堆记录后,我的习惯是三步走:
- 先按用户聚合,看时间段内
mage的登录密度:
bash复制grep /var/log/auth.log | grep "session opened for user mage" | awk '{print $1, $2, $3}'
- 再按来源IP聚合,看是不是同一个IP反复登录,或者登录成功后紧接着有sudo动作:
bash复制grep "Accepted.*for mage" /var/log/auth.log | awk '{print $9}' | sort | uniq -c
- 最后交叉验证
sudo记录:
bash复制grep "mage.*sudo" /var/log/auth.log
如果看到 mage : TTY=pts/0 ; PWD=/home/mage ; USER=root ; COMMAND=/bin/bash,说明这个用户已经提权过了,性质完全不一样。
这里要给你提个醒:auth.log只记录“登录”和“提权”,不记录登录后执行了什么普通命令。要查用户登录后干了什么,得看 ~/.bash_history,但那玩意儿用户自己可以清。所以溯源时,auth.log只能证明“这个人进过系统、提过权”,不能证明“这个人一定删了文件”。写报告时措辞要严谨,别把证据链推过头。
另外,日志轮转会干扰溯源。如果关键时间是三天前,而 /var/log/auth.log 只有今天的内容,记得去翻 .1、.2.gz。我通常直接用 zgrep 把所有压缩文件一起搜了:
bash复制zgrep "Accepted.*for mage" /var/log/auth.log.*
排查日期跨度大的历史事件,这条命令比手动翻文件省事得多。
3. 系统异常关机排查:怎么从日志里找出“谁关了我的机器”
“系统无缘无故重启了”“机房断电后开不起来”“半夜机器自己关机了”,这些诉求背后都指向同一件事:查异常关机日志。日志系统里专门记录这些痕迹的地方,比你想的多得多。
3.1 last、journalctl与启动记录的配合使用
先介绍一个最快的命令组合。last -x 能列出关机、重启、运行级别变化的历史:
bash复制last -x | head -30
输出里的 shutdown 表示一次正常关机流程,reboot 表示系统重启,crash 表示异常中断。如果你看到一堆 crash,基本可以确认系统不是正常关的。
journalctl --list-boots 则是另一套语言,它把每次启动列为一次boot,编号从0开始递减:0 是当前启动,-1 是上一次启动。排查异常关机时,核心是看上一次启动的尾部,也就是系统“断气”前的最后记录:
bash复制journalctl -b -1 -e
-e 会直接跳到日志末尾。如果你在末尾看到 Powering off 或用户执行 shutdown 的记录,那是人为正常关机;如果日志戛然而止,后面什么都没有,那多半是断电、硬件错误或内核直接崩溃。
3.2 从时间线反推异常关机的几种典型场景
看日志只看一行不够,得把时间线串起来。常见三类:
第一类是内核panic。此时候选日志在 /var/log/kern.log 或 journalctl -k -b -1 里,会看到 Kernel panic - not syncing,紧跟一堆调用栈。这种情况先查最近改过什么内核参数、驱动模块,或者是不是硬件不稳定。
第二类是硬件层面的断电。时间线上表现为上次启动日志的结束时间突然中断,下一次boot时间比预期晚很多,中间没有任何关机记录。有些机器带BMC/IPMI日志,可以交叉验证是否为物理断电。没有BMC的小机器,只能靠 journalctl --list-boots 里的启动间隔判断。
第三类是触发了看门狗(watchdog)。日志里会出现 watchdog: watchdog0: watchdog did not stop!,这表明系统主进程卡死,被硬件看门狗强制复位。这种问题排查难度最高,因为现场往往被复位动作清掉一部分,建议把kdump内核转储配上,下次再崩能抓到完整的coredump。
查异常关机最容易踩的坑是时间不同步。如果系统用了ntp但没配好,或者主板电池没电,日志时间会和真实时间差出几个小时甚至一天。排查前先执行 timedatectl 确认当前时间和时区,再看日志里时间是否连续,别被虚假的“时间跳跃”误导成重启事件。
4. 日志膨胀和磁盘清理:既删得掉垃圾,又保得住数据
日志系统的副作用是日志文件越滚越大。尤其是跑了一年半载的服务器,/var/log 能轻松吃到几十GB;Windows机器也一样,更新缓存和临时文件堆久了,C盘能红到发紫。清理这件事很多人做得太激进,直接把 rm -rf /var/log/*,结果日志没保住,连现在正在写的文件句柄都搞出毛病。正确姿势是先算账,再分类型处理。
4.1 先算账:哪类日志和缓存最占空间
在Linux上我习惯用 du 排个序:
bash复制sudo du -sh /var/log/* 2>/dev/null | sort -rh | head -20
常见大头是 journal/ 目录、syslog、kern.log 和历史旧档。其中journal目录往往能到好几个GB,因为它默认不受logrotate控制,只受 /etc/systemd/journald.conf 里的 SystemMaxUse 限制。Windows那边则通常是 C:\Windows\SoftwareDistribution\Download(更新缓存)、C:\Windows\Temp、C:\Users\用户名\AppData\Local\Temp 和回收站。
庞大日志和缓存的特点是一样的:大部分是重复的、早已无效的数据,真正需要保留的只有最近几天的记录,外加少量用于追溯的旧档。所以清理策略不是“能删就删”,而是“按时间留、按大小限”。
4.2 自动扫描与安全删除的实操脚本
我写过一个小脚本,专治“日志/缓存占满磁盘但不敢手动删”的情况。核心思路是扫描各个临时目录,删除超过指定天数的文件,同时避开所有个人目录和配置目录,最后统计释放了多少空间。基本框架长这样,按你的系统改路径就能用:
bash复制#!/bin/bash
# 安全清理Linux日志和缓存:只动临时文件,不碰个人数据
today=$(date +%Y-%m-%d)
declare -a TARGET_DIRS=(
"/var/log"
"/var/tmp"
"/tmp"
"/home/*/.cache"
)
echo "清理开始时间: $today"
for dir in "${TARGET_DIRS[@]}"; do
if [ ! -d "$dir" ]; then
continue
fi
before=$(du -sb "$dir" 2>/dev/null | awk '{print $1}')
# 仅清理5天前的.log/.gz/.tmp文件
find "$dir" -type f \( -name "*.log" -o -name "*.gz" -o -name "*.tmp" \) -mtime +5 -delete 2>/dev/null
after=$(du -sb "$dir" 2>/dev/null | awk '{print $1}')
freed=$(( (before - after) / 1024 / 1024 ))
echo "目录 $dir 释放约 ${freed} MB"
done
# 清理systemd journal日志,保留最近500MB
journalctl --vacuum-size=500M >/dev/null 2>&1
# 清理回收站(如果启用了trash-cli)
if command -v trash-empty >/dev/null 2>&1; then
trash-empty 30
fi
echo "全部清理完成"
几个关键点我提一下:find 只删指定后缀的文件,绝不会动 conf、pid、socket 这些关键文件;-mtime +5 给所有文件留了5天缓冲,不会把还在用的日志删掉;-delete 前最好先跑一遍不带 -delete 的 find 看清单,确认没有删到自己的配置文件。统计释放空间时用 du 前后差值,比逐个文件累加准得多,因为稀疏文件会误导计算。
4.3 Ubuntu 20.04与银河麒麟V10的清理差异
其实核心命令在两个系统上几乎通用,差别主要在面板和路径。我实测对比过,Ubuntu 20.04默认用的就是systemd-journald加rsyslog,日志体系很“标准”,按照上面的方式操作完全没问题。银河麒麟V10虽然也是Linux内核,但它的图形化系统工具里带了“日志清理”入口,底层调用的还是 journalctl 和 logrotate。如果你习惯命令行,直接用一样的脚本就行;如果对方只会点鼠标,那就打开“系统工具-日志收集工具”,按时间范围清理。
Windows侧则不用找journalctl,图形化里用 cleanmgr(磁盘清理)勾掉“Windows更新清理”“临时文件”“回收站”,命令行用 cleanmgr /sagerun:1 自动化。关键的 SoftwareDistribution\Download 目录删除前要先停掉Windows Update服务:
cmd复制net stop wuauserv
net stop bits
del /f /q C:\Windows\SoftwareDistribution\Download\*.*
net start bits
net start wuauserv
这套操作我跑了无数次,只要不动 Users 里面的文档、照片和已安装程序的目录,个人数据绝对安全。清理后记得看释放空间大小,Linux上用 df -h,Windows上用资源管理器看C盘可用空间,心里才有底。
5. iuv5g故障排查里的日志分级:同一套思路换个场景照样用
前面讲的是通用Linux日志,但实际项目里还会遇到一些专用设备,比如iuv5g这类带通信和计算能力的网关盒子。很多人一碰到专用设备就懵,觉得日志格式看不懂、命令也不对。其实排查思路一点都没变:先定范围,再分级别,最后用时间线串起来。设备再怪,也是跑代码的机器,日志就是它的“病历本”。
5.1 设备日志与系统日志的关联定位
先说一个最常见的问题:设备出故障了,到底是设备本身坏了,还是它所在的系统环境出问题了?我的排查方法是同时开三个“视图”对照。
第一个视图是整机系统日志,看CPU、内存、磁盘有没有异常。用 journalctl -b 0 看最近一次启动以来有没有OOM、磁盘I/O错误、进程崩溃。第二个视图是设备自身的运行日志,通常在设备管理页面或 /var/log 下对应进程的独立日志文件里,记录它注册、连接、断连的整个过程。第三个视图是网络日志,看交换机或服务端的日志有没有丢包、拒连。
如果三个视图的时间点能对上,基本就能定位。比如设备日志显示“连接超时重试”,同时系统日志显示某个网卡频繁down/up,而交换机侧没有异常,那问题大概率在这台设备的物理链路或网卡驱动上。反过来,如果只有设备日志报错、其他两方都正常,才应该怀疑设备固件逻辑。
5.2 故障复现时最容易遗漏的日志行为
再讲一个实际教训:排查iuv5g这类设备时,最怕时间戳错乱。设备内置电池没电或者网络校时失败,日志时间会跳到1970年或者前后乱跳,跟系统日志一对全对不上。所以每次抓设备日志之前,我先 date 确认设备当前时间,再和服务器时间做一次对照,偏差超过30秒就先校时再复现。
故障复现是排查里的高价值时段。我的做法是:先把设备日志级别调到最详细(常见是debug或trace),清空现有日志,然后手动触发一次故障流程,复现后立刻抓包、抓日志、抓系统状态。这样拿到的一手数据干干净净,不用在几十万行历史日志里捞线索。复现过程里,设备日志、系统日志、抓包文件三样尽量同时间开始、同时间结束,后期按时间戳对齐才可靠。
日志界有个说法:“日志本身不会撒谎,但残缺的日志最会误导。”采集时宁可多抓一点,也别只拿结论性的那几行。我有一次排查设备偶发离线,单看设备日志全是“断开-重连-断开-重连”,根本看不出原因;后来把系统日志也拉上,才发现是设备进程在收到某个信号后主动退了,而触发信号的是外部管理程序误发。这种问题只盯单一日志永远找不到根因,跨日志交叉验证才是正解。
日志系统这块,我这些年最大的体会是:工具可以不会很多,关键是把时间线和上下文两个词刻在脑子里。任何日志记录,脱离了时间线就是孤岛,脱离了上下文就是噪音。不管面前的盒子叫Ubuntu、银河麒麟还是iuv5g,只要你能回答“这个日志是什么时候、在什么进程、因什么事件产生”,故障排查就已经成功了一大半。这套思路你顺着用下去,慢慢也会发现,那些当初让你抓狂的故障,其实早就在日志里写好了答案,只等你翻到那一页。
