您的位置:首页 > 运维架构 > Linux

Linux printk and log level

2016-01-09 18:46 459 查看


只有当printk打印信息时的loglevel小于console loglevel的值(即:优先级高于console loglevel),这些信息才会被打印到console上。

改变console loglevel的方法有如下几种:

1.启动时Kernel boot option:loglevel=level

2.运行时Runtime: dmesg -n level

(注意:demsg -n level 改变的是console上的loglevel,dmesg命令仍然会打印出所有级别的系统信息。)

3.运行时Runtime: echo $level > /proc/sys/kernel/printk

4.运行时Runtime:写程序使用syslog系统调用(可以man syslog)

123456789101112131415#include <unistd.h>#include <sys/syscall.h> static inline int syslog(int type, char *bufp, int len){ return syscall(SYS_syslog, type, bufp, len);} int main(){ /* Set the console loglevel to 4 */ syslog(8, 0, 4); return 0;}
在kernel boot option中:
loglevel Set the default console log level.
loglevel=level
Specify the initial console log level. Any log messages with levels less than this (that is
26594
, of higher priority) will be printed to the console, whereas any messages with levels equal to or greater than this will not be displayed.
The console log level can also be changed by the klogd program, or by writing the specified level to the /proc/sys/kernel/printk file. (在2.6.32及之上kernel的Linux系统中,我没有找到klogd这个程序了,应该是有所变化了)
  printk有8个loglevel,定义在中:#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 ""

/*

* 标注为一个“连续”的日志打印输出行(只能用于一个

* 没有用 \n封闭的行之后). 只能用于启动初期的 core/arch 代码

* (否则续行是非SMP的安全).

*/

#define KERN_CONT ""
     如果使用时没有指定日志等级,内核会选用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定为“”,将无关紧要的调试记录等级“KERN_DEBUG”定为“<7>”KERN_ERR, KERN_DEBUG等是一些宏定义,在$Linux_SRC/include/linux/printk.h中可以查看到。dmesg是从kernel的ring buffer(环缓冲区)中读取信息的.
man dmesg得到如下信息:
dmesg is used to examine or control the kernel ring buffer.
The program helps users to print out their bootup messages. Instead of copying the messages by hand, the user need only: dmesg > dmesg.log
最后特别提醒:1、虽然printk很健壮,但是看了源码你就知道,这个函数的效率很低:做字符拷贝时一次只拷贝一个字节,且去调用console输出可能还产生中断。所以如果你的驱动在功能调试完成以后做性能测试或者发布的时候千万记得尽量减少printk输出,做到仅在出错时输出少量信息。否则往console输出无用信息影响性能。
2、printk的临时缓存printk_buf只有1K,所有一次printk函数只能记录<1K的信息到log buffer,并且printk使用的“ring buffer”那什么是ring buffer呢?
在LINUX中,所有的系统信息(包内核信息)都会传送到ring buffer中。而内核产生的信息由printk()打印出来。系统启动时所看到的信息都是由该函数打印到屏幕中。printk()打出的信息往往以 <0>…<2>… 这的数字表明消息的重要级别。高于一定的优先级别(当前的console loglevel)就会打印到console上,否则只会保留在系统的缓冲区中(ring buffer)。
至于dmesg具体是如何从ring buffer中读取的,大家可以看dmesg.c源代码。$Linux-SRC/arch/m68k/tools/amiga/dmesg.c,很短,比较容易读懂。默认的loglevel在kernel/printk.c中有定义:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

/*printk'swithoutaloglevelusethis..*/

#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL

 

/*WeshoweverythingthatisMOREimportantthanthis..*/

#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people
use */

#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG
*/

 

DECLARE_WAIT_QUEUE_HEAD(log_wait);

 

intconsole_printk[4]={

        DEFAULT_CONSOLE_LOGLEVEL,      /*console_loglevel*/

        DEFAULT_MESSAGE_LOGLEVEL,      /*default_message_loglevel*/

        MINIMUM_CONSOLE_LOGLEVEL,      /*minimum_console_loglevel*/

        DEFAULT_CONSOLE_LOGLEVEL,      /*default_console_loglevel*/

};

cat /proc/sys/kernel/printk

4 4 1 7

所得到的信息是$Linux_SRC/include/linux/printk.h中定义的宏:

#define console_loglevel (console_printk[0])

#define default_message_loglevel (console_printk[1])

#define minimum_console_loglevel (console_printk[2])

#define default_console_loglevel (console_printk[3])

依次分别为:

控制台日志级别:优先级高于该值的消息将被打印至控制台

缺省的消息日志级别:将用该优先级来打印没有优先级的消息

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

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

为了下面我做的一个实验:

首先,需要一个module,我的loglevel.c代码如下:

123456789101112131415161718192021222324252627282930313233343536#include <linux/module.h>       /* Needed by all modules */#include <linux/kernel.h>       /* Needed for log level */#include <linux/init.h>         /* Needed for the macros */ MODULE_AUTHOR("Jay, <Jay's email> ");MODULE_DESCRIPTION("To test: console log level.");MODULE_LICENSE("GPL");MODULE_VERSION("Version-0.0.1"); static int __init hello_start(void){printk(KERN_INFO "Loading loglevel module...\n");printk(KERN_INFO "Hello, Jay.\n");printk(KERN_EMERG "------------------------------------\n"); printk(KERN_EMERG "Hello, EMERG.\n");printk(KERN_ALERT "Hello, ALERT.\n");printk(KERN_CRIT "Hello, CRIT.\n");printk(KERN_ERR "Hello, ERR.\n");printk(KERN_WARNING"Hello, WARNING.\n");printk(KERN_NOTICE "Hello, NOTICE.\n");printk(KERN_INFO "Hello, INFO.\n");printk(KERN_DEBUG "Hello, DEBUG.\n"); printk(KERN_EMERG "------------------------------------\n"); return 0;} static void __exit hello_end(void){printk(KERN_INFO "Goodbye, Jay.\n");} module_init(hello_start);module_exit(hello_end);
将这个module编译好之后,有了loglevel.ko这个module文件。

