• C语言日志处理


    一、简介

    zlog是一个高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库,在效率、功能、安全性上大大超过了log4c,并且是用c写成的,具有比较好的通用性。

    二、安装

    下载

    三、实例

    参考:

    源码目录:test,包括了大量使用示例,如下:

    image

    四、系统日志

    参考:

     

    示例:

    #include <syslog.h>
    int main(int argc, char **argv)
    {
        openlog("MyMsgMARK", LOG_CONS | LOG_PID, 0);
        syslog(LOG_INFO,
               "This is a syslog test message generated by program '%s'
    ",
               argv[0]);
        closelog();
        return 0;
    }

    编译

    gcc -g -o test test.c

    运行

    1

     

    五、Apache 日志处理分析

    Apache通过调用ap_log_XXX函数进行日志记录,此处以ap_log_perror为例进行分析

    Apache启动时通过httpd/modules/core/mod_so.c:load_module函数进行DSO模块加载,加载成功后将调用ap_log_perror函数记录模块加载日志

    266     ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, cmd->pool, APLOGNO(01575)"loaded module %s from %s", modname, module_file);

    ap_log_perror函数事实上是一个宏,定义在文件:/httpd/include/http_log.h,如下:

    412 #define ap_log_perror ap_log_perror_
    而ap_log_perror_函数实现在文件:httpd/server/log.c,代码如下:
    1409 AP_DECLARE(void) ap_log_perror_(const char *file, int line, int module_index,
    1410                                 int level, apr_status_t status, apr_pool_t *p,
    1411                                 const char *fmt, ...)
    1412 {
    1413     va_list args;
    1414 
    1415     va_start(args, fmt);
    1416     log_error_core(file, line, module_index, level, status, NULL, NULL, NULL,
    1417                    p, fmt, args);
    1418     va_end(args);
    1419 }

    函数log_error_core,逻辑如下:

    1、判断请求结构r是否为NULL,若不为空则:c = r->connection

    2、判断服务器结构s是否为NULL,若为空则:logf = stderr_log,此处s为NULL

    3、填充结构日志info

    4、调用do_errorlog_default函数拼接要写入日志的内容并暂存在buf中,并返回相应长度len

    5、调用write_logline函数进行实际的日志输出

    6、运行日志钩子error_log

    static void log_error_core(const char *file, int line, int module_index,
                               int level,
                               apr_status_t status, const server_rec *s,
                               const conn_rec *c,
                               const request_rec *r, apr_pool_t *pool,
                               const char *fmt, va_list args)
    {
        char errstr[MAX_STRING_LEN];
        apr_file_t *logf = NULL;
        int level_and_mask = level & APLOG_LEVELMASK;
        const request_rec *rmain = NULL;
        core_server_config *sconf = NULL;
        ap_errorlog_info info;
    
        /* do we need to log once-per-req or once-per-conn info? */
        int log_conn_info = 0, log_req_info = 0;
        apr_array_header_t **lines = NULL;
        int done = 0;
        int line_number = 0;
    
        if (r)
        {
            AP_DEBUG_ASSERT(r->connection != NULL);
            c = r->connection;
        }
    
        if (s == NULL)
        {
            /*
             * If we are doing stderr logging (startup), don't log messages that are
             * above the default server log level unless it is a startup/shutdown
             * notice
             */
    #ifndef DEBUG
            if ((level_and_mask != APLOG_NOTICE)
                    && (level_and_mask > ap_default_loglevel))
            {
                return;
            }
    #endif
    
            logf = stderr_log;
        }
        else
        {
            int configured_level = r ? ap_get_request_module_loglevel(r, module_index)        :
                                   c ? ap_get_conn_server_module_loglevel(c, s, module_index) :
                                   ap_get_server_module_loglevel(s, module_index);
            if (s->error_log)
            {
                /*
                 * If we are doing normal logging, don't log messages that are
                 * above the module's log level unless it is a startup/shutdown notice
                 */
                if ((level_and_mask != APLOG_NOTICE)
                        && (level_and_mask > configured_level))
                {
                }
                else
                {
                    /*
                     * If we are doing syslog logging, don't log messages that are
                     * above the module's log level (including a startup/shutdown notice)
                     */
                    if (level_and_mask > configured_level)
                    {
    
                    }
                }
    
                /* the faked server_rec from mod_cgid does not have s->module_config */
    
                sconf = ap_get_core_module_config(s->module_config);
                if (c && !c->log_id)
                {
                    add_log_id(c, NULL);
                    if (sconf->error_log_conn && sconf->error_log_conn->nelts > 0)
                        log_conn_info = 1;
                }
                if (r)
                {
                    if (r->main)
                        rmain = r->main;
                    else
                        rmain = r;
    
                    if (!rmain->log_id)
                    {
                        /* XXX: do we need separate log ids for subrequests? */
                        if (sconf->error_log_req && sconf->error_log_req->nelts > 0)
                            log_req_info = 1;
                        /*
                         * XXX: potential optimization: only create log id if %L is
                         * XXX: actually used
                         */
                        add_log_id(c, rmain);
                    }
                }
            }
        }
    
        info.s             = s;
        info.c             = c;
        info.pool          = pool;
        info.file          = NULL;
        info.line          = 0;
        info.status        = 0;
        info.using_syslog  = (logf == NULL);
        info.startup       = ((level & APLOG_STARTUP) == APLOG_STARTUP);
        info.format        = fmt;
    
        while (!done)
        {
            apr_array_header_t *log_format;
            int len = 0, errstr_start = 0, errstr_end = 0;
            /* XXX: potential optimization: format common prefixes only once */
            if (log_conn_info)
            {
                /* once-per-connection info */
                if (line_number == 0)
                {
                    lines = (apr_array_header_t **)sconf->error_log_conn->elts;
                    info.r = NULL;
                    info.rmain = NULL;
                    info.level = -1;
                    info.module_index = APLOG_NO_MODULE;
                }
    
                log_format = lines[line_number++];
    
                if (line_number == sconf->error_log_conn->nelts)
                {
                    /* this is the last line of once-per-connection info */
                    line_number = 0;
                    log_conn_info = 0;
                }
            }
            else if (log_req_info)
            {
                /* once-per-request info */
                if (line_number == 0)
                {
                    lines = (apr_array_header_t **)sconf->error_log_req->elts;
                    info.r = rmain;
                    info.rmain = rmain;
                    info.level = -1;
                    info.module_index = APLOG_NO_MODULE;
                }
    
                log_format = lines[line_number++];
    
                if (line_number == sconf->error_log_req->nelts)
                {
                    /* this is the last line of once-per-request info */
                    line_number = 0;
                    log_req_info = 0;
                }
            }
            else
            {
                /* the actual error message */
                info.r            = r;
                info.rmain        = rmain;
                info.level        = level_and_mask;
                info.module_index = module_index;
                info.file         = file;
                info.line         = line;
                info.status       = status;
                log_format = sconf ? sconf->error_log_format : NULL;
                done = 1;
            }
    
            /*
             * prepare and log one line
             */
    
            if (log_format && !info.startup)
            {
                len += do_errorlog_format(log_format, &info, errstr + len,
                                          MAX_STRING_LEN - len,
                                          &errstr_start, &errstr_end, fmt, args);
            }
            else
            {
                len += do_errorlog_default(&info, errstr + len, MAX_STRING_LEN - len,
                                           &errstr_start, &errstr_end, fmt, args);
            }
    
            if (!*errstr)
            {
                /*
                 * Don't log empty lines. This can happen with once-per-conn/req
                 * info if an item with AP_ERRORLOG_FLAG_REQUIRED is NULL.
                 */
                continue;
            }
            write_logline(errstr, len, logf, level_and_mask);
    
            if (done)
            {
                /*
                 * We don't call the error_log hook for per-request/per-conn
                 * lines, and we only pass the actual log message, not the
                 * prefix and suffix.
                 */
                errstr[errstr_end] = '';
                ap_run_error_log(&info, errstr + errstr_start);
            }
    
            *errstr = '';
        }
    }

    do_errorlog_default函数拼接要写入日志的内容并暂存在buf中,并返回相应长度len,此处拼接出的日志的内容如下:

    [Sat Jun 20 22:08:19.506426 2015] [so:debug] [pid 3826] mod_so.c(266): AH01575: loaded module unixd_module from /app/HRP/lib/mod_unixd.so

    do_errorlog_default函数实现在文件:httpd/server/log.c,代码如下:

    static int do_errorlog_default(const ap_errorlog_info *info, char *buf,
                                   int buflen, int *errstr_start, int *errstr_end,
                                   const char *errstr_fmt, va_list args)
    {
        int len = 0;
        int field_start = 0;
        int item_len;
    #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
        char scratch[MAX_STRING_LEN];
    #endif
    
        if (!info->using_syslog && !info->startup)
        {
            buf[len++] = '[';
            len += log_ctime(info, "u", buf + len, buflen - len);
            buf[len++] = ']';
            buf[len++] = ' ';
        }
    
        if (!info->startup)
        {
            buf[len++] = '[';
            len += log_module_name(info, NULL, buf + len, buflen - len);
            buf[len++] = ':';
            len += log_loglevel(info, NULL, buf + len, buflen - len);
            len += cpystrn(buf + len, "] [pid ", buflen - len);
    
            len += log_pid(info, NULL, buf + len, buflen - len);
    #if APR_HAS_THREADS
            field_start = len;
            len += cpystrn(buf + len, ":tid ", buflen - len);
            item_len = log_tid(info, NULL, buf + len, buflen - len);
            if (!item_len)
                len = field_start;
            else
                len += item_len;
    #endif
            buf[len++] = ']';
            buf[len++] = ' ';
        }
    
        if (info->level >= APLOG_DEBUG)
        {
            item_len = log_file_line(info, NULL, buf + len, buflen - len);
            if (item_len)
            {
                len += item_len;
                len += cpystrn(buf + len, ": ", buflen - len);
            }
        }
    
        if (info->status)
        {
            item_len = log_apr_status(info, NULL, buf + len, buflen - len);
            if (item_len)
            {
                len += item_len;
                len += cpystrn(buf + len, ": ", buflen - len);
            }
        }
    
        /*
         * useragent_ip/client_ip can be client or backend server. If we have
         * a scoreboard handle, it is likely a client.
         */
        if (info->r)
        {
            len += apr_snprintf(buf + len, buflen - len,
                                info->r->connection->sbh ? "[client %s:%d] " : "[remote %s:%d] ",
                                info->r->useragent_ip,
                                info->r->useragent_addr ? info->r->useragent_addr->port : 0);
        }
        else if (info->c)
        {
            len += apr_snprintf(buf + len, buflen - len,
                                info->c->sbh ? "[client %s:%d] " : "[remote %s:%d] ",
                                info->c->client_ip,
                                info->c->client_addr ? info->c->client_addr->port : 0);
        }
    
        /* the actual error message */
        *errstr_start = len;
    #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
        if (apr_vsnprintf(scratch, MAX_STRING_LEN, errstr_fmt, args))
        {
            len += ap_escape_errorlog_item(buf + len, scratch,
                                           buflen - len);
    
        }
    #else
        len += apr_vsnprintf(buf + len, buflen - len, errstr_fmt, args);
    #endif
        *errstr_end = len;
    
        field_start = len;
        len += cpystrn(buf + len, ", referer: ", buflen - len);
        item_len = log_header(info, "Referer", buf + len, buflen - len);
        if (item_len)
            len += item_len;
        else
            len = field_start;
    
        return len;
    }

    write_logline函数实现在文件:httpd/server/log.c,代码如下:

    static void write_logline(char *errstr, apr_size_t len, apr_file_t *logf,
                              int level)
    {
        /* NULL if we are logging to syslog */
        if (logf)
        {
            /* Truncate for the terminator (as apr_snprintf does) */
            if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR))
            {
                len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
            }
            strcpy(errstr + len, APR_EOL_STR);
            apr_file_puts(errstr, logf);
            apr_file_flush(logf);
        }
    #ifdef HAVE_SYSLOG
        else
        {
            syslog(level < LOG_PRIMASK ? level : APLOG_DEBUG, "%.*s",
                   (int)len, errstr);
        }
    #endif
    }
  • 相关阅读:
    MVC 4 中 WEB API 选择 返回格式
    用XML配置菜单的一种思路,附一些不太准确的测试代码
    2020.11.15(每周总结)
    2020.11.19
    2020.11.22
    2020.11.21
    2020.11.14
    202.11.13
    2020.11.20
    2020.11.17
  • 原文地址:https://www.cnblogs.com/274914765qq/p/4589929.html
Copyright © 2020-2023  润新知