由于守护进程并不拥有控制终端,因此无法将进程运行信息输出显示。但有时候需要根据进程提供的信息来进行系统管理和维护工作。为此,Linux系统提供了一种特殊的机制来解决守护进程的日志问题。syslogd守护进程通过接收其他守护进程的信息,并将这些信息记录在指定位置来解决日志记录问题。syslogd守护进程会根据消息级别来判断是将消息记录在日志文件,还是显示在用户终端上。本节将首先介绍syslogd的基本知识,然后介绍如何编程实现守护进程的日志。
8.3.1 syslogd守护进程
syslogd守护进程负责记录、发送系统或工具所产生的信息,其配置文件是/etc/syslog.conf。当系统内核或工具产生信息时,通过调用相关函数,将信息发送到syslogd守护进程。syslogd守护进程会根据/etc/syslog.conf中的配置信息,对消息的去向做出处理。例如,将消息记录在系统日志中、输出到控制台或转发给某个指定的用户,甚至可以让syslogd将信息通过网络转发给网络上其他主机的syslogd守护进程实现系统的集中管理。
8.3.2 syslogd守护进程配置文件说明
syslogd守护进程根据/etc/syslog.conf中的配置信息实现消息转发和处理。下面是该配置文件的具体信息:
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.* /dev/console
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none /var/log/messages
# The authpriv file has restricted access.
authpriv.* /var/log/secure
# Log all the mail messages in one place.
mail.* -/var/log/maillog
# Log cron stuff
cron.* /var/log/cron
# Everybody gets emergency messages
*.emerg *
# Save news errors of level crit and higher in a special file.
uucp,news.crit /var/log/spooler
# Save boot messages also to boot.log
local7.* /var/log/boot.log
在syslog.conf文件中以#开头的是注释行,配置行的语法格式为:[消息类型][TAB分隔符][处理方案]。
1.消息类型
消息类型包括facility和level两个部分,这两个部分以“.”隔开,如:
mail.* -/var/log/maillog
表示facility为mail,而level是所有级别。处理方案是将消息记录在/var/log/maillog日志文件中。表8.2所示为facility可以使用的字段。
表8.2 facility字段
|
facility取值 |
值 |
说 明 |
|
kern |
0 |
内核日志信息 |
|
user |
1 |
用户日志信息 |
|
|
2 |
邮件系统日志信息 |
|
daemon |
3 |
系统守护进程日志信息 |
|
auth |
4 |
安全管理日志信息 |
|
syslog |
5 |
syslogd守护进程的日志信息 |
|
lpr |
6 |
打印服务日志信息 |
|
news |
7 |
新闻组服务日志信息 |
|
uucp |
8 |
uucp系统日志信息 |
|
cron |
9 |
守护进程cron的日志信息 |
|
authpriv |
10 |
私有的安全管理日志信息 |
|
ftp |
11 |
ftp守护进程 |
续表
|
facility取值 |
值 |
说 明 |
|
12~15 |
系统保留 |
|
|
local0~local7 |
16~23 |
保留给系统本地使用 |
level给出的级别代表着信息的重要性,表8.3所示为level中的级别信息。
表8.3 level字段
|
level取值 |
值 |
说 明 |
|
emerg |
0 |
系统不可用,出现这一情况的话,应该通知所有用户,因为这表示系统出现了严重的问题 |
|
alert |
1 |
警告事件,必须立即采取行动纠正的事件 |
|
crit |
2 |
关键事件,例如硬件出现故障 |
|
err |
3 |
其他错误事件 |
|
warning |
4 |
警告事件 |
|
notice |
5 |
应该注意的事件,需要特别处理 |
|
info |
6 |
通报信息 |
|
debug |
7 |
调试程序时产生的信息 |
在syslog.conf中,可以使用*表示任何facility和任意的level。通过指定facility和level的取值,可以使facility在大于或等于该优先级的时候才记录相关日志信息。对于level,还可以使用none参数,表示不包含任何优先级别。例如,*.*表示任何facility的任何优先级的信息。*.emerg表示任何facility的大于或高于emerg优先级的信息。
2.处理方案
处理方案中指定的字段可以为如下的内容。
l 普通文件:使用文件的绝对路径来指明日志文件所在位置。
l 管道文件:在syslogd中支持使用管道文件(FIFO),在管道文件路径名前加“|”,表示将所得信息写入管道中。
l 终端设备:通过将信息写入/dev/console中,可以在终端显示相关信息。
l 其他主机:syslogd支持将信息发往网络中的其他主机的syslogd守护进程,以实现集中管理,格式为“@hostname”。
l 用户列表:syslogd守护进程支持将日志信息发给某些指定的用户。
l 所有登录用户:可以用*表示所有登录的用户。在获得日志信息时,syslogd守护进程会自动将信息发送给登录用户。
下面选取前面给出的syslog.conf中的一条配置来解释其意义。具体配置如下:
cron.* /var/log/cron
配置中的facility为cron,表示记录守护进程cron的信息。level为*,表示记录所有优先级别的信息,并将日志信息记录到/var/log/cron文件中。在Linux系统中,往往把各种日志文件保存在/var/log目录中。

