log4c demo学习

今天给大家分享log4c的一个demo,不管三七二十一,直接用,能用了~在看原理!

github地址:

https://github.com/gt19930910/mytest-projects/tree/gt-dev/log4c-test

当然,mytest-projects里面还有一些别的程序,大家看上的可以随便临幸O(∩_∩)O哈哈~

用法:

下面简单说说log4c里面一些基本的东西:

安装

    很简单,在linux下直接dnf install log4c-devel,我使用的系统是fedora 30,当然要是ubuntu用apt安装就ok,至于windows,大家有兴趣的可以找我吧,需要用到windows的库,我现在是自己用msys2+mingw32来实现的,原理是一样的就是环境麻烦点。

配置文件

1、version

    学到这里我相信大家应该都知道log4c有一个配置文件叫做log4crc,下面我给大家贴出来这个配置文件简单说一下都是什么东西。这里面有一个版本非常重要version="1.2.4",这个版本一定要与本地log4c的版本一样,否则是不会出日志的。

2、root category

    接下来看root category这一栏 ,name="mycat"(或者root或者file),简单地说就是这回使用的日志的名字,代表这个配置文件,在程序里面读取这个配置文件的时候,就会读取这个name,然后引用这个name。

3、priority

    之后就是priority="debug"(或者error),这个是日志等级,具体分为fatal error warn notice info debug trace这么一些等级,具体不明白的同学可以自己去了解了解。咱们只分析咱们用。简单解释就是:这里写了error,就只输出fatal和error的日志了,如果写了debug,就会将debug之前的(fatal error warn notice info debug)都给输出出来,这就是日志等级的作用(当然,你程序里面得写了这些等级的日志,才会打印相应的日志)。

4、appender

    这是日志输出流向,比如stdout,就直接输出到桌面,如果是下文中的test.log,那么久该看下面一栏了,我们可以看到appender name = "test.log",这里可以具体给出日志输出的方式。

a、 type="rollingfile"  日志存储方式(详细可以查资料),rollingpolicy是下面有专栏给出的具体配置

b、logdir日志文件路径

c、prefix是日志文件的名字

d、layout是日志具体输出格式,这个看下面的专栏<layout name="test-log4c" type="dated_format"/> dated_format这个是代码里面的函数,可以具体设置输出方式,输出函数文件名什么的。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE log4c SYSTEM "">
<log4c version="1.2.4">
 
<config>
<bufsize>0</bufsize>
<debug level="2"/>
<nocleanup>0</nocleanup>
<reread>1</reread>
</config>
 
<!-- root category -->
<category name="root" priority="notice"/>
<category name="mycat" priority="error" appender="stdout"/>
<category name="file" priority="debug" appender="test.log"/>
 
<!-- default appenders -->
<appender name="stdout" type="stream" layout="basic"/>
<appender name="test.log" type="rollingfile" logdir="/var/log" prefix="loginfo" layout="test-log4c" rollingpolicy="RollingPolicy"/>
<appender name="stderr" type="stream" layout="dated"/>
<appender name="syslog" type="syslog" layout="basic"/>
 
<!-- default layouts -->
<layout name="basic" type="basic"/>
<layout name="dated" type="dated"/>
<layout name="test-log4c" type="dated_format"/>
 
<!--sizewin表示达到最大值后新建日志文件  值由maxsize设定,单位Bytes     maxnum为最大文件数目 maxsize=50mb -->
<rollingpolicy name="RollingPolicy" type="sizewin" maxsize="52428800" maxnum="10" />
</log4c>

代码解析

log.c

首先找到log4crc这个配置文件,可以通过添加环境变量来自己找,也可以自己load具体的文件名,我们这里是给出的环境变量。之后就是初始化log4c给出的接口。下面就是导入日志具体配置了:

log_category = log4c_category_get("mycat");这里就是直接导入的mycat配置,直接输出到stdout,如果选择了"file"这个配置,就会输出到logdir=/var/log这个目录

dated_format具体格式,会在代码中给出,不管输出行号还是文件名什么的,都可以由自己选择,下面给出了一种方式,仅供参考。

#include <libgen.h>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include "log.h"

static log4c_category_t *log_category = NULL;

