Linux驱动 2026年4月22日 14 分钟

printk 日志级别详解

级别 名称 值 说明 0 KERN_EMERG 0 系统崩溃,系统不可用 1 KERN_ALERT 1 需要立即处理的紧…

级别名称说明
0KERN_EMERG0系统崩溃,系统不可用
1KERN_ALERT1需要立即处理的紧急情况
2KERN_CRIT2临界条件,严重硬件/软件故障
3KERN_ERR3错误条件,驱动报告错误
4KERN_WARNING4警告条件,可能出现问题
5KERN_NOTICE5正常但重要的信息
6KERN_INFO6信息级别,普通提示
7KERN_DEBUG7调试级别,详细调试信息

驱动开发中的使用示例

#include <linux/kernel.h>

static int __init hello_init(void)
{
    printk(KERN_EMERG   "Fatal: system is down!\n");    // 0级 - 极度紧急
    printk(KERN_ALERT   "Alert: hardware failure!\n"); // 1级 - 紧急
    printk(KERN_CRIT    "Critical: CPU overheating!\n");// 2级 - 严重
    printk(KERN_ERR     "Error: failed to read register\n");    // 3级 - 错误
    printk(KERN_WARNING "Warning: buffer near full\n");          // 4级 - 警告
    printk(KERN_NOTICE  "Notice: config updated\n");            // 5级 - 注意
    printk(KERN_INFO    "Info: driver initialized\n");          // 6级 - 信息
    printk(KERN_DEBUG   "Debug: function x() called\n");       // 7级 - 调试

    return 0;
}

简写形式(常用)

实际开发中通常省略前缀数字,使用预定义常量:

printk(KERN_EMERG   "System崩溃!\n");
printk(KERN_ALERT   "硬件故障!\n");
printk(KERN_CRIT    "严重错误!\n");
printk(KERN_ERR     "驱动错误: 寄存器读取失败\n");
printk(KERN_WARNING "警告: 缓冲区接近满\n");
printk(KERN_NOTICE  "通知: 配置已更新\n");
printk(KERN_INFO    "信息: 驱动加载成功\n");
printk(KERN_DEBUG   "调试: 入口函数被调用\n");

日志级别的控制机制

1. 当前日志级别

系统有一个当前日志级别,只有级别 >= 当前级别的消息才会输出到控制台。

# 查看当前日志级别
cat /proc/sys/kernel/printk

# 输出示例:6  4  1  7
# |   |   |   └── 最低级别(引导时的级别)
# |   |   └────── 默认级别
# |   └────────── 控制台日志级别
# └────────────── 当前日志级别

2. 级别阈值的作用

假设当前日志级别为 6

消息级别是否输出到控制台原因
0 (EMERG)0 < 6
1 (ALERT)1 < 6
2 (CRIT)2 < 6
3 (ERR)3 < 6
4 (WARNING)4 < 6
5 (NOTICE)5 < 6
6 (INFO)6 = 6
7 (DEBUG)7 > 6

级别数字越小越紧急,越优先显示。

3. 临时调整日志级别

# 临时设为 8(显示所有消息)
echo 8 > /proc/sys/kernel/printk

# 设为 3(只显示 ERR 及以上级别)
echo 3 > /proc/sys/kernel/printk

# 恢复默认值 4
echo 4 > /proc/sys/kernel/printk

4. 永久修改日志级别

# 在 /etc/sysctl.conf 中添加
vi /etc/sysctl.conf

# 写入以下内容(内核参数格式)
kernel.printk = 8 4 1 7

# 使其生效
sysctl -p

驱动开发中的最佳实践

1. 使用条件编译控制调试信息

#ifdef DEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "[DRIVER] " fmt, ##args)
#else
#define DPRINTK(fmt, args...) do {} while(0)
#endif

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello driver loaded\n");
    DPRINTK("Debug: init called\n");  // DEBUG 关闭时不输出
    return 0;
}

2. 统一的日志宏

#define DRV_INFO(fmt, args...)   printk(KERN_INFO   "[MYDRV] " fmt, ##args)
#define DRV_ERR(fmt, args...)    printk(KERN_ERR    "[MYDRV ERROR] " fmt, ##args)
#define DRV_WARN(fmt, args...)   printk(KERN_WARNING "[MYDRV WARN] " fmt, ##args)
#define DRV_DEBUG(fmt, args...)  printk(KERN_DEBUG  "[MYDRV DBG] " fmt, ##args)

static int __init hello_init(void)
{
    DRV_INFO("Driver initialized\n");
    DRV_ERR("Failed to register device\n");
    DRV_WARN("Using legacy mode\n");
    DRV_DEBUG("GPIO pin %d configured\n", pin);
}

3. 根据错误级别决定返回值

static int __init hello_init(void)
{
    int ret;

    ret = register_chrdev(0, "hello", &hello_fops);
    if (ret < 0) {
        printk(KERN_ERR "hello: chrdev registration failed\n");
        return ret;
    }

    printk(KERN_INFO "hello: driver registered, major=%d\n", ret);
    return 0;
}

在 menuconfig 中配置 DEBUG

内核提供了通用的 DEBUG 宏选项:

Kernel hacking  --->
    [*] Kernel debugging
    (8) Default console log level (0-7)

驱动中可以这样使用:

#include <linux/device.h>

#define DEBUG

#ifdef DEBUG
#define DBG(fmt, args...) printk(KERN_DEBUG fmt, ##args)
#else
#define DBG(fmt, args...) do {} while(0)
#endif

常用场景对照表

场景推荐级别示例
模块加载成功KERN_INFOprintk(KERN_INFO "driver loaded\n");
模块卸载KERN_INFOprintk(KERN_INFO "driver removed\n");
打开/关闭设备KERN_INFOprintk(KERN_INFO "device opened\n");
读取数据成功KERN_DEBUGprintk(KERN_DEBUG "read %d bytes\n", count);
寄存器读取失败KERN_ERRprintk(KERN_ERR "failed to read reg\n");
内存分配失败KERN_ERRprintk(KERN_ERR "kmalloc failed\n");
缓冲区溢出警告KERN_WARNINGprintk(KERN_WARNING "buffer overflow\n");
硬件检测到异常KERN_CRITprintk(KERN_CRIT "HW fault detected\n");
上一篇 menuconfig 与 Kconfig 详解

# Linux 内核配置系统 — menuconfig 与 Kconfig 详解 ## 目录 – [一、me...

下一篇 将驱动模块编译进内核的完整方法

# 将驱动模块编译进内核的完整方法 ## 目录 – [方法一:外部模块编译](#方法一外部模块编译最灵活) ...