3、printk日志级别实战:如何选择合适的日志级别、动态调整控制台日志级别
printk 的日志级别,说白了就是给内核消息贴了个「重要性标签」。我刚开始接触内核调试时,总觉得这玩意儿可有可无——反正都是打印,有啥区别?直到有一次,我在一个嵌入式项目里被海量日志刷屏刷到怀疑人生……嗯,从那以后,我再也不敢小看日志级别了。
3.1 日志级别到底是个啥?
printk 的日志级别,本质是一个数字,范围从 0 到 7。数字越小,消息越紧急。你可以把它想象成「警报等级」:0 是火灾警报,7 是楼下大爷闲聊。
内核源码里定义了一组宏,方便我们使用:
#define KERN_EMERG "<0>" /* 系统崩溃,没救了 */
#define KERN_ALERT "<1>" /* 必须立即处理 */
#define KERN_CRIT "<2>" /* 严重错误 */
#define KERN_ERR "<3>" /* 错误 */
#define KERN_WARNING "<4>" /* 警告 */
#define KERN_NOTICE "<5>" /* 正常但重要 */
#define KERN_INFO "<6>" /* 信息 */
#define KERN_DEBUG "<7>" /* 调试信息 */
用法很简单:
printk(KERN_ERR "DMA 传输失败,状态码: %d\n", status);
printk(KERN_INFO "网卡已初始化,MAC: %pM\n", mac_addr);
printk(KERN_DEBUG "当前缓冲区指针: %p\n", buf_ptr);
我个人习惯是:开发阶段全用 KERN_DEBUG,等代码稳定了再逐级提升。你想想看,要是上线后还满屏的调试信息,那运维同事怕是要提着键盘来找你。
3.2 控制台日志级别:谁说了算?
光有消息级别还不够,还得有个「过滤器」——这就是控制台日志级别。内核通过 /proc/sys/kernel/printk 这个文件来控制哪些消息能显示到控制台。
这个文件里有 4 个数字:
$ cat /proc/sys/kernel/printk
7 4 1 7
这四个数字分别代表:
| 位置 | 含义 | 默认值 |
|---|---|---|
| 第1个 | 控制台日志级别 | 7(显示所有) |
| 第2个 | 默认消息日志级别 | 4(KERN_WARNING) |
| 第3个 | 最小控制台日志级别 | 1(KERN_ALERT) |
| 第4个 | 默认控制台日志级别 | 7 |
核心规则就一条:消息级别 ≤ 控制台日志级别 时,消息才会显示。数字越小越紧急,所以控制台日志级别设得越低,显示的消息越少。
举个例子:控制台日志级别设为 3(KERN_ERR),那么只有 KERN_EMERG、KERN_ALERT、KERN_CRIT、KERN_ERR 这四级消息能显示。KERN_WARNING 及以下的统统被过滤掉。
3.3 动态调整:不改代码,改文件
这是我最常用的技巧。调试时把级别调高,上线后调低,全程不用改一行代码。
方法一:直接写文件
# 只显示 KERN_ERR 及以上的消息
echo "3 4 1 7" > /proc/sys/kernel/printk
# 显示所有消息(调试模式)
echo "7 4 1 7" > /proc/sys/kernel/printk
方法二:用 sysctl 命令
# 查看当前设置
sysctl kernel.printk
# 设置控制台日志级别为 4
sysctl -w kernel.printk="4 4 1 7"
我的小习惯:调试驱动时,我一般先设成 "8 4 1 7"。8 比 7 还大,意味着所有级别的消息都能显示。等调试完了再改回 "4 4 1 7",只保留警告和错误。
3.4 实战场景:怎么选级别?
我在项目中踩过不少坑,总结了一套「选级指南」:
- KERN_EMERG (0):系统要挂了,比如内存耗尽、内核 panic。平时别用,用了容易吓到人。
- KERN_ALERT (1):必须立刻处理的事,比如硬件过热、电池电量极低。
- KERN_CRIT (2):严重错误,但系统还能苟延残喘。比如磁盘 I/O 错误。
- KERN_ERR (3):功能出错了,但系统整体还能跑。比如驱动加载失败、设备断开。
- KERN_WARNING (4):有问题但没崩。比如配置不推荐、性能下降。
- KERN_NOTICE (5):正常但值得注意。比如设备热插拔、模块加载。
- KERN_INFO (6):普通信息。比如驱动版本号、初始化完成。
- KERN_DEBUG (7):调试专用。开发时随便用,上线前记得删掉或改成更高等级。
我曾经犯过的错:在一个量产项目里,我把调试信息全用了 KERN_ERR。结果客户现场一跑,控制台疯狂刷屏,系统响应慢得像蜗牛。后来排查才发现,是某个循环里每毫秒打印一次「正常状态」……从那以后,我严格区分「错误」和「调试」,绝不混用。
3.5 知识体系:一张图看懂
下面这张 SVG 图,把 printk 日志级别的核心逻辑串起来了。你可以把它当作「调试时的速查手册」:
3.6 避坑指南:我踩过的几个坑
坑一:忘记改回默认级别
我曾经调试完一个驱动,把控制台级别设成了 8,然后直接提交了代码。结果同事拉代码后,控制台被调试信息刷爆……嗯,从那以后我养成了习惯:调试完立刻改回 "4 4 1 7"。
坑二:在生产环境用 KERN_DEBUG
这个不用多说,谁用谁后悔。生产环境里,KERN_DEBUG 的消息会大量消耗 CPU 和 I/O,严重拖慢系统。我建议生产环境只保留 KERN_WARNING 及以上。
坑三:混淆「消息级别」和「控制台级别」
这两个概念容易搞混。记住一句话:消息级别是「我有多重要」,控制台级别是「多重要的消息才能显示」。前者是标签,后者是过滤器。
我的调试三板斧:
- 开发阶段:控制台级别设 8,所有消息全看
- 集成测试:控制台级别设 4,只看警告和错误
- 生产环境:控制台级别设 3,只看错误和更严重的
这样既不会漏掉关键信息,也不会被无关日志淹没。
好了,关于 printk 日志级别,核心内容就这些。记住:级别选对了,调试事半功倍;级别选错了,调试生不如死。你自己品品,是不是这个理?