Linux 内核日志 dmesg 进阶实战:从现场过滤到持久化闭环

工业边缘设备突然重启、串口看不到输出、网关离线后自动恢复、USB 转串口设备消失、eMMC 写入异常、进程被 OOM Killer 杀掉,这些问题往往最早出现在内核日志里。dmesg 是查看 Linux 内核环形缓冲区的入口,适合快速拿到驱动、硬件、内存、块设备、网络和内核异常的第一现场。

但 dmesg 不是完整的日志系统。内核环形缓冲区容量有限、重启后丢失、日志可能被高噪声覆盖,容器里看到的也是宿主机全局内核日志。工程化使用时必须回答三个问题:怎么过滤出有效证据;怎么把关键日志持久化;怎么把内核日志与业务指标、告警和时间线关联起来。

本文按现场排障顺序整理 dmesg 的进阶用法,并结合 journalctl、rsyslog、sysctl 和工业边缘运维场景,构建一条从采集、过滤、留存到告警的闭环。

一、先理解 dmesg 能看到什么

dmesg 读取的是内核日志环形缓冲区,主要来源包括:

  • 内核与驱动初始化信息;
  • 硬件错误、MCE、EDAC、I/O 错误;
  • 内存不足与 OOM Killer 记录;
  • 网卡、USB、串口、块设备驱动事件;
  • 内核 WARN / Oops / Panic;
  • 通过 /dev/kmsg 写入的用户态或容器日志。

它有几个重要边界:

边界 工程含义
环形缓冲区容量有限 高噪声场景会覆盖早期日志
默认保存在内存中 重启后 dmesg 现场通常丢失
不是完整系统日志 systemd、应用、登录审计应看 journalctl 或应用日志
全局视角 容器内 dmesg 不能按容器隔离内核日志
权限可控 kernel.dmesg_restrict 开启后需要 root 或相应 capability
时间为单调时钟 -T 转换的系统时间在休眠、时钟跳变场景要谨慎解读

因此,dmesg 适合现场快速判断,journalctl -k 与集中式日志才适合长期审计和事后追溯。

二、基础命令与常用参数

1. 快速查看

bash 复制代码
# 查看内核环形缓冲区
dmesg

# 显示人类可读时间
dmesg -T

# 更适合人工阅读的输出
dmesg -H

# 只看内核 facility,通常与默认 dmesg 等价
dmesg -k

# 过滤错误级别
sudo dmesg -l err

# 过滤 warning 及以上常见级别,注意级别是列表匹配,不是数值区间
sudo dmesg -l emerg,alert,crit,err,warning

# 实时跟随
sudo dmesg --follow

# 只显示新产生的日志
sudo dmesg --follow-new

-l 的取值包括 emerg、alert、crit、err、warning、notice、info、debug。如果要看多个级别,需要显式列出;不同发行版的 util-linux 版本可能还有选项差异,可先执行:

bash 复制代码
dmesg --help
dmesg --version

2. 参数口径

参数 含义 工程注意点
-T 显示系统时间 受时钟跳变、休眠恢复影响
-H 人类可读输出 常隐含分页,脚本中要谨慎
-k 只看 kern facility dmesg 默认也主要读取内核日志
-l 按日志级别过滤 是列表匹配,不是"低于/高于"
-f 按 facility 过滤 可区分 kern、user、daemon 等
--since / --until 按时间过滤 依赖 util-linux 版本,建议现场确认支持
--follow 跟随读取 适合现场观察,不适合替代采集器
--follow-new 只显示新日志 避免启动日志干扰
-n 设置控制台日志级别 不改变缓冲区里已经记录的内容
-C 清空缓冲区 排障前不要随手清空,会破坏证据

原文中把 dmesg -P 写成"不带前缀"是不准确的。-P 在 util-linux 中是 --nopager,用于禁止分页;-p 并不是现代 dmesg 的标准"err 及以上"过滤参数。过滤级别应使用 -l 或 journalctl -p。

3. 权限与安全

bash 复制代码
# 查看是否限制非 root 读取
sysctl kernel.dmesg_restrict

# 读取 dmesg
sudo dmesg -T

