您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 国内外标准规范 > 内核日志:API 及实现
zzhhaannggddii__cchhiinnaa中文技技术术主主题题软软件件下下载载社社区区技技术术讲讲座座内内核核日日志志::AAPPII 及及实实现现从内核到用户空间的日志M. Tim Jones, 独立撰稿人简简介介:: 在内核开发中,我们通常使用 printk 进行日志。但是您曾经考虑过它的过程,以及内核日志的底层实现吗?本文介绍了内核日志的整个过程,包括 printk 及用户空间日志文件的插入。发发布布日日期期:: 2010 年 11 月 09 日级级别别:: 中级其其他他语语言言版版本本:: 英文访访问问情情况况 :: 10103 次浏览评评论论:: 0 (查看 | 添加评论) 平均分 (3个评分)为本文评分TTiimm 的的联联系系方方式式Tim 是昀著名且多产的撰稿人之一。浏览 developerWorks 上 Tim 的所有文章。访问 Tim 的帐户。然后在 My developerWorks 与 Tim、其他作者及读者联系交流。使用日志进行调试的方法由来已久。日志不仅在理解系统的内部操作方面很有用,而且对于通过时间标记的日志中按时间顺序排列的消息所记录的系统活动的计时和关系也非常有用。本文首先通过介绍用于配置和收集日志信息的应用程序接口(API)来说明了内核的日志(见图 1 关于总结框架和组件的示意图)。然后,本文介绍了日志数据从内核到用户空间的移动过程。昀后,本文还介绍了基于内核的日志数据的目标:用户空间中使用 rsyslog 进行日志管理。图图 11.. 内内核核日日志志生生态态系系统统和和主主要要组组件件内核 API内核的日志是通过 printk 函数实现的,它与用户空间对应函数 printf(按格式打印)具有相似的作用。printf 命令在编程语言中已存在很长时间,昀近出现是在 C 语言中,但是昀早出现可以追溯到 50 年代和 60 年代的 Fortran(PRINT 和 FORMAT 语句)、BCPL(writf 函数;BCPL是 C 的前身)和 ALGOL 68 语言(printf 和 putf)。在内核中,printk(打印内核)可以使用与 printf 函数几乎一样的格式将将格式化消息写入到缓冲区。您可以在 ./linux/include/linux/kernel.h(及其实现 ./linux/kernel/printk.c)中看到 printk 的格式:intprintk(constchar*fmt,...);这个格式表示的是一个用于定义文本和格式的字符串(类似于 printf),它同时带有一组可变个数参数(由省略号表示 [...])。内内核核配配置置与与错错误误通过 printk 实现的日志是通过内核配置选项 CONFIG_PRINTK 激活的。虽然 CONFIG_PRINTK 一般都是激活的,但是不包含这个选项的系统对内核的调用会返回一个 ENOSYS 错误返回值。在使用 printk 时,您首先会发现的不同点更多是关于协议,而不是功能的。这个特性使用了 C 语言的一种模糊方面来简化消息级别和优先级的规内核日志:API 及实现第1页 共6页12-2-24 上午11:40范。内核允许每一个消息根据日志级别(定义不同消息重要必的八种级别之一)来分类。这些级别可以用来判断系统是否不可用(紧急消息)、是否发现严重状况(严重消息)或者是否为简单报告消息。 这个内核代码直接将日志级别定义消息的第一个参数,下面这个例子说明的就是严重消息的定义:printk(KERN_CRITErrorcode%08x.\n,val);注意,第一个参数并不一个真正的参数,因为其中没有用于分隔级别(KERN_CRIT)和格式字符的逗号(,)。KERN_CRIT 本身只是一个普通的字符串(事实上,它表示的是字符串 2;表 1 列出了完整的日志级别清单)。作为预处理程序的一部分,C 会自动地使用一个名为 字符串串联 的功能将这两个字符串组合在一起。组合的结果是将日志级别和用户指定的格式字符串包含在一个字符串中。注意,如果调用者未将日志级别提供给printk,那么系统就会使用默认值 KERN_WARNING(表示只有 KERN_WARNING 级别以上的日志消息会被记录。)表表 11.. 日日志志级级别别、、标标识识符符和和使使用用方方法法标标识识符符字字符符串串使使用用方方法法KERN_EMERG0紧急消息(导致系统崩溃)KERN_ALERT1必须立即处理的错误KERN_CRIT2严重错误(硬件或软件)KERN_ERR3错误状况(一般出现在驱动程序上)KERN_WARNING4警告状况(可能导致错误)KERN_NOTICE5不是错误,但是一个重要状况KERN_INFO6报告消息KERN_DEBUG7仅用于调试的消息KERN_DEFAULTd默认内核日志级别KERN_CONTc日志行继续(避免增加新的时间截)printk 可以在内核的任意上下文中调用。这个调用从 ./linux/kernel/printk.c 中的 printk 函数开始,它会在使用 va_start 解析可变长度参数之后调用 vprintk(在同一个源文件)。日日志志辅辅助助函函数数内核也提供了一些日志辅助函数,它们可以简化日志函数的使用。每一个日志级别都有一个对应的函数,它会扩展为 printk 函数的一个宏。例如,如果要使用 printk 处理 KERN_EMERG 日志级别时,您可以直接使用 pr_emerg。所有宏都已列在 ./linux/include/linux/kernel.h 文件中。vprintk 函数执行了许多管理级检查(递归检查),然后获取日志缓冲区的锁(__log_buf)。接下来,它会对输入的字符串进行日志级别检查;如果发现日志级别信息,那么对应的日志级别就会被设置。昀后,vprintk 会获取当前时间(使用函数 cpu_clock)并使用 sprintf(不是标准库版本,而是在 ./linux/lib/vsprintf.c 中实现的内部内核版本)将它转换成一个字符串。这个字符串会被传递给 printk,然后它会被一个管理缓冲边界(emit_log_char)的特殊函数复制到内核日志缓冲区中。这个函数昀后将获取和释放执行控制台信号,并将下一条日志消息发送到控制台(在 release_console_sem 中执行)。内核缓冲缓冲区的大小初始值为 4KB,但是昀新的内核大小已经升级到 16KB(在不同的体系架构上,这个值昀高可以达到 1MB)。至此,您已经了解用于将日志消息插入到内核环缓冲区的 API。现在,让我们讨论一下用于将数据从内核移动到用户空间的方法。内核日志与接口多用途的 syslog 系统调用提供了内核的日志缓冲区访问方法。这个调用执行了很多个操作,所有操作都可以在用户空间执行,但是只有一个操作可以被非 root 用户执行。syslog 系统调用的原型定义位于 ./linux/include/linux/syslog.h;而它的实现位于 ./linux/kernel/printk.c。ssyysslloogg((22)) vvss.. ssyysslloogg((33))注意,这里定义的 syslog(syslog(2))与发送消息到系统日志(syslog(3))的 API 是不同的。后者允许将消息发送到 syslog(通过以特定优先级调用的日志处理函数 open、close 和 write 实现)。syslog 调用是作为内核日志消息环缓冲区的输入/输出(I/O)和控制接口。通过 syslog 调用,应用程序可以读取日志消息(部分、整体或者只读取新消息), 以及控制环缓冲区的行为(清除内容、设置日志的消息级别、启用或禁用控制台等等)。图 2 用图形说明了使用所讨论的主要组件进行日志记录的过程。FFiigguurree 22.. 标标识识主主要要组组件件的的内内核核日日志志内核日志:API 及实现第2页 共6页12-2-24 上午11:40syslog 调用(在内核中调用 ./linux/kernel/printk.c 的 do_syslog)是一个相对较小的函数,它能够读取和控制内核环缓冲区。注意在 glibc 2.0中,由于词汇 syslog 使用过于广泛,这个函数的名称被修改成 klogctl,它指的是各种调用和应用程序。syslog 和 klogctl(在用户空间中)的原型函数定义为:intsyslog(inttype,char*bufp,intlen);intklogctl(inttype,char*bufp,intlen);type 参数是用于传递所执行的命令,它指定了可选的缓冲区长度。有一些命令(如清除环缓冲)是忽略 bufp 和 len 这两个参数的。虽然前面两个命令类型不会对内核进行任何操作,但是其余命令则是用于读取日志消息或控制日志。其中有三个命令是用于读取日志消息的。SYSLOG_ACTION_READ 用于阻塞操作,直至日志消息到达后才释放该操作,然后将它们返回到所提供的缓冲区。这个命令会处理这些消息(旧的消息将不会出现在这个命令的后续调用中)。SYSLOG_ACTION_READ_ALL 命令会从日志读取昀后 n 个字符(而 n 是在传递给 klogctl 的参数'len' 中定义的)。SYSLOG_ACTION_READ_CLEAR 命令会先执行 SYSLOG_ACTION_READ_ALL 操作,然后执行SYSLOG_ACTION_CLEAR 命令(清除环缓冲区)。SYSLOG_ACTION_CONSOLE ON 和 OFF 可以将日志级别设置为激活或禁用日志消息输出到控制台,而 SYSLOG_CONSOLE_LEVEL 则允许调用者定义控制台所接受的日志消息级别。昀后,SYSLOG_ACTION_SIZE_BUFFER 是用于返回内核环缓冲区大小,而 SYSLOG_ACTION_SIZE_UNREAD 则返回当前内核环缓冲区可读取的字符数。表 2 显示了 SYSLOG 命令的完整清单。表表 22.. 使使用用 ssyysslloogg//kkllooggccttll 系系统统调调用用实实现现的的命命令令命命令令//操操作作代代码码作作用用SYSLOG_ACTION_CLOSE(0)关闭日志(未实现)SYSLOG_ACTION_OPEN(1)打开日志(未实现)SYSLOG_ACTION_READ(2)从日志读取SYSLOG_ACTION_READ_ALL(3)从日志读取所有消息(非破坏地)SYSLOG_ACTION_READ_CLEAR(4)从日志读取并清除所有消息SYSLOG_ACTION_CLEAR(5)清除环缓冲区SYSLOG_ACTION_CONSOLE_OFF(6)Disable printks to the consoleSYSLOG_ACTION_CONSOLE_ON(7)激活控制台 printkSYSLOG_ACTION_CONSOLE_LEVEL(8)将消息级别设置为控制接受SYSLOG_ACTION_SIZE_UNREAD(9)
本文标题:内核日志:API 及实现
链接地址:https://www.777doc.com/doc-1085197 .html