一. 内核打印函数 printk 介绍
1.1 前言
内核提供了 printk 函数在内核运行时打印信息,类似于 C 语言中的 printf 函数。
使用方式:
1 | printk(<日志级别> "打印内容"); |
什么是日志级别? 日志级别表示这句 log 的严重等级,总共有 8 个级别,分别是 0-7,数字越小级别越高。kernel 中可以设置屏蔽一些低级别的 log 不打印出来。
printk 的日志级别定义在 linux-2.6.32.2/inlcude/linux/kernel.h 中:
1 |
简单解释一下:
- 紧急事件消息,系统崩溃前的提示,表示系统不可用
- 报告事件,表示必须立刻采取措施
- 临界条件,通常涉及严重的硬件或软件失败
- 错误条件,驱动程序通常用此等级报告硬件错误
- 警告条件,对可能出现的问题进行警告
- 正常又重要的信息,用于提醒
- 提示信息,打印运行时的提示信息
- 调试信息,调试级别的消息
Kernel 中可以修改 /proc/sys/kernel/printk 节点修改 printk 打印相关的配置。
1 | [root@FriendlyARM /]# cat /proc/sys/kernel/printk |
其实这四个值是在kernel/printk.c 中被定义的,这四个数值分别表示:
1 | int console_printk[4] = { |
简单解释一下:
- 当前控制台日志级别:优先级高于该值的消息将被打印至控制台
- 默认的消息日志级别:将用该优先级来打印没有优先级的消息
- 最高的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级)
- 默认的控制台日志级别:控制台日志级别的缺省值
当 printk 的消息日志级别小于当前控制台日志级别 DEFAULT_CONSOLE_LOGLEVEL 时,才会被打印出来。
1.2 示例模块
文件一:print_level.c
1 |
|
文件二:Makefile
1 | obj-m += print_level.o |
1.3 加载模块
加载卸载模块打印的信息:
1 | [root@FriendlyARM /mnt]# insmod print_level.ko |
修改控制台日志级别:
1 | [root@FriendlyARM /mnt]# cat /proc/sys/kernel/printk |
修改后加载卸载模块打印的信息:
1 | [root@FriendlyARM /mnt]# dmesg -c > 0 # 清空缓冲区 |
可以看出,只打印了 0-3 级别的 log 信息,完整的 log 信息可以用 dmesg 查看。
dmesg 命令被用于检查和控制内核的环形缓冲区。kernel 会将运行时的打印信息存储在 ring buffer 中。没有及时查看到的信息,可利用 dmesg 来查看。
1 | [root@FriendlyARM /mnt]# dmesg |
二. 封装 printk 打造一个专属的打印函数
2.1 前言
每次调试的时候都要加行号,加函数名调试,实在是太麻烦了,为什么不自己封装一个专属的 print log 的函数呢?
1 |
其中 __func__ __LINE__ 分别表示当前函数名和行号。
2.2 示例模块
文件一:log_module.c
1 |
|
文件二:Makefile
1 | obj-m += log_module.o |
2.3 加载模块
加载模块,看看打印效果。
1 | [root@FriendlyARM /mnt]# insmod log_module.ko |