工业设备不建议为了方便而长期关闭 kernel.dmesg_restrict。需要采集时,优先让日志采集组件以最小权限运行,或将内核日志统一交给 journald、rsyslog、Fluent Bit 等组件转发。

三、过滤出有效证据

1. 按时间过滤

如果当前系统安装的 util-linux 支持 --since / --until,可以直接过滤:

bash 复制代码
dmesg -T --since "1 hour ago"
dmesg -T --since "2026-10-19 08:00:00"
dmesg -T --since "1 hour ago" --until "10 minutes ago"

更稳妥的跨启动方式是使用 journald:

bash 复制代码
# 当前启动
sudo journalctl -k -b 0 --no-pager

# 上一次启动
sudo journalctl -k -b -1 --no-pager

# 今天以来的 warning 及以上
sudo journalctl -k --since today -p warning --no-pager

# 按正则搜索
sudo journalctl -k -b --grep "OOM|I/O error|Hardware Error" --no-pager

注意:journalctl -b -1 只有在 journald 持久化开启且历史日志未被清理时才可用。

2. 按级别过滤

bash 复制代码
sudo dmesg -T -l emerg,alert,crit,err
sudo journalctl -k -b -p err --no-pager
sudo journalctl -k -b -p warning --no-pager

journalctl -p err 与 dmesg -l err 的语义不同。journalctl 的优先级过滤通常按阈值语义处理,而 dmesg -l 是显式级别列表匹配。脚本化采集时要统一口径,避免误以为二者完全等价。

3. 按 facility 过滤

bash 复制代码
dmesg -f kern
dmesg -f user
dmesg -f kern,daemon

工业现场常见的干扰是应用或容器直接向 /dev/kmsg 写日志,导致真正的硬件错误被淹没。处理方式不是盲目调低内核日志级别,而是:

  • 审计谁在写 /dev/kmsg;
  • 收敛应用直接写内核日志的行为;
  • 对采集日志做级别与关键字分层;
  • 将硬件错误、OOM、内核异常单独路由到高优先级通道。

四、典型故障排查

1. 硬件与 MCE 错误

bash 复制代码
sudo dmesg -T | grep -iE 'hardware error|mce|machine check|edac|ecc'
sudo journalctl -k -b --grep 'Hardware Error|MCE|EDAC|ECC' --no-pager

重点看是否出现内存 ECC 错误、CPU Machine Check、PCIe AER、温度或电源相关异常。内核日志只能给出第一线索,还需要继续采集:

bash 复制代码
sudo dmidecode -t memory
sudo ras-mc-ctl --summary
lspci -vv
sensors

如果只是偶发一次,需要结合发生时间、现场温度、供电、负载和机箱震动综合判断;如果错误持续增长,应按硬件故障处理。

2. OOM 与内存压力

bash 复制代码
sudo dmesg -T | grep -iE 'out of memory|oom|killed process'
sudo journalctl -k -b --grep 'Out of memory|Killed process' --no-pager

# 查看 OOM 前后的完整上下文
sudo dmesg -T | grep -B 30 -A 40 -i 'killed process'

重点确认:

  • 被杀进程是谁,是否是网关主进程;
  • 进程 RSS 与系统可用内存;
  • 是否存在 cgroup memory limit;
  • 是否是页缓存、tmpfs、容器内存叠加导致;
  • 是否有内存泄漏趋势;
  • swap 是否存在以及是否适合该设备。

容器场景应同时查看 cgroup:

bash 复制代码
cat /sys/fs/cgroup/memory.current
cat /sys/fs/cgroup/memory.max
cat /sys/fs/cgroup/memory.events

内核 OOM 与 cgroup OOM 的处理方向不同:前者通常要评估整机内存和现场负载,后者可能是单个容器 limit 配置过小。

3. 存储与 I/O 错误

bash 复制代码
sudo dmesg -T | grep -iE 'i/o error|blk_update_request|medium error|nvme|mmc|ata|scsi'
sudo journalctl -k -b --grep 'I/O error|EXT4-fs error|XFS|mmc|nvme' --no-pager

需要同步确认设备健康和文件系统状态:

bash 复制代码
lsblk -o NAME,TYPE,SIZE,ROTA,MOUNTPOINTS
df -hT
sudo smartctl -a /dev/sda
sudo dmesg -T --follow

