日志等级
内核根据日志级别来判断是否在终端(console)上打印消息:内核把级别比某个特定值低的所有消息显示在终端(console)上。但是所有信息都会记录在printk的“ring buffer”中。
printk有8个loglevel,定义在<linux/kernel.h>中:
- #define KERN_EMERG "<0>"/* 系统不可使用 */
- #define KERN_ALERT "<1>"/* 需要立即采取行动*/
- #define KERN_CRIT "<2>"/* 严重情况 */
- #define KERN_ERR "<3>"/* 错误情况 */
- #define KERN_WARNING "<4>" /* 警告情况*/
- #define KERN_NOTICE "<5>" /* 正常情况, 但是值得注意*/
- #define KERN_INFO "<6>"/* 信息型消息 */
- #define KERN_DEBUG "<7>"/* 调试级别的信息 */
- /* 使用默认内核日志级别*/
- #define KERN_DEFAULT "<d>"
- /*
- * 标注为一个“连续”的日志打印输出行(只能用于一个
- * 没有用 \n封闭的行之后). 只能用于启动初期的 core/arch 代码
- * (否则续行是非SMP的安全).
- */
- #define KERN_CONT "<c>"
如果使用时没有指定日志等级,内核会选用DEFAULT_MESSAGE_LOGLEVEL,这个定义位于kernel/printk.c:
- /* printk's without a loglevel use this..*/
- #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
可以看出,这个等级是可以在内核配置时指定,这种机制是从2.6.39开始有的,如果你不去特别配置,那么默认为<4>,也就是KERN_WARNING。
内核将最重要的记录等级 KERN_EMERG定为“<O>”,将无关紧要的调试记录等级“KERN_DEBUG”定为“<7>”。
内核用这些宏指定日志等级和当前终端的记录等级console_loglevel来决定是不是向终端上打印,使用示例如下:
- printk(KERN_EMERG"log_level:%s\n", KERN_EMERG);
当编译预处理完成之后,前例中的代码实际被编译成成如下格式:
- printk( "<0>" "log_level:%s\n", KERN_EMERG);
给一个printk()什么日志等级完全取决于你。那些正式、且需要保持的消息应该根据信息的性质给出相应的日志等级。但那些为了解决一个问题临时加得到处都是的调试信息可以有两种做法:
一种选择是保持终端的默认记录等级不变,给所有调试信息KERN CRIT或更低的等级以保证信息一定会被输出。
另一种方法则相反,给所有调试信息KERN DEBUG等级,而调整终端的默认记录等级为7,也可以输出所有调试信息。
两种方法各有利弊。
这里说到了调整内核的默认的日志级别,在我3年半前的学习笔记《 Linux设备驱动程序学习(2)-调试技术 》中有介绍,可以通过 /proc/sys/kernel/printk来改变,或者C程序调用syslog系统调用来实现。但是现在的glibc的函数接口改了,由于 syslog 这个词使用过于广泛,这个函数的名称被修改成 klogctl,所以原来博文中的代码无法使用了,以下是新版的 console_loglevel代码:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- //#define __LIBRARY__/* _syscall3and friends are only available through this */
- //#include<linux/unistd.h>
- /* define the systemcall, to override the library function */
- //_syscall3(int, syslog,int, type, char*, bufp,int, len);
- int main(int argc, char**argv)
- {
- int level;
- if (argc == 2){
- level = atoi(argv[1]);/* the chosen console*/
- } else {
- fprintf(stderr,"%s: need a single arg\n", argv[0]);
- exit(1);
- }
- if (klogctl(8,NULL, level)< 0) {
- fprintf(stderr,"%s: syslog(setlevel): %s\n",
- argv[0], strerror(errno));
- exit(1);
- }
- exit(0);
- }