dmesg 命令详解与参数实测(Ubuntu 22.04)
dmesg 命令逐参数实测详解:默认读取内核环形缓冲区、-T/-t 时间戳控制、--level 级别过滤、--facility 设施过滤、-H 人类可读、--color 彩色、-s 缓冲大小、-r 原始、-x 解码前缀、-w 跟随模式与 -c/-C 清空说明,含权限受限两形态排障与内核日志三入口对比,全部回显在 Ubuntu 22.04(util-linux 2.37.2)实测通过。
dmesg 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 dmesg 的每一个常用参数——默认读取内核环形缓冲区、
-T人类可读时间戳、-t去时间前缀、--level/-l级别过滤、--facility/-f设施过滤、-H人类可读输出、--color彩色输出、-s缓冲区大小、-r原始输出、-x设施:级别前缀、-w跟随模式、-c/-C清空缓冲区,全部命令与回显已在 Ubuntu 22.04(util-linux 2.37.2)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- 内核版本:6.8.0-138-generic(
uname -r实测) - dmesg 版本:util-linux 2.37.2(
dmesg --version实测) - 实测环境一:最小化安装环境,当前用户 uid=0 但运行环境未授予 CAP_SYSLOG 能力,
kernel.dmesg_restrict=1,用于实测「权限受限」形态 - 实测环境二:root 全能力环境(具备 CAP_SYSLOG),可完整读取内核环形缓冲区(实测 2798 行)并可写入
/dev/kmsg,用于实测各参数的完整输出 - 内核环形缓冲区:约 2800 行,覆盖从
[ 0.000000]起的完整启动日志与运行期事件
二、命令概览
2.1 语法与实测环境准备
dmesg(display message / driver message)用于显示和控制内核环形缓冲区(kernel ring buffer):硬件自检、模块加载、文件系统挂载、OOM 事件等内核消息都会写入这里。核心语法:
dmesg [<options>]:不带参数读取全部缓冲区内容;dmesg <过滤参数>:按级别、设施、时间等条件过滤输出。
为让各参数的过滤效果可复现、可观察,先以 root 身份向 /dev/kmsg 写入 6 条演示消息。写入内核缓冲区的优先级数值 = 设施编号 × 8 + 级别编号(设施编号:kern=0、user=1、daemon=3;级别编号:err=3、warning=4、notice=5、info=6、debug=7),因此 <3> 为 kern.err、<27>(3×8+3)为 daemon.err、<30>(3×8+6)为 daemon.info:
$ echo '<3>dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable' > /dev/kmsg
$ echo '<4>dmesg-demo: thermal zone cpu-thermal temperature above threshold' > /dev/kmsg
$ echo '<6>dmesg-demo: eth0 link up at 1000 Mbps full duplex' > /dev/kmsg
$ echo '<7>dmesg-demo: debug probe message for level filtering test' > /dev/kmsg
$ echo '<27>dmesg-demo: simulated udev worker error event' > /dev/kmsg
$ echo '<30>dmesg-demo: simulated scheduler info event' > /dev/kmsg
💡 说明:
echo重定向写入/dev/kmsg需要 root 权限。经/dev/kmsg写入的消息默认设施为user而非kern(下文 3.5 节用--facility参数实测验证了这一行为)。
读一下确认 6 条消息已入缓冲区:
$ dmesg | grep dmesg-demo | head -n 6
[27546.723050] dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
[27546.723140] dmesg-demo: thermal zone cpu-thermal temperature above threshold
[27546.723160] dmesg-demo: eth0 link up at 1000 Mbps full duplex
[27546.723179] dmesg-demo: debug probe message for level filtering test
[27546.723196] dmesg-demo: simulated udev worker error event
[27546.723215] dmesg-demo: simulated scheduler info event
6 条演示消息全部可读,方括号内是内核启动后经过的秒数(相对时间戳)。下文参数实测都围绕这 6 条消息与缓冲区里的真实内核日志展开。
💡 技术拓展:读取内核日志不止 dmesg 一个入口。三个入口横向对比——
入口 数据来源 持久性 典型场景 dmesg 内核环形缓冲区(/dev/kmsg) 内存中,重启清空、写满覆盖最旧 看启动日志、硬件报错、实时事件 journalctl -k systemd-journald 收集的内核日志 落盘 /var/log/journal/ 追溯历史(含上一次启动 -b -1)tail /var/log/kern.log rsyslog 转存的文本文件 落盘文本 用 grep/文本工具直接检索 后两个入口依赖对应服务:本实验的最小化环境实测
journalctl -k输出No journal files were found.、/var/log/kern.log不存在(rsyslog 未安装),此时 dmesg 是唯一入口。三种入口本文实际以 dmesg 为主线,journal 与 kern.log 的分工详见第五节常见问题。
2.2 --help 全量输出(逐行照抄)
先看 dmesg --help 的完整输出,建立参数全景图(util-linux 2.37.2 实测,逐行照抄):
$ dmesg --help
Usage:
dmesg [options]
Display or control the kernel ring buffer.
Options:
-C, --clear clear the kernel ring buffer
-c, --read-clear read and clear all messages
-D, --console-off disable printing messages to console
-E, --console-on enable printing messages to console
-F, --file <file> use the file instead of the kernel log buffer
-f, --facility <list> restrict output to defined facilities
-H, --human human readable output
-k, --kernel display kernel messages
-L, --color[=<when>] colorize messages (auto, always or never)
colors are enabled by default
-l, --level <list> restrict output to defined levels
-n, --console-level <level> set level of messages printed to console
-P, --nopager do not pipe output into a pager
-p, --force-prefix force timestamp output on each line of multi-line messages
-r, --raw print the raw message buffer
--noescape don't escape unprintable character
-S, --syslog force to use syslog(2) rather than /dev/kmsg
-s, --buffer-size <size> buffer size to query the kernel ring buffer
-u, --userspace display userspace messages
-w, --follow wait for new messages
-W, --follow-new wait and print only new messages
-x, --decode decode facility and level to readable string
-d, --show-delta show time delta between printed messages
-e, --reltime show local time and time delta in readable format
-T, --ctime show human-readable timestamp (may be inaccurate!)
-t, --notime don't show any timestamp with messages
--time-format <format> show timestamp using the given format:
[delta|reltime|ctime|notime|iso]
Suspending/resume will make ctime and iso timestamps inaccurate.
--since <time> display the lines since the specified time
--until <time> display the lines until the specified time
-h, --help display this help
-V, --version display version
Supported log facilities:
kern - kernel messages
user - random user-level messages
mail - mail system
daemon - system daemons
auth - security/authorization messages
syslog - messages generated internally by syslogd
lpr - line printer subsystem
news - network news subsystem
Supported log levels (priorities):
emerg - system is unusable
alert - action must be taken immediately
crit - critical conditions
err - error conditions
warn - warning conditions
notice - normal but significant condition
info - informational
debug - debug-level messages
For more details see dmesg(1).
从 --help 可以看出:dmesg 的参数分为「输出内容控制」(-k/-u/-r/-x)、「过滤」(-l/--level、-f/--facility、--since/--until)、「时间格式」(-T/-t/-e/-d/--time-format)、「输出形态」(-H/-L/-P)、「缓冲区与控制台控制」(-s/-C/-c/-D/-E/-n)几组。帮助输出还列出了全部 8 种设施(facilities)与 8 个级别(levels)——这两个清单正是过滤参数 --facility 与 --level 的合法取值。
2.3 版本信息
$ dmesg --version
dmesg from util-linux 2.37.2
Ubuntu 22.04 仓库中的 dmesg 由 util-linux 2.37.2 提供(util-linux 是 Linux 基础工具集,dmesg 属于它的组成部分)。
三、参数逐项实测
本章在 root 全能力环境逐个实测参数。除特别说明外,示例都基于 2.1 节注入的 6 条演示消息与缓冲区中已有的真实内核日志。
3.1 无参数:读取全部内核环形缓冲区
不带参数时 dmesg 输出缓冲区中全部消息,每行前置相对时间戳(内核启动后秒数)。先用 wc -l 看总量,再取开头 8 行:
$ dmesg | wc -l
2798
$ dmesg | head -n 8
[ 0.000000] Linux version 6.8.0-138-generic (buildd@lcy02-amd64-008) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04.3) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #138~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 7 13:43:15 UTC (Ubuntu 6.8.0-138.138~22.04.1-generic 6.8.12)
[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-6.8.0-138-generic root=UUID=43e68207-7df4-4f66-933a-8a595cdde8c8 ro quiet splash
[ 0.000000] KERNEL supported cpus:
[ 0.000000] Intel GenuineIntel
[ 0.000000] AMD AuthenticAMD
[ 0.000000] Hygon HygonGenuine
[ 0.000000] Centaur CentaurHauls
[ 0.000000] zhaoxin Shanghai
💡 要点:
dmesg | wc -l的 2798 行不是固定值——内核日志是「活」的,每有新事件写入行数就增长(本文多次实测中该值在 2781→2801 之间浮动)。第一行永远从[ 0.000000]内核版本信息开始,这是判断缓冲区是否完整(未被清空/覆盖)的标志。
3.2 -T(--ctime):人类可读时间戳
默认的相对秒数对排障不直观,-T 把时间戳换算成本地墙上时间:
$ dmesg -T | grep dmesg-demo | head -n 6
[Thu Oct 15 13:55:40 2026] dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
[Thu Oct 15 13:55:40 2026] dmesg-demo: thermal zone cpu-thermal temperature above threshold
[Thu Oct 15 13:55:40 2026] dmesg-demo: eth0 link up at 1000 Mbps full duplex
[Thu Oct 15 13:55:40 2026] dmesg-demo: debug probe message for level filtering test
[Thu Oct 15 13:55:40 2026] dmesg-demo: simulated udev worker error event
[Thu Oct 15 13:55:40 2026] dmesg-demo: simulated scheduler info event
6 条演示消息的写入时刻被换算成了 Thu Oct 15 13:55:40 2026 格式的本地时间。
💡 技术拓展:dmesg 的时间戳有多种格式可选——
格式 形态示例 对应参数 rel(默认) [27546.723050]内核启动后秒数默认输出 ctime [Thu Oct 15 13:55:40 2026]墙上时间-T或--time-format=ctimereltime 本地时间 + 与上条消息的间隔 -eiso ISO-8601 精确时间 --time-format=isonotime 不显示时间戳 -t或--time-format=notimedelta 与上条消息的时间差 -d本文示例默认采用 rel 与
-T两种。注意 --help 原文提示:Suspending/resume will make ctime and iso timestamps inaccurate.——系统休眠恢复后 ctime/iso 时间会失准,需要精确时间溯源时应以journalctl -k为准。
3.3 -t(--notime):不带时间前缀
-t 去掉每行开头的时间戳,适合把内核消息纯文本化后做 diff 或二次加工:
$ dmesg -t | grep dmesg-demo | head -n 6
dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
dmesg-demo: thermal zone cpu-thermal temperature above threshold
dmesg-demo: eth0 link up at 1000 Mbps full duplex
dmesg-demo: debug probe message for level filtering test
dmesg-demo: simulated udev worker error event
dmesg-demo: simulated scheduler info event
💡 要点:与
--time-format=notime等价。去掉时间前缀后配合sort -u可以快速得到「出现过哪些内核消息」的去重清单。
3.4 --level / -l:按级别过滤
--level(短格式 -l)只输出指定级别的消息,级别名就是 2.2 节 --help 列出的 8 个:emerg、alert、crit、err、warn、notice、info、debug,逗号分隔可传多个。先看 err+warn 的前 6 行(缓冲区里的真实内核告警):
$ dmesg --level=err,warn | head -n 6
[ 0.936438] core: CPUID marked event: 'cpu cycles' unavailable
[ 0.936446] core: CPUID marked event: 'instructions' unavailable
[ 0.936454] core: CPUID marked event: 'bus cycles' unavailable
[ 0.936462] core: CPUID marked event: 'cache references' unavailable
[ 0.936470] core: CPUID marked event: 'cache misses' unavailable
[ 0.936477] core: CPUID marked event: 'branch misses' unavailable
再看最近 3 条 err/warn(含注入的演示消息):
$ dmesg --level=err,warn | tail -n 3
[27877.135633] dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
[27877.135744] dmesg-demo: thermal zone cpu-thermal temperature above threshold
[27877.135866] dmesg-demo: simulated udev worker error event
注入的 <3>(err)与 <4>(warn)消息被精确捕获,而 <6>(info)、<7>(debug)、<30>(daemon.info)都被过滤掉了。统计一下 err+warn 总量:
$ dmesg -l err,warn | wc -l
52
💡 要点:
-l与--level完全同义。52 条中既有系统真实的启动期告警(如 CPUID 性能事件不可用),也包含注入的演示消息;排障时dmesg -l err,warn是「先看有没有报错」的第一快查命令。级别列表还支持区间写法(如dmesg -l emerg..err表示 emerg 到 err 的所有级别)。
3.5 --facility / -f:按设施过滤
--facility(短格式 -f)按消息来源设施过滤,合法取值同样是 --help 列出的 8 种。daemon 设施的前 5 行(systemd 进程的内核侧消息):
$ dmesg --facility=daemon | head -n 5
[ 23.113138] systemd[1]: Inserted module 'autofs4'
[ 23.413930] systemd[1]: systemd 249.11-0ubuntu3.22 running in system mode (+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY -P11KIT -QRENCODE +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
[ 23.414145] systemd[1]: Detected virtualization vmware.
[ 23.414181] systemd[1]: Detected architecture x86-64.
[ 23.415091] systemd[1]: Hostname set to <ops>.
用 kern 设施过滤演示消息,结果为空;换 user 设施则能读到:
$ dmesg --facility=kern | grep dmesg-demo
$ dmesg --facility=user | grep dmesg-demo | head -n 4
[27546.723050] dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
[27546.723140] dmesg-demo: thermal zone cpu-thermal temperature above threshold
[27546.723160] dmesg-demo: eth0 link up at 1000 Mbps full duplex
[27546.723179] dmesg-demo: debug probe message for level filtering test
💡 要点:两条命令的对比实证了 2.1 节的说明——经
/dev/kmsg用echo写入的消息默认设施是user,所以--facility=kern匹配不到任何演示消息(空输出正是设施过滤生效的证明),而--facility=user能读到。内核自身产生的硬件/驱动日志才是 kern 设施。
3.6 -H(--human):人类可读输出
-H 开启人类可读模式:时间戳按「小时分组 + 相对增量」显示,同小时内的消息只显示与上一条的间隔:
$ dmesg -H | grep dmesg-demo | head -n 8
[Oct15 13:55] dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
[ +0.000090] dmesg-demo: thermal zone cpu-thermal temperature above threshold
[ +0.000020] dmesg-demo: eth0 link up at 1000 Mbps full duplex
[ +0.000019] dmesg-demo: debug probe message for level filtering test
[ +0.000017] dmesg-demo: simulated udev worker error event
[ +0.000019] dmesg-demo: simulated scheduler info event
[ +1.166804] dmesg-demo: follow mode message one
[ +1.002014] dmesg-demo: follow mode message two
💡 要点:
[Oct15 13:55]是小时分组头(该小时的第一条消息显示时刻),后续[ +0.000090]表示距上一条消息过去了 90 微秒。-H在终端上还会自动进入分页器(less),管道或重定向时则正常输出;不想进分页器可加-P(--nopager)。
3.7 --color / -L:彩色输出
--color=always 强制输出 ANSI 颜色码(终端上时间戳绿色、级别关键词按严重度着色)。用 cat -v 把不可见字符显示出来,验证颜色码确实存在:
$ dmesg --color=always | head -n 2 | cat -v
^[[32m[ 0.000000] ^[[0mLinux version 6.8.0-138-generic (buildd@lcy02-amd64-008) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04.3) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #138~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 7 13:43:15 UTC (Ubuntu 6.8.0-138.138~22.04.1-generic 6.8.12)
^[[32m[ 0.000000] ^[[0m^[[33mCommand line^[[0m: BOOT_IMAGE=/boot/vmlinuz-6.8.0-138-generic root=UUID=43e68207-7df4-4f66-933a-8a595cdde8c8 ro quiet splash
💡 要点:
^[[32m(绿色)、^[[33m(黄色)就是 ANSI 转义序列。默认--color=auto——输出到终端时着色、管道/重定向时自动关闭;写脚本处理输出时用--color=never保险,直接看错误时--color=always可以让 err 级别红色高亮。-L与--color同义。
3.8 -s(--buffer-size):查询缓冲区大小
-s 指定读取缓冲区时使用的临时缓冲区大小(字节)。这是为旧内核的 syslog(2) 系统调用准备的——旧接口一次只返回调用方提供的缓冲区那么多的数据,太小会截断;新内核经 /dev/kmsg 读取时基本不受影响,输出行数应当一致:
$ dmesg | wc -l
2798
$ dmesg -s 4096 | wc -l
2798
💡 要点:util-linux 的 dmesg 会先探测缓冲区再读取,默认值已足够大;默认与显式
-s 4096行数一致,说明本机内核走 /dev/kmsg 路径不受该参数影响。只有当内核很老或输出被截断时才需要调大-s(上限 131072)。
3.9 -r(--raw):原始输出
-r 输出原始消息:每行行首带 <优先级> 数值前缀(= 设施×8+级别),不做任何解码:
$ dmesg -r | head -n 4
<5>[ 0.000000] Linux version 6.8.0-138-generic (buildd@lcy02-amd64-008) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04.3) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #138~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 7 13:43:15 UTC (Ubuntu 6.8.0-138.138~22.04.1-generic 6.8.12)
<6>[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-6.8.0-138-generic root=UUID=43e68207-7df4-4f66-933a-8a595cdde8c8 ro quiet splash
<6>[ 0.000000] KERNEL supported cpus:
<6>[ 0.000000] Intel GenuineIntel
💡 要点:
<5>= kern.notice(0×8+5)、<6>= kern.info,与 2.1 节的优先级公式对应。-r输出最接近 syslog(2) 协议的原始形态,适合交给日志采集器或其他程序按优先级再处理;人读时用-x(见 3.10)更直观。
3.10 -x(--decode):facility:level 可读前缀
-x 把每条消息的优先级解码为「设施:级别」前缀:
$ dmesg -x | grep dmesg-demo | head -n 6
user :err : [27546.723050] dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
user :warn : [27546.723140] dmesg-demo: thermal zone cpu-thermal temperature above threshold
user :info : [27546.723160] dmesg-demo: eth0 link up at 1000 Mbps full duplex
user :debug : [27546.723179] dmesg-demo: debug probe message for level filtering test
daemon:err : [27546.723196] dmesg-demo: simulated udev worker error event
daemon:info : [27546.723215] dmesg-demo: simulated scheduler info event
💡 要点:
user:err与daemon:err直接可读,是验证「这条消息到底是什么设施什么级别」的权威手段——上文 3.5 节的设施归属结论、2.1 节的优先级公式都可用-x逐一复核。
3.11 -w(--follow):跟随模式
-w(--follow)读取完现有缓冲区后不退出,持续等待并打印新消息(类似 tail -f)。为能观察到效果,先注入 2 条新消息,再用 timeout 包裹 dmesg 运行 4 秒:
$ echo '<5>dmesg-demo: follow mode message one' > /dev/kmsg
$ echo '<3>dmesg-demo: follow mode message two' > /dev/kmsg
$ timeout 4 dmesg -w --time-format=reltime | tail -n 4
[ +0.000046] dmesg-demo: simulated udev worker error event
[ +0.000046] dmesg-demo: simulated scheduler info event
[ +1.195778] dmesg-demo: follow mode message one
[ +1.002237] dmesg-demo: follow mode message two
💡 要点:dmesg -w 会先把现有缓冲区全部打出来再跟随,上面用
tail -n 4只留了末尾——最后两行正是注入后被实时捕获的 follow mode message one/two,时间增量约 1 秒,与注入节奏吻合。只想看「开始跟随之后」的新消息用-W(--follow-new)。生产上用它实时盯 USB 插拔、磁盘报错非常顺手,退出按 Ctrl+C。
3.12 -c / -C:清空内核环形缓冲区
两个清空参数的标准形态:
dmesg -c # 读取全部消息后清空缓冲区(读后清)
dmesg -C # 直接清空缓冲区(不读取)
dmesg | wc -l # 验证:清空后应输出 0
⚠️ 注意:清空操作需要 root(CAP_SYSLOG)权限,且不可恢复——缓冲区在内存里,清掉的日志无法找回,执行前务必先留存快照(
dmesg -T > /var/log/dmesg-backup.log,见 4.4)。本实验环境是常驻系统,清空会丢掉既有未落盘的内核日志、影响其他排障工作,因此本节仅给出标准命令形态与验证方法(dmesg | wc -l应为 0),未实际执行。日常排障建议优先用 4.4 节的快照方式留档,而不是频繁清空。
四、实战示例
4.1 开机后硬件健康巡检
目标:确认启动期有没有报错,并把最近的错误带上可读时间。-T --level=err 组合输出「最近 3 条 err 级别消息 + 墙上时间」:
$ dmesg -T --level=err | tail -n 3
[Thu Oct 15 14:01:11 2026] dmesg-demo: simulated nvme0n1 I/O error, sector 2048 not readable
[Thu Oct 15 14:01:11 2026] dmesg-demo: simulated udev worker error event
[Thu Oct 15 14:01:13 2026] dmesg-demo: follow mode message two
真实巡检中如果这里出现 I/O error、ECC、thermal 相关字样,就该进一步查磁盘/内存/散热;演示消息只是为了让回显可复现。
4.2 设备事件入账验证
目标:模拟一条设备插入事件,确认它进入内核缓冲区并可被检索。写入一条 USB 枚举消息后立即查看最后 1 行:
$ echo '<6>dmesg-demo: usb 1-1: new high-speed USB device number 5 attached' > /dev/kmsg
$ dmesg -T | tail -n 1
[Thu Oct 15 14:01:15 2026] dmesg-demo: usb 1-1: new high-speed USB device number 5 attached
写入即生效(实时性验证)。真实场景中插上 USB 设备后,用同样的 dmesg -T | tail -n 5 就能看到内核为新设备分配的端口号与厂商信息。
4.3 按设备名检索内核日志
目标:只看磁盘相关消息。用扩展正则匹配 sdX/nvme 设备名:
$ dmesg | grep -E 'sd[a-z]|nvme' | head -n 4
[ 10.364213] sd 2:0:0:0: [sda] 1677721600 512-byte logical blocks: (859 GB/800 GiB)
[ 10.364647] sd 2:0:0:0: [sda] Write Protect is off
[ 10.364660] sd 2:0:0:0: [sda] Mode Sense: 61 00 00 00
[ 10.365007] sd 2:0:0:0: [sda] Cache data unavailable
💡 要点:内核对磁盘的命名([sda])与 SCSI 通道号(sd 2:0:0:0)都在消息里,配合
grep -E是不装任何额外工具时最快的磁盘排障入口。
4.4 保存内核日志快照
目标:把当前缓冲区带时间戳落盘,用于故障复盘或清空前备份:
$ dmesg -T > /var/log/dmesg-snapshot.log; wc -l /var/log/dmesg-snapshot.log
2801 /var/log/dmesg-snapshot.log
$ tail -n 2 /var/log/dmesg-snapshot.log
[Thu Oct 15 14:01:13 2026] dmesg-demo: follow mode message two
[Thu Oct 15 14:01:15 2026] dmesg-demo: usb 1-1: new high-speed USB device number 5 attached
2801 行全量快照已保存,末尾正是 4.1/4.2 节注入的消息,落盘内容与缓冲区一致。
4.5 设施 + 级别 + 时间戳组合输出
目标:把过滤条件叠加——只要 user 设施的 err 级别、带可读时间、带设施:级别前缀:
$ dmesg -xT | grep dmesg-demo | tail -n 2
user :err : [Thu Oct 15 14:01:13 2026] dmesg-demo: follow mode message two
user :info : [Thu Oct 15 14:01:15 2026] dmesg-demo: usb 1-1: new high-speed USB device number 5 attached
-xT(解码前缀 + 墙上时间)再叠加 --level/--facility 即可精确圈定,如 dmesg -xT -l err --facility=user。参数之间全部可叠加,按「内容过滤(-l/-f)→ 时间格式(-T/-t/-e)→ 输出形态(-x/-H/--color)」三步组合即可覆盖绝大多数排障诉求。
五、注意事项与常见问题
Q1:dmesg: read kernel buffer failed: Operation not permitted 是怎么回事?
这是最常见的报错,有两种典型形态。形态一:kernel.dmesg_restrict=1 时,非特权用户读取被内核拒绝。先确认开关:
$ sysctl kernel.dmesg_restrict
kernel.dmesg_restrict = 1
形态二:即使是 uid=0 的 root,若运行环境未授予 CAP_SYSLOG 能力(本实验的最小化环境即如此),读缓冲区同样失败:
$ id -u
0
$ dmesg; echo rc=$?
dmesg: read kernel buffer failed: Operation not permitted
rc=1
用管道接其他命令时退出码会被掩盖(返回的是管道最后一个命令的退出码):
$ dmesg | tail -n 3; echo rc=$?
dmesg: read kernel buffer failed: Operation not permitted
rc=0
Q2:如何放开 dmesg 读取权限?
两条路:其一,具备 CAP_SYSLOG 的 root 账户(服务器上默认的 root 即是)不受 dmesg_restrict 限制——本文实测环境二在 kernel.dmesg_restrict=1 的情况下依然完整读到了 2798 行,所以普通用户加 sudo 运行即可;其二,放开 sysctl 开关让所有本地用户可读(标准形态,改完即生效):sudo sysctl -w kernel.dmesg_restrict=0;要开机持久生效则写入 /etc/sysctl.d/99-dmesg.conf(内容为 kernel.dmesg_restrict = 0 一行)后执行 sudo sysctl --system。
⚠️ 注意:内核日志包含物理地址、内核指针等信息,
dmesg_restrict=1是防信息泄露的安全加固项(配合 KASLR 生效)。多用户生产服务器建议保持默认的 1,需要看日志的账号走sudo dmesg按需读取,而不是全局放开。
Q3:为什么 dmesg 明明失败了,脚本的退出码却是 0? 见 Q1 第三段实测:管道中 dmesg 的失败退出码(1)被 tail 的 0 覆盖。排障脚本要么先单独执行 dmesg 判断退出码,要么把 dmesg 写入临时文件再处理,不要依赖管道末端的退出码。
Q4:-T 显示的时间可靠吗?
基本可靠但有已知盲区:--help 原文明确提示 Suspending/resume will make ctime and iso timestamps inaccurate.——系统休眠/恢复后,ctime 与 iso 格式的时间会失准,因为换算基于「内核单调时钟 + 本次开机时刻」。需要严格可信的时间线时用 journalctl -k(journald 在事件发生时即刻记录时间)。
Q5:dmesg 的日志会丢吗?
会。内核环形缓冲区是固定大小的内存环形队列:写满后新消息覆盖最旧消息;系统重启后缓冲区清零。所以 dmesg 只适合看「当前这次开机以来」的事件,历史追溯要用持久化设施——启用并使用 journalctl -k -b(本次开机)/journalctl -k -b -1(上次开机),或安装 rsyslog 让内核日志持续转存到 /var/log/kern.log。重要现场的缓冲区内容应尽快用 4.4 节的快照方式落盘。
Q6:journalctl -k 提示 "No journal files were found." 是什么情况?
本实验最小化环境的实测输出:
$ journalctl -k; echo rc=$?
No journal files were found.
-- No entries --
rc=0
含义是 journald 没有可读的日志文件(服务未持久化或当前用户不在可读组)。此时内核日志只能靠 dmesg 读实时缓冲区;要启用 journald 持久化,标准做法是创建 /var/log/journal 目录并重启 systemd-journald 服务,之后 journalctl -k 即可读到历史内核日志。另外 /var/log/kern.log 依赖 rsyslog 转存,本实验环境中该文件同样不存在:
$ ls -l /var/log/kern.log
ls: cannot access '/var/log/kern.log': No such file or directory
装好并启动 rsyslog 后该文件才会生成。
六、参考链接
- Ubuntu 22.04 手册页 dmesg(1):https://manpages.ubuntu.com/manpages/jammy/en/man1/dmesg.1.html
- man7.org syslog(2) 系统调用(内核缓冲区读取机制):https://man7.org/linux/man-pages/man2/syslog.2.html
- Linux 内核文档 kernel.dmesg_restrict 等 sysctl 说明:https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html
- /dev/kmsg 接口文档(内核源码树):https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg
- util-linux 上游源码仓库:https://github.com/util-linux/util-linux