4、dmesg 命令深度使用:常用参数与内核日志过滤
dmesg 这工具,说白了就是内核的“日记本”。系统从加电开始,内核一路干了什么、遇到了什么异常,全记在这里。我刚开始做运维那会儿,遇到服务器起不来只会看 /var/log/messages,后来才发现 dmesg 里藏着大量第一手线索——尤其是硬件初始化阶段的问题,messages 还没开始记呢,dmesg 已经写了好几页了。
这一节我们就把 dmesg 的几个核心参数吃透,再配合 grep 做精准过滤。嗯,学会了这些,排查内核级问题会顺手很多。
4.1 为什么需要 dmesg 参数?
裸敲 dmesg 会输出从开机到现在的全部内核日志。一台跑了半年的服务器,输出可能有几十万行。你想想看,要在里面找一条关键错误,跟大海捞针差不多。
所以我们需要参数来“切”日志:
- 切时间:把时间戳转成人类能看懂的时间
- 切级别:只看错误、警告,忽略信息
- 切设施:只看内核、驱动、硬件相关
- 切内容:用 grep 过滤关键词
核心思路:dmesg 参数负责“粗筛”,grep 负责“精筛”。两者配合,效率翻倍。
4.2 常用参数详解
4.2.1 -T:把时间戳变成人话
dmesg 默认的时间戳是从系统启动开始的秒数。比如 [ 12.345678] 表示开机后 12.34 秒。这谁记得住?加上 -T 就能显示成标准时间格式。
# 默认输出
$ dmesg | head -1
[ 0.000000] Linux version 5.10.0-28-amd64
# 加上 -T
$ dmesg -T | head -1
[Mon Jan 15 10:23:45 2024] Linux version 5.10.0-28-amd64
我个人习惯排查问题时先用 -T,这样能直接跟应用日志的时间对上。有一次数据库半夜挂了,我对比 dmesg -T 和 MySQL 错误日志的时间戳,发现内核在 03:15:22 报了一个 PCIe 错误,MySQL 在 03:15:25 就崩了——时间线一下就清晰了。
小提示:-T 依赖系统当前时区设置。如果服务器时区不对,显示的时间也会偏。建议先确认 timedatectl 的结果。
4.2.2 -l:按日志级别过滤
内核日志有 8 个级别,从紧急到调试。用 -l 可以只输出指定级别的消息。
| 级别编号 | 级别名称 | 含义 | 常见场景 |
|---|---|---|---|
| 0 | KERN_EMERG | 系统不可用 | 内核 panic |
| 1 | KERN_ALERT | 必须立即处理 | 硬件故障 |
| 2 | KERN_CRIT | 严重错误 | 驱动崩溃 |
| 3 | KERN_ERR | 一般错误 | I/O 错误 |
| 4 | KERN_WARNING | 警告 | 资源不足 |
| 5 | KERN_NOTICE | 正常但重要 | 模块加载 |
| 6 | KERN_INFO | 信息 | 硬件探测 |
| 7 | KERN_DEBUG | 调试信息 | 开发阶段 |
# 只看错误和更严重的(0-3级)
$ dmesg -l err
# 只看警告和错误(3-4级)
$ dmesg -l warn,err
# 只看紧急消息(0级)
$ dmesg -l emerg
我曾经遇到一台机器频繁重启,裸敲 dmesg 输出好几屏,根本看不出问题。加上 -l err 之后,只看到一行:KERN_CRIT: CPU soft lockup。嗯,问题一下就定位了——是 CPU 频率调节驱动有 bug。
4.2.3 -c:清空内核日志缓冲区
-c 参数会读取并清空当前内核日志缓冲区。这个参数我建议谨慎使用,尤其是在生产环境。
# 读取并清空
$ dmesg -c
警告:-c 会清空缓冲区,清掉之后旧日志就没了。除非你明确知道自己在做什么(比如刚开机、想从头记录),否则别在生产环境用。我见过有人手滑执行了 dmesg -c,结果排查历史问题时发现日志全空了……
如果你只是想“重置”视角,建议用 dmesg --since 或配合 journalctl 来查看增量日志,而不是直接清空。
4.2.4 -k:只看内核日志
dmesg 默认输出内核日志,但有些系统上也会混入用户空间的消息。加上 -k 可以明确只显示内核产生的日志。
# 只显示内核日志
$ dmesg -k
这个参数在容器环境或某些特殊发行版上比较有用。大部分场景下,裸敲 dmesg 和 dmesg -k 效果一样,但养成加 -k 的习惯能避免意外。
4.3 结合 grep 过滤内核日志
参数只能做“粗筛”,真正精准定位还得靠 grep。这里分享几个我常用的组合。
4.3.1 按关键词过滤
# 查找 USB 相关日志
$ dmesg -T | grep -i usb
# 查找硬盘错误
$ dmesg -T | grep -iE 'error|fail|critical'
# 查找网卡信息
$ dmesg -T | grep -i eth
4.3.2 按时间范围过滤
dmesg 本身没有按时间范围过滤的参数,但我们可以用 grep 配合正则来实现。
# 查找 2024 年 1 月的日志
$ dmesg -T | grep 'Jan 2024'
# 查找 10:00 到 11:00 之间的日志
$ dmesg -T | grep '10:'
不过说实话,这种过滤方式比较粗糙。更精确的做法是用 journalctl --dmesg,它支持 --since 和 --until 参数。但那是另一节课的内容了。
4.3.3 多级过滤组合
把参数和 grep 串起来,效果最好:
# 只看错误级别、包含 "pci" 的日志
$ dmesg -T -l err | grep -i pci
# 只看警告级别、包含 "memory" 的日志
$ dmesg -T -l warn | grep -i memory
# 只看紧急和错误级别、包含 "timeout" 的日志
$ dmesg -T -l emerg,err | grep -i timeout
实战技巧:先用 -l err 缩小范围,再用 grep 过滤关键词。如果结果太少,再放宽到 -l warn,err。这样不会漏掉关键信息,也不会被海量日志淹没。
4.4 知识体系图
下面这张图把 dmesg 的核心用法串起来了。你可以把它当作排查时的“路线图”。
4.5 实战案例:排查硬盘 I/O 错误
最后分享一个真实案例。有一次监控报警,说某台数据库服务器磁盘 I/O 延迟飙升。我按以下步骤排查:
- 先看错误级别:
dmesg -T -l err | grep -i 'sd\|ata\|scsi' - 发现关键行:
[Wed Feb 14 02:33:17 2024] sd 0:0:1:0: [sdb] Unhandled error code - 再查上下文:
dmesg -T | grep -A 5 'sdb.*error' - 定位根因:磁盘 sdb 出现大量链路重置,最终确认是 SAS 线缆松动
整个过程不到 5 分钟。如果没有 dmesg 参数和 grep 的组合,光翻原始日志可能得半小时。
常用 grep 关键词速查:
- 硬件:pci, usb, sata, nvme, sd, hd
- 错误:error, fail, critical, panic, oops
- 资源:oom, memory, irq, timeout
- 驱动:module, driver, firmware