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 的核心用法串起来了。你可以把它当作排查时的“路线图”。

dmesg 深度使用知识体系 dmesg 命令 -T 时间转换 -l 级别过滤 -c 清空缓冲区 -k 内核日志 时间对齐排查 只看错误/警告 重置日志起点 排除用户空间 grep 精筛:关键词 + 时间 + 多级组合 精准定位:硬件错误 / 驱动问题 / 内核异常 核心原则:先参数粗筛(-T -l),再 grep 精筛,最后定位问题 避免裸敲 dmesg 看全部日志,效率极低

4.5 实战案例:排查硬盘 I/O 错误

最后分享一个真实案例。有一次监控报警,说某台数据库服务器磁盘 I/O 延迟飙升。我按以下步骤排查:

  1. 先看错误级别:dmesg -T -l err | grep -i 'sd\|ata\|scsi'
  2. 发现关键行:[Wed Feb 14 02:33:17 2024] sd 0:0:1:0: [sdb] Unhandled error code
  3. 再查上下文:dmesg -T | grep -A 5 'sdb.*error'
  4. 定位根因:磁盘 sdb 出现大量链路重置,最终确认是 SAS 线缆松动

整个过程不到 5 分钟。如果没有 dmesg 参数和 grep 的组合,光翻原始日志可能得半小时。

常用 grep 关键词速查:

  • 硬件:pci, usb, sata, nvme, sd, hd
  • 错误:error, fail, critical, panic, oops
  • 资源:oom, memory, irq, timeout
  • 驱动:module, driver, firmware