文章目录
概述
klogd&syslogd
klogd
dmesg
dmesg获取内核log以及输出原理
dmesg与x86中dmesg的区别
使用方法
内核log在klogd dmesg中的数据流
klogd和dmesg的共同点和区别
参考资料:
概述
有的时候运行linux内核的设备(现在市场上有很多智能设备运行android或GNU/Linux)发生了死机、挂起或其他不正常的行为,但是该设备并没有连接控制台串口,如何获取内核log就需要这些工具了,内核可能发生过oops,通过这些工具可以查看发生错误的具体内容,帮助进行问题诊断。
下面简单介绍一下获取内核log工具的原理和使用。
klogd&syslogd
klogd
klogd是一个专门截获并记录 Linux 内核消息的守护进程,可以指定输出到控制台,文件或syslogd守护进程等,常用情况是把内核消息输出到syslogd进程,由syslogd统一处理。
0x12 syslogd
syslogd负责记录系统中kenel或应用程序(邮件、新闻等)产生的各种log信息的工具。这些信息被写入到系统文件中,通常是/var/log目录下,或者是输出到远程server,让使用者进行故障排除、追踪尝试非法入侵的使用者等等。
本文主要关注的是内核log,syslogd涉及到的log信息种类很多,并且都有对应等级描述,配置文件syslog.conf需要用规定的语法进行配置,内容比较多,这里不做过多介绍,要更详细了解syslogd及配置方法,请参考https://linux.die.net/man/8/syslogd。
klogd获取内核log通过两种方式,一种是系统调用syslog(),glibc对应用程序的API是klogctl(),两个函数的原型分别为:
int syslog(int type, char *bufp, int len); /* No wrapper provided in glibc */ /* The glibc interface */ #include <sys/klog.h> int klogctl(int type, char *bufp, int len);
另一种方式是,通过/proc/kmsg,以正常打开文件形式,通过系统调用open、read、write去操作。
klogd输出到syslogd的方法是通过glibc中的api,openlog 、syslog 、closelog,这几个函数的原型是:
#include <syslog.h> void openlog(const char *ident, int option, int facility); void syslog(int priority, const char *format, ...); void closelog(void);
内部操作都是通过socket实现,其中会在调用openlog的时候创建socket,调用syslog的时候实现发送,调用closelog关闭socket。需要了解更多,请参考glibc源码。
0x14 利用klogd&syslogd保存内核log
系统初始化时打开守护进程:
在/etc/inittab文件中指定控制台串口设备后添加如下指令:
# 启动klogd syslogd服务 null::respawn:/sbin/klogd -n null::respawn:/sbin/syslogd -n # 重启系统之前关闭 null::shutdown:/bin/killall klogd null::shutdown:/bin/killall syslogd
注意: 在init控制klogd和syslogd的情况下-n参数一定要加,否则会执行完之后直接退出,init进程会反复重启这两个守护进程。
syslogd配置保存内核消息
syslogd的配置文件/etc/syslog.conf添加内核log的配置
kern.* -/var/log/kern.log
上面配置的解释:kern是内核log的关键字,表示需要处理内核log, *是表示要保存所有级别的log, -代表每次有log写入要同步文件到磁盘,/var/log/kern.log是保存log的路径名称。
0x15 klogd在嵌入式系统中和PC中的区别
通常在嵌入式系统中由busybox提供系统工具,klogd也在其中,它支持两个选项c 和n:
-c 设置控制台消息的默认等级,内核消息等级由0到7,定义在内核代码的kern_levels.h头文件中
-n 上面已经解释过,由init进程控制klogd时要加上
而PC端的klogd要强大很多,可以输出到文件、动态配置内核log来源、动态加载内核符号表等帮助分析内核错误,例如oops。但是现在很多PC端的GNU/Linux系统发行版中已经不用klogd和syslogd了,它们已经被功能更强大的rsyslog服务所去取代。
dmesg
打印或控制kernel ring buffer,默认的行为是显示所有保存在kernel ring buffer中的log信息。
0x21 常用命令选项
-c 清除log
当完成打印显示后清除kernel ring buffer的内容。
-s 定义缓冲区大小
定义指定大小的缓冲区用于查询kernel ring buffer。默认大小为 16392(内核3.16 log buffer大小是16384字节),如果你设置了一个大于默认值的缓冲区,那就可以用这来查看完整的kernel ring buffer内容,下限是4096字节,如果比这个值小则改为4096。
-n 设置log级别
设置控制台输出log级别。比如,-n 1或-n alert选项阻止了除了内核panic信息之外的其他所有信息在控制台打印。所有级别的log信息仍然可以通过/proc/kmsg文件中获取,因此,syslogd(8)同样可以用来对信息的输出进行控制。当使用-n选项时,dmesg不会打印和清除kernel ring buffer中的内容。
-r
打印原始数据,也就是不加消息级别前缀
要注意真正的原始数据依赖于读取内核日志的方法。/dev/kmsg与系统调用syslog()不同。为了向后兼容,dmesg返回syslog的数据格式。也可以通过/dev/kmsg读取,例如,使用命令:
dd if=/dev/kmsg iflag=nonblock
dmesg获取内核log以及输出原理
- dmesg 的内核消息来源有两个,其中一个是系统调用syslog,和klogd是相同的,调用glibc的klogctl接口实现。
- 另一个是通过设备文件/dev/kmsg获取,通过系统调用open、read、write去操作dmesg通过获取内核log后,通过fwrite函数输出到stdout。
dmesg与x86中dmesg的区别
- busybox中只支持-c -n -s -r四个选项;
- buxybox 日志缓冲区最小是16k,最大是16M, x86最小是4096+8,没有设置上限;
- busybox只支持通过syslog系统调用读取内核日志,x86支持syslog系统调用和/dev/kmsg。
使用方法
- 终端命令行下输入命令
dmesg | less dmesg | grep keyword
内核log在klogd dmesg中的数据流
klogd和dmesg的共同点和区别
共同点:
1. 都是获取内核消息到用户空间;
2. 都可以通过系统调用syslog获取内核log;
3. 它们通过所有方法获取的内核log都是kernel ring buffer中的内容。
区别:
klogd输出log信息到文件或syslogd进程中,比较适用于无人值守的情况,当系统发生过挂起,或设备发生过断电重启,log仍然可以完好的保存。
dmesg获取log后输出到stdout,也就是终端屏幕或控制台串口,比较适用于实时查看kenrel ring buffer中的内容,比如事先并没有连接控制台,或内核log优先级设置的数字很低(优先级很高),或是log早已被其他应用程序繁多的log所淹没的情况下(android系统log很多)使用,通过dmesg仍然看以查看内核log。当然现在的ubuntu发行版中也保存了dmesg信息到文件中,但是rsyslog已经保存了内核log,对这个行为表示不理解。
参考资料:
klogd
http://www.linuxcommand.org/man_pages/klogd8.html
http://baike.baidu.com/link?url=DNO3mDsSEUT7pju2ujw9-WxT–wmxp4yAwCHayIBQLjya_O4d1BiBj8cdyeUyuSNwXIhCJWC7l0XYj_LHPpgy_
syslogd
https://linux.die.net/man/8/syslogd
dmesg
http://man7.org/linux/man-pages/man1/dmesg.1.html
内核源码地址:
linux工具源码地址:
https://www.kernel.org/pub/linux/utils/util-linux/
glibc源码地址
busybox源码地址
https://busybox.net/downloads/