/*******************************************************************************/
static const char* dated_format(
        const log4c_layout_t *a_layout,
        const log4c_logging_event_t *a_event)
{
    static char buffer[1024];

#ifndef _WIN32
//#ifndef __HP_cc
//#warning gmtime() routine should be defined in sd_xplatform
//#endif
    struct tm tm;
    gmtime_r(&a_event->evt_timestamp.tv_sec, &tm);
    snprintf(buffer, sizeof(buffer), "%04d%02d%02d %02d:%02d:%02d.%06ld %-5s %s\n",
             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
             (tm.tm_hour + 8) % 24, tm.tm_min, tm.tm_sec,
             a_event->evt_timestamp.tv_usec,
             log4c_priority_to_string(a_event->evt_priority),
             a_event->evt_msg);
#else
    SYSTEMTIME stime;

    if (FileTimeToSystemTime(&a_event->evt_timestamp, &stime)) {
        snprintf(buffer, sizeof(buffer), "%04d%02d%02d %02d:%02d:%02d.%03ld %-6s %s\n",
                 stime.wYear, stime.wMonth , stime.wDay,
                 (stime.wHour + 8) % 24, stime.wMinute, 
                 stime.wSecond, stime.wMilliseconds,
                 log4c_priority_to_string(a_event->evt_priority),
                 a_event->evt_msg);
    }
#endif
    return buffer;
}

/*******************************************************************************/
const log4c_layout_type_t log4c_layout_type_spice = {
    "dated_format",
    dated_format,
};

static int init_dated_format(void)
{
    log4c_layout_type_set(&log4c_layout_type_spice);//自定义格式类型函数指针
    return 0;
}

// ===  FUNCTION  ======================================================================
//  Name:  log_message
//  Description:  记录日志信息
//  @param priority [in]: 日志类别
//  @param file [in]: 文件
//  @param line [in]: 行
//  @param fun [in]: 函数
//  @param fmt [in]: 格式化参数
// =====================================================================================
void log_message(int priority, const char *file, int line, const char *fun, const char *fmt, ...)
{
    const int len_buf = 2048;
    char new_fmt[len_buf];
    int n;
    if (log_category == NULL)
        return;

    n = snprintf(new_fmt, len_buf, "[%s %d %s] ", file, line, fun);
    if (n <= 0)
        return;
 
    va_list ap;
    va_start(ap, fmt);
    vsnprintf(new_fmt, len_buf, fmt, ap);

    va_end(ap);
    log4c_category_log(log_category, priority, new_fmt);
}

// ===  FUNCTION  ======================================================================
//  Name:  log_fini
//  Description:  清理所有申请的内存,关闭它们打开的文件
// =====================================================================================
int test_log_fini(void)
{
    return log4c_fini();
}

static void set_log4c_envirment(void)
{
    setenv("LOG4C_RCPATH", ".", 0);
}

int test_log_init(void)
{
    set_log4c_envirment();
    init_dated_format();
    if (log4c_init() == 1) {
        return -1;
    }

    log_category = log4c_category_get("mycat");
    return 0;
}

log.h

最重要的输出函数其实是log_message,这是实质性输出日志的函数,我们用宏定义给他包装一下,之后就可以直接用

LOG_FATAL("LOG_FATAL");类似的方式来输出日志啦,很方便的!

#ifndef __VCD_LOG_H__
#define __VCD_LOG_H__
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <stdlib.h>
#include <log4c.h>

void log_message(int priority ,
        const char *file, int line, const char *fun,
        const char *fmt , ...);
int test_log_fini(void);

#define LOG_FATAL(fmt,  args...) log_message(LOG4C_PRIORITY_FATAL, basename(__FILE__), __LINE__ , __FUNCTION__ , fmt, ##args)
#define LOG_ERROR(fmt,  args...) log_message(LOG4C_PRIORITY_ERROR, basename(__FILE__), __LINE__ , __FUNCTION__ , fmt, ##args)
#define LOG_WARN(fmt,   args...) log_message(LOG4C_PRIORITY_WARN,  basename(__FILE__), __LINE__ , __FUNCTION__ , fmt, ##args)
#define LOG_NOTICE(fmt, args...) log_message(LOG4C_PRIORITY_NOTICE,basename(__FILE__), __LINE__, __FUNCTION__ , fmt, ##args)
#define LOG_INFO(fmt,   args...) log_message(LOG4C_PRIORITY_INFO,  basename(__FILE__), __LINE__ , __FUNCTION__ , fmt, ##args)
#define LOG_DEBUG(fmt , args...) log_message(LOG4C_PRIORITY_DEBUG, basename(__FILE__), __LINE__ , __FUNCTION__ , fmt, ##args)
#define LOG_TRACE(fmt,  args...) log_message(LOG4C_PRIORITY_TRACE, basename(__FILE__), __LINE__ , __FUNCTION__ , fmt, ##args)

int test_log_init(void);

#endif

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章