工业边缘设备常见诱因包括 eMMC 磨损、SD 卡质量问题、供电不稳、高温、文件系统只读和写放大。不要只依据一条 I/O error 就更换硬件,要确认具体设备、扇区、错误频率和业务影响。

4. 网络链路异常

bash 复制代码
sudo dmesg -T | grep -iE 'eth|link is|carrier|nic|phy|timeout|reset'
sudo journalctl -k -b --grep 'link|carrier|eth0|timeout' --no-pager

如果日志中出现反复 link down / link up、PHY reset、TX timeout,需要继续看:

bash 复制代码
ip -s link
ethtool eth0
ethtool -S eth0
ss -s

重点区分硬件链路问题、驱动问题、电源休眠策略、交换机侧异常和现场网络抖动。

5. USB 与串口设备

bash 复制代码
# 插入设备前先启动跟随
sudo dmesg -Tw

# 查看设备枚举与断开
sudo dmesg -T | grep -iE 'usb|tty|cp210|ftdi|ch34|cdc_acm'

工业现场要特别记录设备插入瞬间、断开瞬间和驱动绑定结果:

bash 复制代码
lsusb -t
ls -l /dev/serial/by-id
udevadm info -a -n /dev/ttyUSB0

如果设备 ID 不断变化,应用应使用 /dev/serial/by-id 或 udev 规则绑定稳定路径,而不是硬编码 /dev/ttyUSB0。

6. 内核 Oops、WARN 与 Panic

bash 复制代码
sudo dmesg -T | grep -iE 'bug:|oops:|panic|warning:|call trace|general protection'
sudo journalctl -k -b --grep 'BUG:|Oops:|panic|Call Trace' --no-pager

看到 Oops 或 Panic 时,先保存完整日志,再重启或恢复设备:

bash 复制代码
sudo journalctl -k -b --no-pager -o short-precise > kernel-panic.log
uname -a > kernel-version.txt

如果配置了 kdump,还应保留 vmcore,并用 crash 或厂商工具进一步分析调用栈。

五、现场证据打包

排障时建议一次性保存以下信息,文件名包含设备编号和采集时间:

bash 复制代码
TS=$(date +%Y%m%d-%H%M%S)
OUT=/tmp/edge-kernel-$TS
mkdir -p "$OUT"

sudo dmesg -T -P > "$OUT/dmesg.txt"
sudo journalctl -k -b --no-pager -o short-precise > "$OUT/kernel-journal.txt"
sudo journalctl -p err -b --no-pager > "$OUT/system-errors.txt"

uname -a > "$OUT/uname.txt"
uptime > "$OUT/uptime.txt"
ip -s link > "$OUT/ip-link.txt"
lsblk -o NAME,TYPE,SIZE,ROTA,MOUNTPOINTS > "$OUT/lsblk.txt"
df -hT > "$OUT/df.txt"
free -h > "$OUT/free.txt"

tar -czf "${OUT}.tar.gz" -C /tmp "edge-kernel-$TS"

这样能避免"重启以后证据消失"的被动局面。对无人值守站点,采集动作应内置到远程运维流程或故障自动上报机制中。

六、持久化:让内核日志跨重启留存

1. journald 持久化

推荐优先启用 journald 持久化,而不是自己写脚本长期执行 dmesg -w。

创建配置文件:

ini 复制代码
# /etc/systemd/journald.conf.d/90-edge-kernel.conf
[Journal]
Storage=persistent
Compress=yes
SystemMaxUse=500M
MaxRetentionSec=30day

启用并检查:

bash 复制代码
sudo mkdir -p /etc/systemd/journald.conf.d
sudo systemctl restart systemd-journald

# 确认持久化目录存在
ls -ld /var/log/journal

# 查看磁盘占用
journalctl --disk-usage

# 查询当前启动
journalctl -k -b 0 --no-pager | tail -n 20

如果 /var/log/journal 不存在,journald 在 Storage=auto 下通常只使用易失存储,重启后历史日志会丢失。存储空间有限的边缘设备要同时配置 SystemMaxUse 和保留周期,避免日志挤占业务数据空间。

