内核打印
printk 说明
在开发Linux device Driver
或者跟踪调试内核行为的时候经常要通过Log API
来trace
整个过程,Kernel API printk()
是整个Kernel Log
机制的基础API
,几乎所有的Log
方式都是基于printk
来实现的。
当然,利用printk
还有一些需要注意的地方,在详细讲述之前先分析一下printk()
实现,大致流程如下图所示:
从上图可以看出,printk
的流程大致可以分为两步:
将所有
Log
输出到内核的Log Buffer
,该Log Buffer
是一个循环缓冲区,其地址可以在内核中用log_buf
变量访问根据设定的
Log
级别决定是否将Log
输出到Console
基于以上内容,我们打印的Log
最终会走向两个位置:
Log Buffer
:该Buffer
里面的内容可以存储在/proc/kmsg
Console
:Console
的实现可以有很多,目前我们用到的有UART Console
(串口)和RAM Console
。通向UART Console
的Log
会在对应的UART
端口打印出来。
对于Console Log
,不可避免的对系统性能有影响。所以对于Console Log
设置了两道关卡
第一个是对
Log
级别进行过滤,只能输出高优先级的Log
;第二个是为
UART
设置单独的开关,在不必要的时候可以将其关闭以提高系统性能。这里提到了Log
优先级,那什么是Log
优先级呢?
printk 日志等级设置
Linux 内核为printk定义了8个打印等级,KERN_EMERG
等级最高,KERN_DEBUG
等级最低。在内核配置时,有一个宏来设定系统默认的打印等级 CONFIG_MESSAGE_LOGLEVEL_DEFAULT
,通常该值设置为4
,那么只有打印等级高于4
时才会打印到终端或者串口。kern_levels.h
#define KERN_EMERG KERN_SOH "0" /* system is unusable 紧急事件,一般是系统崩溃之前的提示消息 */
#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately 必须立即采取行动 */
#define KERN_CRIT KERN_SOH "2" /* critical conditions 临界状态,通常涉及严重的硬件或者软件操作失败 */
#define KERN_ERR KERN_SOH "3" /* error conditions 报告错误状态,经常用来报告硬件错误 */
#define KERN_WARNING KERN_SOH "4" /* warning conditions 对可能出现问题的情况进行警告,通常不会对系统造成严重问题 */
#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition 有必要的提示,通常用于安全相关的状况汇报 */
#define KERN_INFO KERN_SOH "6" /* informational 提示信息,驱动程序常用来打印硬件信息 */
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages 用于调试信息 */
```一个有`8`个等级,从`0`到`7`,优先级依次降低。
通常通过修改`/proc/sys/kernel/printk`来设置`printk`打印。
cat /proc/sys/kernel/printk
7 4 1 7
//打开所有的内核打印
echo 8 > /proc/sys/kernel/printk
cat /proc/sys/kernel/printk
8 4 1 7
4个值的含义依次如下:
console_loglevel
:当前console
的log
级别,只有更高优先级的log
才被允许打印到console
;default_message_loglevel
:当不指定log
级别时,printk
默认使用的log
级别;minimum_console_loglevel
:console
能设定的最高log
级别;default_console_loglevel
:默认的console
的log
级别。
另外,关于printk
格式化字符串形式,参考printk-formats.txt
使用dmesg
命令,可以显示之前所有的打印信息,常配合grep
来查找历史纪录。
屏蔽等级日志控制机制
屏蔽如下代码片段:
文件目录:kernel\kernel\printk\printk.c
/*
* Call the console drivers, asking them to write out
* log_buf[start] to log_buf[end - 1].
* The console_lock must be held.
*/
static void call_console_drivers(int level, const char *text, size_t len)
{
struct console *con;
trace_console(text, len);
/*
if (level >= console_loglevel && !ignore_loglevel)
return;
if (!console_drivers)
return;
#ifndef CONFIG_DYNAMIC_DEBUG
if (!perf_mode_console)
return;
#endif
*/
for_each_console(con) {
if (exclusive_console && con != exclusive_console)
continue;
if (!(con->flags & CON_ENABLED))
continue;
if (!con->write)
continue;
if (!cpu_online(smp_processor_id()) &&
!(con->flags & CON_ANYTIME))
continue;
con->write(con, text, len);
}
}
printk打印常用方式
打印对应函数名(func
)及对应行数(LINE
)
printk("[me]%s[%d].\n",__func__,__LINE__);
最后编辑:SteveChen 更新时间:2025-03-30 18:07