欢迎来到Casey's Blog😉|

caseyzz

园龄:2年4个月粉丝:1关注:0

内核日志打印

https://code84.com/23329.html
https://blog.csdn.net/lu_embedded/article/details/116813900
https://zhuanlan.zhihu.com/p/543103513?utm_id=0


 用户态可以通过syslog相关的系统调用或者/proc文件以及/dev/kmsg设备节点来查看__log_buf的信息,这些操作都是通过do_syslog的系统调用接口来实现的。

kernel中打印日志形式

(1)printk
(2)pr_xxx (pr_debug支持动态打印)
(3)dev_xxx (dev_dbg支持动态打印)
(4)module_param_named (支持动态动态打印)
目前在kernel驱动代码中,不在建议直接使用printk直接添加打印信息,而是使用pr_debug、pr_info、dev_info、dev_dbg之类的函数替代,这些函数的本质还是printk打印,但相比具有以下优点:
(1)支持打印模块信息、dev信息(指的是dev_xxx)
(2)支持动态调试(dynamic debug)方式

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

printk函数主要做两件事:
1.将信息记录到log中;
2.调用控制台驱动来将信息输出。

##一.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 KERN_SOH "\001" /* ASCII Start Of Header */
#define KERN_SOH_ASCII '\001'
#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 */

说明:

  • KERN_EMERG 表示紧急事件,一般是系统崩溃之前提示的信息;

  • KERN_ALERT 表示必须立即采取行动的消息;

  • KERN_CRIT 表示临界状态,通常涉及严重的硬件或软件操作失败;

  • KERN_ERR 用于报告错误状态,设备驱动程序会经常使用该级别来报告来自硬件的问题;

  • KERN_WARNNING 对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重的问题;

  • KERN_NOTICE 表示有必要进行提示的正常情形,许多与安全相关的状况用这个级别进行汇报;

  • KERN_INFO 表示内核提示信息,很多驱动程序在启动的时候,用这个级别打印出它们找到的硬件信息;

  • KERN_DEBUG 用于调试信息;

##三.内核printk文件
调试内核模块时候,若调试信息太多可以通过修改/proc/sys/kernel/printk文件内容来控制。

cat /proc/sys/kernel/printk
7 4 1 7 # 默认值为7 4 1 7,值越小,优先级越高
  • 控制台日志级别: 优先级高于该值的消息将被打印至控制台

  • 默认的消息日志级别: 将用该优先级来打印没有优先级的消息

  • 最低的控制台日志级别: 控制台日志级别可被设置的最小值(最高优先级)

  • 默认的控制台日志级别: 控制台日志级别的缺省值

这四个值是在kernel/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 */
};

调整打印级别

1.在menuconfig中修改
MESSAGE_LOGLEVEL_DEFAULT 这个值是在KCONFIG中配置的

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

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

echo 1 4 1 7 > /proc/sys/kernel/printk

##四.使用用例
printk(KERN_ERR "GetIot: KERN_ERR\n");

如果没有设置消息的日志级别如:printk("GetIot: KERN_ERR\n");,默认使用default_message_loglevel级别。

当printk中的消息日志级别小于当前控制台的日志级别(console_printk[0])时,printk的信息就会在控制台上显示。

但无论当前控制台的日志级别是何值,即使没有在控制台打印出来,都可以通过下面两种方法查看日志:

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

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

##五.其他用法
pr_xxx

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

#define pr_emerg(fmt, ...) printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_devel(fmt, ...) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug(fmt, ...) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)

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

/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_DEBUG)
#include <linux/dynamic_debug.h>
/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
#define pr_debug(fmt, ...) \
dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif

默认情况下DEBUG宏是未定义的,要打开只需在要打印的log的文件定义即可。(.c里定义的宏只在当前文件有效)

dev_xxx
对于驱动程序,在<linux/device.h>里也提供了一些驱动模型诊断宏,例如dev_err,dev_warn,dev_info等等。使用它们,不仅可以按标记的消息级别打印,还会打印对应的设备和驱动信息,

#define dev_emerg(dev, fmt, ...) _dev_emerg(dev, dev_fmt(fmt), ##__VA_ARGS__)
#define dev_crit(dev, fmt, ...) _dev_crit(dev, dev_fmt(fmt), ##__VA_ARGS__)
#define dev_alert(dev, fmt, ...) _dev_alert(dev, dev_fmt(fmt), ##__VA_ARGS__)
#define dev_err(dev, fmt, ...) _dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__)
#define dev_warn(dev, fmt, ...) _dev_warn(dev, dev_fmt(fmt), ##__VA_ARGS__)
#define dev_notice(dev, fmt, ...) _dev_notice(dev, dev_fmt(fmt), ##__VA_ARGS__)
#define dev_info(dev, fmt, ...) _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__)

本文作者:caseyzz

本文链接:https://www.cnblogs.com/caseyzq/p/17358131.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   caseyzz  阅读(387)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起