一、printk()的介绍
Linux系统在开机的过程中我们可以看见很多打印信息,这都是Linux内核内部调用printk(level,message)函数打印出来的
其中level是定义的打印优先级,当优先级小于console_loglevel时定义的优先级小于当前日志的打印级别时,信息才会打印在控制终端(根据要打印信息的类型,分为0~7,其中0位最高级别),通常宏来指示日志优先级
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
其中console_loglevel的初始值是DEFAULT_CONSOLE_LOGLEVEL,可以通过sys_syslog()系统调用进行修改,或者修改文件/proc/sys/kernel/printk下的优先级,,这个文件中包含了4个整数值,分别是当前日志优先级,未明确指定的日志级别时的默认日志优先级,最小允许的日志优先级,引导时的默认日志优先级。向该文件中写入一个整数值,就会把当前日志文件的优先级修改为该值,修改方式为
echo 4 > /proc/sys/kernel/printk(linux内核2.6日志默认的优先级是4)
message是我们要打印出调试的信息
二、消息被记录的原理
在内核中有一个内核自定义的一个长度为__LOG_BUF_LEN(在内核配置时为该变量配置值,范围是4kb~1mb)字节ring buffer(循环缓冲区),Linux系统中所有的系统信息输出的信息都是调用printk()都被输出到这里(包含内核信息),
通常获得我们想要的信息,有两种方式,一种是直接读取ring buffer中的信息,另一种是查看/var/log下的文件。
1、直接使用dmesg命令
该命令直接从循环缓冲区中读取数据到stdout
2、通过查看/var/log下的文件
在Linux中有两个守护程序,klogd和syslogd
klogd这个进程会通过syslog()这个系统调用或者读取proc文件系统来得到printk()从ring buffer中得到的信息,也就是我们的内核信息。并且klogd也会把信息传给syslog这个进程的。
LINUX系统启动后,由/etc/init.d/sysklogd先后启动klogd,syslogd两个守护进程,其中syslogd通过/etc/syslog.conf这个配置文件将系统产生的信息分类记录到相应的log中,因此这个目录下会有很多文件,其中将klogd传输过来的内核信息记录到/var/log/messgae中。
需要注意的是!!!,syslogd获取内核信息依赖进程klogd,因此要想通过syslogd获得内核的信息,klogd和syslogd这两个守护进程必须同时存在(这时无论当前日志的级别是多少,klogd都会把内核消息输出到/var/log/messgae下。这里我的理解是把打印级别高的输出到控制台,而把所有的内核信息,无论打印级别高低,都输出到/var/log/messgae下),如果klogd没有运行,内核不会传递信息到用户空间,因此此时/var/log/messgae不会有信息,此时只能通过查看内核专门用来存放打印信息的目录/proc/kmsg。
因为循环缓冲区的大小是固定的因此不能无限制的存储日志信息,因此当缓冲区满了之后,printk()函数会从缓冲区的开头,通过覆盖之前的日志信息继续存储最新的信息,这样做会导致原来的信息丢失,但一般之前的信息对我们的调试没什么作用,因此这样做是有利的。
为了避免大量的输出信息影响调试,可以通过klogd -f选项指定文件,将信息输出到指定的文件内,或者强制杀死进程klogd,然后打开一个新的终端,使用命令cat /proc/kmsg将信息显示在新打开的终端。