今天給大家分享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