一、守护进程如何进行出错处理
- 与守护进程有关的一个问题是如何处理出错消息。因为它没有控制终端,所以不能只是写到标准出错输出上
- 在很多工作站上,控制台设备运行一个窗口系统,我们不希望守护进程将它自己的出错写到控制台设备上。我们也不希望每个守护进程将它自己的出错消息写到一个单独的文件中。对系统管理人员而言,如果要关心哪一个守护进程写到哪一个记录文件中,并定期地 检查这些文件,那么一定会使他感到头痛。所以,需要有一个集中的守护进程出错记录设施
二、syslogd守护进程
syslogd守护进程可以用来处理守护进程的消息,syslogd守护进程在启动时执行以下步骤:
- ①读取配置文件。通常为/etc/syslog.conf的配置文件指定本守护进程可能收取的各种日志消息应该如何处理。这些消息可能被添加到一个文件(/dev/console文件是一个特例,它把消息写到控制台上),或被写到指定用户的登录窗口(若该用户已登录到本守护进程所在系统中),或被转发给另一个主机上的syslogd进程
- ②创建一个Unix域数据报套接字,给它绑定路径名/var/run/log(在某些系统上是/dev/log)
- ③创建一个UDP套接字,给它绑定端口514(syslog服务使用的端口号)
- ④打开路径名/dev/klog。来自内核中的任何出错消息看着像是这个设备的输入
3种日志消息处理方式
由上面syslogd守护进程的运行方式我们可以知道,系统的syslogd守护进程有3种对守护进程日志消息的处理方式
- syslogd启动之后,syslogd守护进程处于无限循环中运行;调用select以等待它的3个描述符之一变为可读,读入日志消息,并按照配置文件进行处理。如果守护进程收到SIGHUP信号,那就重新读取配置文件
上图中3种产生日志消息的办法
- 内核例程可以调用log函数。任何一个用户进程通过打开和读/dev/klog设备就可以读取这些消息。因为我们无意编写内核中的例程,所以不再进一步说明此函数
- 大多数用户进程(守护进程)调用syslog函数来产生日志消息,消息被发送至UNIX域数据报套接字/dev/log(下面我们介绍其地调用序列)
- 无论一个用户进程是在此主机上,还是在通过通过TCP/IP网络连接到此主机的其他主机上,都可将日志消息发向UDP端口514。注意:syslog函数从不产生这些UDP数据报,它们要求产生此日志消息的进程进行显式的网络编程
syslog函数消息重复到达处理:
- 大多数syslog实现将使消息短时间处于队列中。如果在此段时间中有重复消息到达,那么syslog守护进程不会把它写到日志记录中,而是会打印输出一条类似于“上一条消息重复了N次”的消息
三、openlog()、closelog()
openlog函数
#include <syslog.h> void openlog(const char *ident, int option, int facility);
调用openlog函数用来开启程序的日志处理。调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时,自动调用openlog
- ident参数:是一个由syslog冠于每个日志消息之前的字符串。ident一般是程序的名称(例如,cron、inetd等)
- option参数:此参数指定各种选项的位屏蔽,由下面一个或多个常值的逻辑或构成(如果在Single UNIX Specification支持下面的选项,则XSI处用一个黑点表示)
openlog被调用时,通常并不立即创建Unix域套接字。相反,该套接字直到首次调用syslog时才打开。LOG_NDELAY选项迫使该套接字在openlog被调用时就创建
- facility参数:设置facility参数的目的是可以让配置文件说明,来自不同设施的消息将以不同的方式进行处理。(Single UNIX Specification不支持的facility,XSI处为空)
如果不调用openlog,或者以facility为0来调用openlog,那么后面在调用syslog时,可将facility作为syslog函数priority参数进行调用
有些守护进程通常调用openlog指定一个设施(对于一个给定守护进程,设施通常不变),然后在每次调用syslog时只指定level(级别),因此级别可随错误性质改变
closelog函数
#include <syslog.h> void closelog(void);
- 调用closelog也是可选择的,如果应用程序不再需要发送日志消息时可以调用该函数
四、syslog()
#include <syslog.h>
void syslog(int priority, const char *message, ...);
- 调用此函数来产生一个日志消息
- 当syslog被应用程序首次调用时,它创建一个Unix域数据报套接字,然后调用connect连接到由syslogd守护进程创建的Unix域数据报套接字的众所周知路径名(譬如/var/run/log)。这个套接字一直保持打开,直到进程终止为止。作为替换,进程也可以调用openlog和closelog
参数:
- priority参数:是level(级别)与openlog函数的facility(设施)两者的组合。(下面的level值按优先级从高到低排序)
如果未指定level值,默认为LOG_NOTICE
如果未指定facility值,默认为LOG_USER
level与facility的目的在于,允许在/etc/syslog.conf文件中同一配置来自同一给定设施的所有消息,或者同一配置具有相同级别的所有消息。举例来说,该配置文件可能含有以下两行:
kern.* /dev/console local7.debug /var/log/cisco.log /* 这两行指定: 所有内核消息登记到控制台 来自local7设施的所有debug消息添加到文件/var/log/cisco.log的末尾 */
- format参数:此参数以及其他参数传至vsprintf函数以便进行格式化。在message中,每个%m都被代换成对应于errno值的出错消息字符串(strerror)
五、setlogmask()、vsyslog()
#include <syslog.h>
int setlogmask(int mask);
//返回值:前日志记录优先级屏蔽字值
#include <syslog.h>
#include <stdarg.h>
void vsyslog(int priority, const char *format, va_list ap);
setlogmask函数
vsyslog函数
- 此函数可以处理可变参数列表
六、演示案例
七、logger命令
- 日志消息也可以由logger命令产生。举例来说,logger命令可用在shell脚本中以向syslogd发送消息