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