使用 printk 进行消息记录¶
printk()
是 Linux 内核中最广为人知的函数之一。它是我们打印消息的标准工具,通常也是跟踪和调试最基本的方法。如果您熟悉 printf(3),您会发现 printk()
是基于它的,尽管它有一些功能差异
printk()
消息可以指定日志级别。格式化字符串虽然在很大程度上与 C99 兼容,但并不完全遵循相同的规范。它有一些扩展和一些限制(没有
%n
或浮点转换说明符)。请参阅如何正确使用 printk 格式说明符。
所有 printk()
消息都会被打印到内核日志缓冲区,这是一个通过 /dev/kmsg 导出到用户空间的环形缓冲区。读取它的常用方法是使用 dmesg
。
printk()
通常像这样使用
printk(KERN_INFO "Message: %s\n", arg);
其中 KERN_INFO
是日志级别(请注意,它与格式字符串连接在一起,日志级别不是一个单独的参数)。可用的日志级别有
名称 |
字符串 |
别名函数 |
---|---|---|
KERN_EMERG |
“0” |
|
KERN_ALERT |
“1” |
|
KERN_CRIT |
“2” |
|
KERN_ERR |
“3” |
|
KERN_WARNING |
“4” |
|
KERN_NOTICE |
“5” |
|
KERN_INFO |
“6” |
|
KERN_DEBUG |
“7” |
|
KERN_DEFAULT |
“” |
|
KERN_CONT |
“c” |
日志级别指定消息的重要性。内核根据消息的日志级别和当前的 *console_loglevel*(内核变量)决定是否立即显示消息(将其打印到当前控制台)。如果消息优先级高于(日志级别值较低)*console_loglevel*,则消息将被打印到控制台。
如果省略日志级别,则使用 KERN_DEFAULT
级别打印消息。
您可以使用以下命令检查当前的 *console_loglevel*
$ cat /proc/sys/kernel/printk
4 4 1 7
结果显示 *current*、*default*、*minimum* 和 *boot-time-default* 日志级别。
要更改当前的 console_loglevel,只需将所需的级别写入 /proc/sys/kernel/printk
。例如,要将所有消息打印到控制台
# echo 8 > /proc/sys/kernel/printk
另一种方法,使用 dmesg
# dmesg -n 5
将 console_loglevel 设置为将 KERN_WARNING (4) 或更严重的消息打印到控制台。有关更多信息,请参阅 dmesg(1)
。
作为 printk()
的替代方案,您可以使用用于日志记录的 pr_*()
别名。这个宏系列将日志级别嵌入到宏名称中。例如
pr_info("Info message no. %d\n", msg_num);
打印一条 KERN_INFO
消息。
除了比等效的 printk()
调用更简洁之外,它们还可以通过 pr_fmt()
宏使用格式字符串的通用定义。例如,在源文件顶部(在任何 #include
指令之前)定义此内容
#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
将使该文件中每个 pr_*() 消息都带有发起该消息的模块和函数名称作为前缀。
出于调试目的,还有两个有条件编译的宏:pr_debug()
和 pr_devel()
,除非定义了 DEBUG
(或者在 pr_debug()
的情况下还定义了 CONFIG_DYNAMIC_DEBUG
),否则它们会被编译掉。
函数参考¶
-
pr_fmt¶
pr_fmt (fmt)
pr_*() 宏用于生成 printk 格式字符串
参数
fmt
从 pr_*() 宏传递的格式字符串
描述
此宏可用于为 pr_*() 宏生成统一的格式字符串。一个常见的用途是在文件中为所有 pr_*() 消息添加一个通用字符串作为前缀。例如,在源文件的顶部定义此内容
#define pr_fmt(fmt) KBUILD_MODNAME “: “ fmt
将使文件中所有 pr_info、pr_emerg... 消息都带有模块名称作为前缀。
-
printk¶
printk (fmt, ...)
打印内核消息
参数
fmt
格式字符串
...
可变参数
描述
这是 printk()
。它可以从任何上下文中调用。我们希望它能够工作。
如果启用了 printk 索引,则从 printk_index_wrap 调用 _printk()。否则,printk 只是 #defined 到 _printk。
我们尝试获取 console_lock。如果我们成功,那就很简单了 - 我们记录输出并调用控制台驱动程序。如果我们无法获得信号量,我们将输出放入日志缓冲区并返回。console_sem 的当前持有者将注意到 console_unlock()
中的新输出;并在释放锁之前将其发送到控制台。
这种延迟打印的一个影响是,调用 printk()
然后更改 console_loglevel 的代码可能会中断。这是因为在实际打印发生时会检查 console_loglevel。
另请参阅:printf(3)
有关 C99 的格式字符串扩展,请参阅 vsnprintf()
文档。
-
pr_emerg¶
pr_emerg (fmt, ...)
打印紧急级别的消息
-
pr_alert¶
pr_alert (fmt, ...)
打印警告级别的消息
-
pr_crit¶
pr_crit (fmt, ...)
打印关键级别的消息
-
pr_err¶
pr_err (fmt, ...)
打印错误级别消息
-
pr_warn¶
pr_warn (fmt, ...)
打印警告级别消息
-
pr_notice¶
pr_notice (fmt, ...)
打印通知级别消息
-
pr_info¶
pr_info (fmt, ...)
打印信息级别消息
-
pr_cont¶
pr_cont (fmt, ...)
在同一行中继续上一条日志消息。
参数
fmt
格式字符串
...
格式字符串的参数
描述
此宏会扩展为带有 KERN_CONT 日志级别的 printk。它只应该在继续一条不包含换行符('n')的日志消息时使用。否则它会回退到 KERN_DEFAULT 日志级别。
-
pr_devel¶
pr_devel (fmt, ...)
有条件地打印调试级别消息
参数
fmt
格式字符串
...
格式字符串的参数
描述
如果定义了 DEBUG,此宏会扩展为带有 KERN_DEBUG 日志级别的 printk。否则它不执行任何操作。
它使用 pr_fmt()
来生成格式字符串。
-
pr_debug¶
pr_debug (fmt, ...)
有条件地打印调试级别消息