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

 

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