2. rsyslog 单独落盘

如果站点已有 rsyslog 体系,可以把内核日志单独写入文件:

text 复制代码
# /etc/rsyslog.d/90-edge-kernel.conf
kern.* /var/log/kern.log

重启并验证:

bash 复制代码
sudo systemctl restart rsyslog
logger -p kern.warning "kernel log pipeline test"
tail -n 10 /var/log/kern.log

rsyslog 方案要同步配置轮转和磁盘上限:

text 复制代码
/var/log/kern.log {
    daily
    rotate 14
    compress
    missingok
    notifempty
    copytruncate
}

对于大规模站点,更推荐将 journald 或 rsyslog 转发到集中式日志平台,本地保留短期证据,远端保留长期审计数据。

七、实时监测与告警

1. 现场实时观察

bash 复制代码
sudo dmesg --follow-new
sudo journalctl -kf -n 0 --no-pager

长时间保存时不要用无节制的管道直接写文件:

bash 复制代码
# 可用于短时间现场观察
sudo journalctl -kf -o short-precise | tee kernel-live.log

生产环境应使用 journald、rsyslog、Fluent Bit、Vector 等组件采集。它们自带缓冲、重试、轮转、格式化和集中转发能力,比手写 dmesg -w 管道可靠。

2. 简单关键字分层

bash 复制代码
sudo journalctl -kf -n 0 -o short-precise |
while IFS= read -r line; do
    case "$line" in
      *"Hardware Error"*|*"Machine Check"*|*"EXT4-fs error"*|*"XFS"*"error"*|*"Out of memory"*|*"Killed process"*|*"BUG:"*|*"Kernel panic"*)
        printf '%s\n' "[critical] $line"
        ;;
      *"I/O error"*|*"link is down"*|*"usb"*"disconnect"*|*"over-current"*)
        printf '%s\n' "[warning] $line"
        ;;
    esac
done

真正接入告警时还需要增加:

  • 关键字去重;
  • 时间窗口内的频率限制;
  • 设备、站点、版本标签;
  • 值班升级策略;
  • 恢复通知;
  • 与 CPU、内存、I/O、网络、业务错误率联动判断。

否则一条周期性 USB 断连日志可能在深夜生成上百条告警,反而掩盖真正严重的硬件故障。

八、sysctl 与控制台级别

1. dmesg -n 的真实作用

bash 复制代码
# 查看当前控制台日志级别
cat /proc/sys/kernel/printk

# 设置控制台日志级别为 7
sudo dmesg -n 7

# 只在控制台输出 emerg 级别,减少串口噪声
sudo dmesg -n 0

/proc/sys/kernel/printk 的四个数值分别对应:

位置 含义
第 1 个 当前控制台日志级别
第 2 个 未指定级别的默认消息级别
第 3 个 最小控制台日志级别
第 4 个 默认控制台日志级别

重点:dmesg -n 只影响哪些级别会输出到控制台,不会减少内核环形缓冲区记录,也不会改变 journald 采集到的日志。串口输出过多时可以调低控制台级别,但不建议为了"让屏幕干净"去清空环形缓冲区。

2. Panic 自动重启

ini 复制代码
# /etc/sysctl.d/90-edge-recovery.conf
kernel.panic = 10
kernel.panic_on_oops = 1

应用配置:

bash 复制代码
sudo sysctl --system
sysctl kernel.panic kernel.panic_on_oops

kernel.panic = 10 表示 panic 后延迟 10 秒重启;0 表示不自动重启。panic_on_oops = 1 会把 Oops 视为 panic 处理,能避免内核继续在不一致状态下运行,但可能把原本可恢复的问题变成服务重启,必须结合业务可用性要求评估。

3. 访问控制

ini 复制代码
# /etc/sysctl.d/90-edge-dmesg.conf
kernel.dmesg_restrict = 1

开启后普通用户不能直接读取内核日志,有利于降低内核地址和设备信息暴露面。运维采集账号应有明确的授权和审计。

九、工业边缘的工程化实践