1

2

3

[root@vt-snb9~]#
cat /proc/sys/kernel/printk

7      4      1      7

[root@vt-snb9~]#
insmod /root/loglevel/loglevel.ko

console上打印的信息如下:

##注意DEBUG级别的信息没有打印在console上

Loading loglevel module…

Hello, Jay.

————————————

Hello, EMERG.

Hello, ALERT.

Hello, CRIT.

Hello, ERR.

Hello, WARNING.

Hello, NOTICE.

Hello, INFO.

————————————

改变console loglevel之后,

123[root@vt-snb9 ~]# cat /proc/sys/kernel/printk4      4       1       7[root@vt-snb9 ~]# insmod /root/loglevel/loglevel.ko
##注意”Hello, Jay.”这样的INFO级别的就没有打印到console上
————————————
Hello, EMERG.
Hello, ALERT.
Hello, CRIT.
Hello, ERR.
————————————在kernel启动项目中加入了debug,则启动后:

1

2

3

[root@vt-snb9~]#
cat /proc/sys/kernel/printk

10      4      1      7

[root@vt-snb9~]#
insmod /root/loglevel/loglevel.ko

##注意这次DEBUG等级的信息也被打印在console上了

Loading loglevel module…

Hello, Jay.

————————————

Hello, EMERG.

Hello, ALERT.

Hello, CRIT.

Hello, ERR.

Hello, WARNING.

Hello, NOTICE.

Hello, INFO.

Hello, DEBUG.

————————————

而dmesg始终都是可以打印出module所print出来的所有信息的,不管console loglevel为多少,当insmod loglevel之时,dmesg始终会打印如下信息:
Loading loglevel module...

Hello, Jay.

------------------------------------

Hello, EMERG.

Hello, ALERT.

Hello, CRIT.

Hello, ERR.

Hello, WARNING.

Hello, NOTICE.

Hello, INFO.

Hello, DEBUG.

------------------------------------


另外,最后见说一下syslogd吧(或者新的叫做rsyslogd进程)。 在比较新的系统(比如RHEL6.1)中,syslogd已经存在了,取而代之的是rsyslogd,功能是差不多的,配置文件在/etc/rsyslogd.conf

syslogd这个守护进程根据/etc/syslog.conf,将不同的服务产生的Log记录到不同的文件中.

LINUX系统启动后,由/etc/init.d/sysklogd先后启动klogd,syslogd两个守护进程。

其中klogd会通过syslog()系统调用或者读取/proc/kmsg文件来从系统缓冲区(ring buffer)中得到由内核printk()发出的信息.而syslogd是通过klogd来读取系统内核信息.

(1)所有系统信息是输出到ring buffer中去的,dmesg所显示的内容也是从ring buffer中读取的.

(2)LINUX系统中/etc/init.d/sysklogd会启动2个守护进程:Klogd, Syslogd

(3)klogd是负责读取内核信息的,有2种方式:

syslog()系统调用(这个函数用法比较全,大家去MAN一下看看);

直接的对/proc/kmsg进行读取(再这提一下,/proc/kmsg是专门输出内核信息的地方)

(4)Klogd的输出结果会传送给syslogd进行处理,syslogd会根据/etc/syslog.conf的配置把log信息输出到/var/log/下的不同文件中.

可以将printk与syslog接合使用, 用在内核开发方面很不错的应用:

修改/etc/syslog.conf (或者是/etc/rsyslogd.conf)

kern.* /tmp/my_kernel_debug.txt

就可将kernel的信息输出到文件中了,这样更方便查看。

日志文件详细地记录了系统每天发生的各种各样的事件。用户可以通过日志文件检查错误产生的原因,或者在受到攻击和黑客入侵时追踪攻击者的踪迹。日志的两个比较重要的作用是:审核和监测。

Linux系统的日志主要分为两种类型:

1.进程所属日志

由用户进程或其他系统服务进程自行生成的日志,比如服务器上的access_log与error_log日志文件。

2.syslog消息 【syslogd, klogd协同作用,前面以及提及,新版本中都没了klogd了】

系统syslog记录的日志,任何希望记录日志的系统进程或者用户进程都可以给调用syslog来记录日志。

日志系统可以划分为三个子系统:

1.连接时间日志–由多个程序执行,把纪录写入到/var/log/wtmp和/var/run/utmp,login等程序更新wtmp和utmp文件,使系统管理员能够跟踪谁在何时登录到系统。

2.进程统计–由系统内核执行。当一个进程终止时,为每个进程往进程统计文件(pacct或acct)中写一个纪录。进程统计的目的是为系统中的基本服务提供命令使用统计。

3.错误日志–由syslogd(8)执行。各种系统守护进程、用户程序和内核通过syslog(3)向文件/var/log/messages报告值得注意的事件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: