-
printk简介
内核源码中用来记录日志信息的函数,只能在内核源码范围内使用。用法和printf非常相似 -
printf 和 printk 对比
printf:glibc实现的打印函数,工作于用户空间
printk:内核模块无法使用glibc库函数,内核自身实现的一个类printf函数,但是需要指定打印等级(若不指定就是用默认的打印等级)。 -
printk函数使用
在使用printk时我们会将打印等级/日志级别
放到最开始的位置,如
printk(KERN_EMERG "EMERG\n");
我们没有设置日志级别时,会为他设一个默认的日志级别:default_message_loglevel。
只有当 printk() 中的消息日志级别小于当前控制台日志级别(console_printk[0])时,printk 的信息就会在控制台上显示。 -
printk打印等级相关定义如下
// include/linux/kern_levels.h
#define KERN_SOH "\001" /* ASCII Start Of Header */
...
#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 */
- 查看当前系统printk打印等级:
cat /proc/sys/kernel/printk
(不手动去修改的话就是依次打印源码中这四个数组成员的值)
只有 prink 指定的打印等级比 console 小 才能打印到console,等于都不行。
//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 默认控制台日志级别*/
};
/ #
/ #
/ #
/ # cat /proc/sys/kernel/printk
7 4 1 7
/ #
/ #
/ #
- 若要修改上述默认优先级设置:
1、修改源码
2、修改/proc/sys/kernel/printk文件
将要设置的值写入到/proc/sys/kernel/printk中。我们要先cat /proc/sys/kernel/printk来看一下这个文件中都有什么值。然后我们再写入。其中这里的格式为:控制台的日志级别、默认消息日志级别、最小控制台日志级别和默认控制台日志级别。而我们要设置的就是第一个控制台的日志级别。我们通过echo “W X Y Z” > /proc/sys/kernel/printk 将我们想要设置的四个值写入到/proc/sys/kernel/printk中。
通过 dmesg 可以查看 printk 的所有打印信息
-
内核log缓冲区大小有限制,缓冲区数据可能被冲掉
-
例程
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
// __init 是把该函数放到统一的段里,所有内核模块的入口函数都存到这个指定的段里,
// 等到内核调用了就释放这个段,一次节约内存空间
// __exit 同理
static int __init hello_init(void)
{
printk(KERN_EMERG"%s(%d):[KERN_EMERG]\r\n", __FILE__, __LINE__);
// 也可以手动替换上面的宏如下,效果是一样的
// printk("\001" "1""[ KERN_EMERG ] Hello World Module Init\n");
printk("\001" "7""%s(%d):[\"<7>\"]\r\n", __FILE__, __LINE__);
printk("\001" "6""%s(%d):[\"<7>\"]\r\n", __FILE__, __LINE__);
printk(KERN_DEBUG"\n\n%s(%d):[\"<7>\"]\r\n", __FILE__, __LINE__);
return 0;
}
static void __exit hello_exit(void)
{
printk("[ default ] goodbye\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("author");
MODULE_DESCRIPTION("hello world module");
MODULE_ALIAS("test_module");
- 编译测试
/ #
/ #
/ #
/ # cat /proc/sys/kernel/printk
7 4 1 7
/ #
/ #
/ # modprobe test.ko
/home/jl/linux/imx6ull/linux_driver/z_exercise/test.c(10):[KERN_EMERG]
/home/jl/linux/imx6ull/linux_driver/z_exercise/test.c(14):["<7>"]
/ #
/ #
/ #
- 补充
内核模块实验