printk 内核打印

网友投稿 752 2022-10-12

printk 内核打印

printk 内核打印

printk 在内核源码中用来记录日志信息的函数,只能在内核源码范围内使用,用法类似于 printf 函数。

printk 函数主要做两件事情:

将信息记录到 log 中;调用控制台驱动来将信息输出。

printk 介绍

printk 将内核信息输出到内核信息缓冲区中,内核缓冲区在 kernel/printk/printk.c 中定义:

static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);

内核信息缓冲区是一个环形缓冲区(Ring Buffer),因此,如果塞入的消息过多,则就会将之前的消息冲刷掉。

消息级别

Linux 内核共提供了八种不同的消息级别,分为级别 0~7。数值越大,表示级别越低,对应的消息越不重要。相应的宏定义在 ​​include/linux/kern_levels.h​​ 文件中。

#define/* ASCII Start Of Header */#define#define/* system is unusable */#define/* action must be taken immediately */#define/* critical conditions */#define/* error conditions */#define/* warning conditions */#define/* normal but significant condition */#define/* informational */#define/* debug-level messages */

说明:

​​KERN_EMERG​​ 表示紧急事件,一般是系统崩溃之前提示的消息;​​KERN_ALERT​​ 表示必须立即采取行动的消息;​​KERN_CRIT​​ 表示临界状态,通常涉及严重的硬件或软件操作失败;​​KERN_ERR​​ 用于报告错误状态,设备驱动程序会经常使用该级别来报告来自硬件的问题;​​KERN_WARNING​​ 对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重的问题;​​KERN_NOTICE​​ 表示有必要进行提示的正常情形,许多与安全相关的状况用这个级别进行汇报;​​KERN_INFO​​ 表示内核提示信息,很多驱动程序在启动的时候,用这个级别打印出它们找到的硬件信息;​​KERN_DEBUG​​ 用于调试信息。

内核 printk 文件

通过 ​​/proc/sys/kernel/printk​​ 文件可以调节 printk 的输出等级,该文件有 4 个数字值。例如,在 Ubuntu 上的值如下:

$ cat

四个数值的含义如下:

控制台日志级别:优先级高于该值的消息将被打印至控制台;默认的消息日志级别:将用该优先级来打印没有优先级的消息;最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级);默认的控制台日志级别:控制台日志级别的缺省值。

这四个值是在 ​​kernel/printk/printk.c​​ 中被定义的,如下:

int console_printk[4] = { CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */ MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */ CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */ CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */};EXPORT_SYMBOL_GPL(console_printk);

调整打印级别

在 menuconfig 中修改

修改 ​​CONFIG_MESSAGE_LOGLEVEL_DEFAULT​​ 的值,然后重新编译,更新内核。menuconfig 配置路径如下:

Kernel hacking ---> printk and dmesg options ---> (4) Default message log level (1-7)

在系统中修改

在系统运行期间,可以通过修改 /proc/sys/kernel/printk 中的值来改变内核打印效果。例如,屏蔽掉所有的内核 printk 打印,只需要把第一个数值调到最小值1或者0。

echo 1 4 1 7 >

使用示例

在使用 printk 时我们会将消息级别放到最开始的位置,例如:

printk(KERN_EMERG "GetIot: KERN_EMERG\n");printk(KERN_ALERT "GetIot: KERN_ALERT\n");printk(KERN_CRIT "GetIot: KERN_CRIT\n");printk(KERN_ERR "GetIot: KERN_ERR\n");printk(KERN_WARNING "GetIot: KERN_WARNING\n");printk(KERN_NOTICE "GetIot: KERN_NOTICE\n");printk(KERN_INFO "GetIot: KERN_INFO\n");printk(KERN_DEBUG "GetIot: KERN_DEBUG\n");

如果没有设置消息的日志级别,默认使用 ​​default_message_loglevel​​ 级别(该值可在 menuconfig 中修改)。

当 printk 中的消息日志级别小于当前控制台的日志级别(​​console_printk[0]​​)时,printk 的信息就会在控制台上显示。但无论当前控制台日志级别是何值,即使没有在控制台打印出来,都可以通过下面两种方法查看日志:

第一种是使用​​dmesg​​ 命令打印;第二种是通过​​cat /proc/kmsg​​ 来打印。

另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk 的信息也会追加到 /var/log/messages.log 中。

查看打印

将上述示例代码添加到 ​​最简单的内核模块​​​ 的 ​​hello_init​​​ 函数中,编译并执行 ​​insmod hello.ko​​ 安装模块。

dmesg

执行 ​​dmesg | tail​​ 将会看到如下打印:

[20120.194934] module init success[20120.194935] GetIot: KERN_EMERG[20120.194937] GetIot: KERN_ALERT[20120.194938] GetIot: KERN_CRIT[20120.194939] GetIot: KERN_ERR[20120.194940] GetIot: KERN_WARNING[20120.194940] GetIot: KERN_NOTICE[20120.194940] GetIot: KERN_INFO[20120.194941]

/proc/kmsg

也可以执行 ​​cat /proc/kmsg​​ 等待内核打印:

$ sudo cat /proc/kmsg <6>[20120.194934] module init success<0>[20120.194935] GetIot: KERN_EMERG<1>[20120.194937] GetIot: KERN_ALERT<2>[20120.194938] GetIot: KERN_CRIT<3>[20120.194939] GetIot: KERN_ERR<4>[20120.194940] GetIot: KERN_WARNING<5>[20120.194940] GetIot: KERN_NOTICE<6>[20120.194940] GetIot: KERN_INFO<7>[20120.194941]

其他用法

pr_xxx

除了直接使用 printk 加消息级别的方式,在 ​​​​ 中还定义了 pr_notice、pr_info、pr_warn、pr_err 等接口。使用这些 pr_xxx 接口,就可以省去指定消息级别的麻烦。

#define#define#define#define#define#define#define#define#define#define

需要注意的是,其他 ​​pr_XXX()​​​ 函数能无条件地打印,但 ​​pr_debug()​​​ 却不能。因为默认情况下它不会被编译,除非定义了 ​​DEBUG​​​ 或设定了 ​​CONFIG_DYNAMIC_DEBUG​​。

dev_xxx

对于驱动程序,在 ​​​​ 里也提供了一些驱动模型诊断宏,例如 dev_err、dev_warn、dev_info 等等。使用它们,不仅可以按标记的消息级别打印,还会打印对应的设备和驱动信息,这对于驱动调试来说相当重要。

#define#define#define#define#define#define#define#if#define#elif#define#else#define#endif

同样需要注意,​​deb_dbg()​​​ 也不是无条件打印的,除非定义了 ​​DEBUG​​​ 或设定了 ​​CONFIG_DYNAMIC_DEBUG​​​。一个相关约定是在已经开启了 ​​DEBUG​​​ 时,使用 ​​VERBOSE_DEBUG​​​ 来添加 ​​dev_vdbg()​​。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:使用谷歌TensorFlow框架的简单教程(谷歌TensorFlow开发者认证)
下一篇:熊猫分布密度制图(ArcPy实现)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~