关于Linux的syslog

内核中printk发出的消息是这样传递到用户空间的。

内核留给用户空间的接口是syslog(2),glibc对它进行了包装,于是就有了klogctl(3)和syslog(3)。

先由klogd通过klogctl(3)搜集内核消息(见sysklogd/klogd.c),并通过自己实现的syslog()(注意:和syslog(2),syslog(3)都不一样)传递给 syslogd。syslogd根据/etc/syslog.conf的配置情况进行记录。syslogd提供的是一个统一的方式,它不单单记录内核的消息,还包括其它服务器进程的消息,比如Apache,vsftp。

klogd和syslogd用的syslog()的实现用的是Unix domain socket,如果你看源代码(sysklogd/syslog.c)的话很容易就知道这一点。所以,所谓的syslog()/openlog()/closelog()等接口无非就是对这个socket操作的一个包装。这也就清楚了klogd和syslogd之间的通信方式。

根据syslogd的源代码(sysklogd/syslogd.c)来看,记录日志也可以是发送到远程的,而那个socket就是用的inet socket了。

多说一句,其实内核给出的oops只是一堆地址,而把地址和相应的符号对应起来也是由klogd完成的。sysklogd/ksym.c里有搜索System.map的过程,搜索的顺序是:
“/boot/System.map”
“/System.map”
“/usr/src/linux/System.map”

这就是最好的证据。一些细心的人或许还会奇怪,我们不是还有/proc/kallsyms么?怎么不用它?我知道的解释是:为了照顾那些没有/proc文件系统的Linux系统。;-)

我们再来看syslog(3),即glibc实现的syslog()。看一下glibc中的源代码,我们就会发现glibc中的syslog和sysklogd自己的实现类似,也是用unix domain socket来实现的。具体可以看:glibc/misc/syslog.c。

这两种实现之所以都能够传递给syslogd,是因为它们的unix domain socket都是用的/dev/log这个文件。

而我们最常用的查看内核消息的命令dmesg(1)和上面两位守候进程没太大关系,它是直接通过glibc的klogctl(3)函数来读取内核消息的。详细见:util-linux-2.13-pre7/sys-utils/dmesg.c。

如果想了解更多关于syslogd的东西,可以参考这篇文章

想了解内核的中对syslog(2)的实现,可以参考内核源代码:kernel/printk.c。