klogd&syslogd与dmesg-嵌入式系统获取linux内核log


概述

有的时候运行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

扫描二维码关注公众号,回复: 8746683 查看本文章

系统初始化时打开守护进程:
  在/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的区别

  1. busybox中只支持-c -n -s -r四个选项;
  2. buxybox 日志缓冲区最小是16k,最大是16M, x86最小是4096+8,没有设置上限;
  3. 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,对这个行为表示不理解。

参考资料:

发布了78 篇原创文章 · 获赞 25 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_37596943/article/details/103624719
今日推荐