Chinaunix首页 | 论坛 | 博客
  • 博客访问: 33829
  • 博文数量: 4
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 55
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-17 22:12
文章分类
文章存档

2007年(4)

我的朋友
最近访客

分类: C/C++

2007-03-17 22:12:15

在使用syslog记录日志时,方便是方便了,但是不够灵活,因为不能自定义syslog的输出文件,只能按照syslog定义的不同级别来写入固定的日志文件,比如/var/log/message等等,很多软件为了能把日志写入自定义的文件,都有完善的日志实现方法,相当于重写syslog,很是不爽,比如rsync的日志系统是这么实现的:
 

void log_open(void)
{
        static int initialised;
        int options = LOG_PID;
        time_t t;
        char *logf;

        if (initialised) return;
        initialised = 1;

        /* this looks pointless, but it is needed in order for the
           C library on some systems to fetch the timezone info
           before the chroot */

        t = time(NULL);
        localtime(&t);

        /* optionally use a log file instead of syslog */
        logf = lp_log_file();
        if (logf && *logf) {
                extern int orig_umask;
                int old_umask = umask(022 | orig_umask);
                logfile = fopen(logf, "a");
                umask(old_umask);
                return;
        }

#ifdef LOG_NDELAY
        options |= LOG_NDELAY;
#endif

#ifdef LOG_DAEMON
        openlog("rsyncd", options, lp_syslog_facility());
#else
        openlog("rsyncd", options);
#endif

#ifndef LOG_NDELAY
        logit(LOG_INFO,"rsyncd started\n");
#endif
}

/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */
void rprintf(enum logcode code, const char *format, ...)
{
        va_list ap;
        char buf[1024];
        int len;

        va_start(ap, format);
        len = vslprintf(buf, sizeof(buf), format, ap);
        va_end(ap);

        if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);

        rwrite(code, buf, len);
}

/* this is the underlying (unformatted) rsync debugging function. Call
   it with FINFO, FERROR or FLOG */

void rwrite(enum logcode code, char *buf, int len)
{
        FILE *f=NULL;
        extern int am_daemon;
        extern int am_server;
        extern int quiet;
        /* recursion can happen with certain fatal conditions */

        if (quiet && code == FINFO) return;

        if (len < 0) exit_cleanup(RERR_MESSAGEIO);

        buf[len] = 0;

        if (code == FLOG) {
                if (am_daemon) logit(LOG_INFO, buf);
                return;
        }

        /* first try to pass it off the our sibling */
        if (am_server && io_error_write(log_error_fd, code, buf, len)) {
                return;
        }

        /* then try to pass it to the other end */
        if (am_server && io_multiplex_write(code, buf, len)) {
                return;
        }

        if (am_daemon) {
                static int depth;
                int priority = LOG_INFO;
                if (code == FERROR) priority = LOG_WARNING;

                if (depth) return;

                depth++;

                log_open();
                logit(priority, buf);

                depth--;
                return;
        }

        if (code == FERROR) {
                f = stderr;
        }

        if (code == FINFO) {
                if (am_server)
                        f = stderr;
                else
                        f = stdout;
        }

        if (!f) exit_cleanup(RERR_MESSAGEIO);

        if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);

        if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
}

static void logit(int priority, char *buf)
{
        if (logfile) {
                fprintf(logfile,"%s [%d] %s",
                        timestring(time(NULL)), (int)getpid(), buf);
                fflush(logfile);
        } else {
                syslog(priority, "%s", buf);
        }
}

通过是否有一个全局的日志文件名来判断是用syslog写入标准的message或是写入自己的日志,大家能看到,为了实现重定向的功能,又要与syslog语法兼容,要重写好几个函数,包括一个变参的printf( 我最怕的玩意 ),有什么方法能利用现有的syslog机制就能实现自定义输出文件的syslog呢?

我的解决方法很简单:

#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <syslog.h>

int main( int argc, char* argv[] )
{
        int logfd = open( "/root/log.self", O_RDWR | O_CREAT | O_APPEND, 0644 );
        assert( -1 != logfd );

        close( STDERR_FILENO );
        dup2( logfd, STDERR_FILENO );
        close( logfd );
        openlog( NULL, LOG_PERROR, LOG_DAEMON );
        syslog( LOG_DEBUG, "%i\n", time( NULL ) );
        return 0;
}

这样,就可以把syslog打印的信息写入自己的日志文件,并且还有一个意外的特性,就是不依赖syslogd,即不论syslogd是否启动,都可以写入日志.

注: LOG_PERROR 非POSIX标准.

阅读(7109) | 评论(16) | 转发(0) |
0

上一篇:没有了

下一篇:人民公敌出版社

给主人留下些什么吧!~~