实践 建议做法
持久化优先 开启 journald persistent,并配置容量上限
集中转发 本地短期留存,平台侧长期审计
关键字分层 硬件、OOM、Panic、I/O、网络、USB 分级处理
保留上下文 不只保存 grep 结果,要保存前后日志和时间线
与业务关联 将内核日志与设备离线、指令失败、I/O 延迟对齐
保留版本信息 采集内核版本、驱动版本、硬件型号、系统启动时间
控制噪声 收敛应用直写 /dev/kmsg,告警做去重和限流
保护现场 排障前不清空 dmesg,重启前先保存证据
权限最小化 采集组件单独授权,不放开所有用户访问
定期演练 人为注入 USB 断连、网络抖动、内存压力,验证采集与告警链路

十、常见坑与修正

常见坑 实际影响 修正方式
以为 dmesg 日志重启后仍在 查上次故障时证据已丢 开启 journald 持久化或集中采集
dmesg -C 清空缓冲区 丢失最早硬件线索 排障前禁止清空,先保存日志
把 -n 7 当作"记录更多日志" 它只影响控制台输出 调整日志级别、驱动 verbosity 或采集策略
只看 grep 后的单行结果 缺少调用栈、前后事件和设备上下文 保存 journalctl -k -b 全量日志
容器内直接看 dmesg 内核日志是宿主机全局的 以宿主机采集为主,再关联容器 cgroup 与业务日志
告警关键字过宽 少量噪声就造成告警风暴 分级、去重、限流并联动业务指标
日志没有容量控制 /var/log 写满导致服务异常 配置 SystemMaxUse、轮转和磁盘告警
忽略时间同步 -T 时间无法与平台日志对齐 启用 NTP / PTP,并记录时钟同步状态

十一、TL;DR

Linux 内核日志排障的核心链路是:dmesg 看现场,journalctl -k 查启动与历史,journald 或 rsyslog 做持久化,集中日志平台做长期审计。常用入口包括 -T、-l、-f、--follow、--since;典型场景覆盖硬件错误、OOM、I/O 异常、网络抖动、USB 断连、Oops 和 Panic。

要特别记住:dmesg -n 控制的是控制台输出级别;dmesg -P 是禁止分页;跨启动日志依赖持久化;生产告警不能只靠一条 grep 管道。把内核日志与设备状态、业务指标、版本信息和远程运维流程关联起来,才能真正支撑工业边缘系统的长期稳定运行。

十二、下一步建议

  1. 开启 journald 持久化,并验证上次启动日志可查;
  2. 建立硬件、OOM、I/O、网络、USB、Panic 的关键字分层;
  3. 将内核日志接入集中式采集和告警平台;
  4. 为远程站点固化"故障证据自动打包"流程;
  5. 定期演练断网、断电、存储异常和内存压力场景。

如果在工业边缘运行时中评估内核日志采集、异常识别和远程运维能力,可以参考 Zenova EdgeOS 在日志留存、故障证据打包和运维审计方面的工程实践。

相关推荐
郝亚军2 小时前
ec_private.pem的生成方法
linux·运维·服务器
NendoZen2 小时前
Arch Linux解决Grub无法SAVEDEFAULT问题(uki启动问题)
linux·运维·服务器
Elastic 中国社区官方博客3 小时前
Elasticsearch:安装自行管理的 Elastic Stack 集群
大数据·运维·服务器·数据库·elasticsearch·搜索引擎·全文检索
忆挽篱笙歌3 小时前
进程控制管理
linux·运维·服务器
Escalating_xu3 小时前
【Linux 网络编程】connect 的断线重连:用状态机写一个能恢复连接的 TCP 客户端
linux·网络·tcp/ip
Zucker n5 小时前
英语“论文”语法检查工具
linux·windows
fengkai45455 小时前
3、Kubernetes的Namespace&Contexts&Pod&YAML格式
运维·容器·kubernetes·k8s·namespace·yaml·pod
2401_868534785 小时前
局域网络中信息安全方案设计及攻击防范技术(制造企业园区网)
服务器·网络
戴西软件5 小时前
制造研发中的AI视觉与仿真:戴西工程图纸智能审图智能体、戴西3DViz_CAE AI集成与戴西3DViz_CAD AI集成
大数据·运维·人工智能·3d·自动化·制造·rpa