内容概要

四、守护进程的出错处理

  • 4.1、openlog()函数
  • 4.2、syslog()函数
  • 4.3、closelog()函数
  • 4.4、代码示例

  书接上文守护进程的基础知识,这一篇继续来说明守护进程相关的出错处理。

四、守护进程的出错处理

因为守护进程完全脱离终端控制,所以不能像其它进程一样将错误信息输出到控制终端。所以如何处理错误消息是一个问题。在Linux系统中,一般通用的办法是使用syslog服务,将程序中出错信息输入到系统日志文件中(如"/var/log/messages",此文件需要用用root权限的用户查看),从而可以直观地看到程序的问题所在。在不同的Linux发行版中,系统日志的文件路径全名可能有所不同(比如可能是"/var/log/syslog")。

syslog 是Linux系统日志管理服务,通过守护进程 syslogd 来维护。改守护进程在启动时会读取一个配置文件“/etc/syslog.conf”。该文件决定了不同种类的信息会发送到何处。

自4.2BSD依赖,BSD的syslog设施得到了广发的应用,大多数守护进程都使用这一设施。syslog的详细组织结构如图4.1所示。

java守护现成不工作了 守护进程失败怎么办_linux

图4.1 syslog的详细组织结构图

3 个 syslog 相关的函数,分别是 openlog()、syslog()、closelog()。通常,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);

4.1、openlog()函数

功能:  用于打开与程序的系统记录器的连接参数:  ident  :要向每个消息加入的字符串,通常为程序的名称  option:用于指定各个选项的为屏蔽。可选的参数为:    LOG_CONS    :如果消息无法发送到系统日志服务,则直接输出到系统控制终端上    LOG_NDELAY:立即打开系统日志服务的连接    LOG_NOWAIT:不要等待可能已经创建的子进程,此选项对Linux无效果    LOG_ODELAY:与LOG_NDELAY相反,连接的打开被延迟,直到调用 syslog()    LOG_PERROR:将消息同时发送到标准出错(stderr)上    LOG_PID      :在每条消息中都包含进程的PID  facility:指定程序发送的消息类型,可选的参数为:    LOG_AUTH     :安全/授权信息    LOG_AUTHPRIV  : 安全/授权信息(私有)    LOG_CRON     :时间守护进程(cron 和 at)    LOG_DAEMON   :其他系统的守护进程    LOG_FTP      :ftp的守护进程    LOG_KERN     :内核消息(不能从用户进程生成)    LOG_LOCAL[0~7]:保留给本地使用    LOG_LPR       :行打印机子系统    LOG_MAIL      :邮件子系统    LOG_NEWS      :新闻子系统    LOG_SYSLOG    :syslogd()内部产生的消息    LOG_USER(默认): 一般使用者等级消息    LOG_UUCP      :UUCP子系统返回:  函数无返回

  调用 openlog() 是可选择的。假设不调用 openlog(),则在第一次调用 syslog() 时,自己主动调用 openlog()。

4.2、syslog()函数

功能:  用于把日志消息发给系统程序syslogd记录 参数:  priority:指定消息的重要性,可有以下选项:     LOG_EMERG  :系统无法使用    LOG_ALERT  :需要立即采取措施    LOG_CRIT   :有重要情况发生    LOG_ERR    :有错误发生    LOG_WARNING:有警告发生    LOG_NOTICE :正常情况,但也有重要情况    LOG_INFO   :信息消息    LOG_DEBUG  :调试信息  format  :以字符串指针的形式表示输出的格式,类似于printf中的格式返回:  函数无返回

4.3、closelog()函数

  closelog() 函数关闭用来编写系统 closelog logger 的描述符。closelog() 函数的使用是可选的,因为在程序结束后,会自动关闭与 system log

4.4、代码示例

“/daemon.log”文件中写入内容。实现的代码如下所示。

#include <fcntl.h>     // for O_APPEND ..
#include <stdio.h>     // for perror ..
#include <stdlib.h>    // for exit ..
#include <string.h>    // for strlen
#include <sys/stat.h>  // for umask
#include <sys/types.h> // for setsid
#include <syslog.h>    // for openlog ..
#include <unistd.h>    // for setsid

int main(int argc, const char *argv[])
{
    pid_t pid = 0, sid = 0;

    /* 创建子进程,父进程退出 */
    pid = fork();
    if (pid == -1) /* fork出错 */
    {
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    else if (pid == 0) /* 子进程 */
    {
        /* 打开系统日志服务器 */
        openlog("daemon.syslog", LOG_PID, LOG_DAEMON);

        /* 创建新的会话 */
        if ((sid = setsid()) < 0)
        {
            /* 向系统日志服务器写入错误信息 */
            syslog(LOG_ERR, "%s\n", "setsid() error");
            exit(EXIT_FAILURE);
        }

        /* 改变当前的工作路径 */
        if ((sid = chdir("/")) < 0)
        {
            syslog(LOG_ERR, "%s\n", "chdir() error");
            exit(EXIT_FAILURE);
        }

        /* 改变进程本身的umask */
        umask(0);
        /* 关闭所有可能已打开的文件描述符 */
        int num = getdtablesize(); /* 获取当前进程文件描述符表大小 */
        for (i = 0; i < num; i++)
        {
            close(i);
        }

        /* 周期计数的变量 */
        int cycleCnt = 0;

        /* 至此,守护进程创建完成,以下正式开始守护进程的工作 */
        while (1)
        {
            /* 周期运行计数自加 */
            cycleCnt++;
            /* 写入到系统日志中 */
            syslog(LOG_NOTICE, "I'm Daemon Process, Running %d", cycleCnt);
            /* 休眠片刻 */
            sleep(2);
        }
    }
    else /* 父进程 */
    {
        /* 父进程退出 */
        exit(EXIT_SUCCESS);
    }
    /* 关闭系统日志服务器 */
    closelog();
    return 0;
}

编译并运行上述程序,输入指令 ps -ajx | grep "./syslog" 查看对应的进程状态,使用指令 cat /var/log/syslog 查看系统日志,总体显示效果图4.2所示。

java守护现成不工作了 守护进程失败怎么办_守护进程_02

图4.2 syslog的测试显示效果图