图8.5 日志文件保证目录
8.3.3 守护进程日志的实现
syslogd守护进程用于解决守护进程的日志记录问题,而日志信息保存的位置和记录的信息级别是在syslogd守护进程的配置文件中设定的。守护进程日志主要涉及3个函数,分别是openlog、syslog和closelog函数。表8.4所示为这3个函数的具体信息。
表8.4 openlog、syslog和closelog函数
|
头文件 |
<syslog.h> |
||
|
函数形式 |
void openlog(const char *ident, int option, int facility); void syslog(int priority, const char *format, ...); void closelog(void); |
||
|
返回值 |
成功 |
失败 |
是否设置errno |
|
− |
− |
− |
|
说明:
openlog函数用于打开系统日志连接。只有在打开连接后,才能使用syslog函数向日志文件中添加日志信息。closelog函数用于关闭打开的系统日志连接,该函数的调用在实现中是可选择的。
openlog函数中的第1个参数为ident,该参数常用来表示信息的来源。ident指向的字符信息会被固定地添加在每行日志的前面。第2个参数option用于指定openlog函数和接下来调用的syslog函数的控制标志。option的取值情况如表8.5所示,可以单独取其中的某个值,也可以通过与运算来获得多种特性。第3个参数为facility,这个要与syslogd守护进程的配置文件对应,日志信息会写入syslog.conf文件指定的位置。
表8.5 openlong函数中的option取值表
|
参 数 |
说 明 |
|
LOG_CONS |
如果将信息发送给syslogd守护进程时发生错误,直接将相关信息输出到终端 |
|
LOG_NDELAY |
立即打开与系统日志的连接(通常情况下,只有在产生第一条日志信息的情况下才会打开与日志系统的连接) |
|
LOG_NOWAIT |
在记录日志信息时,不等待可能的子进程的创建 |
|
LOG_ODELAY |
类似于LOG_NDELAY参数,与系统日志的连接只有在syslog函数调用时才会创建 |
续表
|
参 数 |
说 明 |
|
LOG_PERROR |
在将信息写入日志的同时,将信息发送到标准错误输出(POSIX.1-2001不支持该参数) |
|
LOG_PID |
每条日志信息中都包括进程号 |
参数facility的取值如表8.6所示。这些值与前面syslog.conf中的facility是存在对应关系的。
表8.6 openlog函数参数facility取值
|
facility参数 |
syslog.conf中对应的facility取值 |
|
LOG_KERN |
kern |
|
LOG_USER |
user |
|
LOG_MAIL |
|
|
LOG_DAEMON |
daemon |
|
LOG_AUTH |
auth |
|
LOG_SYSLOG |
syslog |
|
LOG_LPR |
lpr |
|
LOG_NEWS |
news |
|
LOG_UUCP |
uucp |
|
LOG_CRON |
cron |
|
LOG_AUTHPRIV |
authpriv |
|
LOG_FTP |
ftp |
|
LOG_LOCAL0~LOG_LOCAL7 |
local0~local7 |
syslog函数中的第一个参数priority表示消息的级别。与openlog函数中的facility参数类似,priority参数与level也存在对应的关系。priority取值和对应关系如表8.7所示。
表8.7 syslog函数参数priority取值
|
priority参数 |
syslog.conf中对应的level取值 |
|
LOG_EMERG |
emerg |
|
LOG_ALERT |
alert |
|
LOG_CRIT |
crit |
|
LOG_ERR |
err |
|
LOG_WARNING |
warning |
|
LOG_NOTICE |
notice |
|
LOG_INFO |
info |
|
LOG_DEBUG |
debug |
syslog函数的第二个参数为消息的格式,之后是格式对应的参数。函数的使用类似于printf函数。
实例演练:
在程序中添加日志功能需要遵循如图8.6所示的步骤。调用syslog函数的过程就是写入日志的过程(如果没有调用openlog函数,直接调用syslog函数的话,facility参数可以作为priority参数的一部分加以说明)。
程序p8.2.c给出了在程序中实现日志的简单实例。首先,程序调用openlog函数打开与系统日志间的连接;然后,通过调用syslog函数产生5条日志信息;最后,关闭与系统日志间的连接。
#include <stdio.h>
#include <syslog.h>
int main(int argc,char* argv[])
{
openlog(argv[0],LOG_CONS | LOG_PID, LOG_USER);
int count=0;
while(count<5){
syslog(LOG_INFO,"%d, log info test...",count);
count++;
}
closelog();
return 0;
}
使用gcc编译p8.2.c,执行编译出的可执行文件。
[program@localhost charter8]$ gcc p8.2.c
[program@localhost charter8]$ ./a.out
如何查看执行结果呢?
前面介绍了syslogd守护进程会根据syslog.conf文件中的配置,将信息写入指定的日志文件中。调用syslog函数时,指定的priority为LOG_INFO,对应于syslog.conf中的info优先级。而调用openlog函数的facility为LOG_USER,对应于syslog.conf中facility取user的情况。查找syslog.conf中的facility.level为user.info的规则,如图8.7所示。可知,日志文件为/var/log/message。
由于查看/var/log下的日志需要root权限,使用su切换到root用户。使用tail命令查看message文件中的日志信息,发现相关信息已经通过syslogd守护进程记录在了/var/log/message日志文件中,如图8.8所示。
通过程序p8.2.c可以清楚地了解如何在程序中实现日志功能。在守护进程中添加日志功能的流程与p8.2.c几乎是相同的,这里就不再给出实例。

图8.7 syslog.conf中对应的规则 图8.8 程序执行结果






