log4c库
介绍
log4c 是一个 C 语言实现的日志库,它是 log4j(Java 语言的日志框架)的 C 语言版本,旨在为 C 语言应用程序提供灵活、可配置的日志功能。log4c 提供了丰富的日志功能,包括日志级别、日志输出目标、日志格式等,支持不同的日志策略,比如滚动文件、按大小或按日期滚动等,具有良好的可扩展性和配置能力。
安装
解压安装
下载链接
https://sourceforge.net/projects/log4c/files/log4c/1.2.4/log4c-1.2.4.tar.gz/download?use_mirror=onboardcloud&login=from_csdn
tar -zxvf log4c-1.2.4.tar.gz
cd log4c-1.2.4
./configure --prefix=/usr/local/log4c # 必须明确指定安装路径
make
make install
注意
--prefix
必须明确指定安装路径
/usr/local/log4c
这个是系统路径,安装完了之后就可以直接使用,不需要指明头文件位置
如果安装到其他位置,再执行完make install
之后会出现在指定的目录下,使用的时候需要指明头文件位置;
apt安装
sudo apt update
sudo apt install liblog4c-dev
使用方式
cmake 文件编写
apt安装
# 指定 CMake 的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 指定项目名称和语言
project(kylin-wine-starter VERSION 1.0 LANGUAGES C)
# 设置 C 编译器标准
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
# 自动查找所有的 .c 文件
file(GLOB SOURCES "*.c")
# 定义可执行文件的名称和源文件
add_executable(${PROJECT_NAME} ${SOURCES})
pkg_check_modules(LOG4C REQUIRED log4c)
include_directories(${LOG4C_INCLUDE_DIRS})
link_directories(${LOG4C_LIBRARY_DIRS})
target_link_libraries(${PROJECT_NAME} ${LOG4C_LIBRARIES})
解压安装
此处展示的文件结构是本篇文章演示的文件结构
# 指定 CMake 的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 指定项目名称和语言
project(kylin-wine-starter VERSION 1.0 LANGUAGES C)
# 设置 C 编译器标准
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
# 自动查找所有的 .c 文件
file(GLOB SOURCES "*.c")
# 定义可执行文件的名称和源文件
add_executable(${PROJECT_NAME} ${SOURCES})
set(3RDLIB_PATH ${PROJECT_SOURCE_DIR}/third)
list(APPEND 3RD_LIBS_INCLUDE "${3RDLIB_PATH}/include")
list(APPEND 3RD_LIBS_INCLUDE "${3RDLIB_PATH}/include/log4c")
link_directories("${3RDLIB_PATH}/lib")
target_link_libraries(${PROJECT_NAME} log4c)
# link_libraries(log4c) # 禁止使用这种链接方式
target_include_directories(${PROJECT_NAME} PUBLIC
${PROJECT_BINARY_DIR}
${EXTRA_INCLUDE}
${3RD_LIBS_INCLUDE}
)
配置输出位置以及轮转策略
log4c使用结构图
创建一个category管理多个appender,
每个appender都是一个文件,
每个appender中都有一个layout,
每个layout都规定了日志文件中输出的格式;
每个appender都可以设置轮转格式,
需要给appender指定一个轮转文件rollingfile,
给rollingfile指定一个轮转策略rolling_policy,
给rolling_policy 指定一个限制文件大小rolling_sizewin。
这样就能实现通过文件大小进行轮转了
配置文件
- 配置文件使用
xml
格式,默认在当前工作目录下找;默认找到是log4crc
(不带扩展名),如果有扩展名(log4crc.xml
)需要特别配置环境变量 LOG4C_RCPATH
配置环境变量- 优先找工作目录配置文件,再通过环境变量找配置文件;只要找到了就会停下来,不论这个配置文件是对是错
配置文件category,appender,rollingpolicy,layout 的相互关系是通过name来相互绑定的
<?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>
<category name="root" priority="error" appender="stdout"/>
<appender name="stdout" type="stream" layout="basic"/>
<appender name="stderr" type="stream" layout="dated"/>
<appender name="syslog" type="syslog" layout="basic"/>
<layout name="basic" type="basic"/>
<layout name="dated" type="dated"/>
</log4c>
log4c_init();// 初始化
// 代码中也是通过配置文件中的name进行获取的
log4c_category_t* mycat = log4c_category_get("root");
log4c_category_log(mycat,LOG4C_PRIORITY_DEBUG,"输出内容");
log4c_fini();// 销毁
layout 日志输出格式
<layout name="basic" type="basic"/>
这里的type
可以替换为下面库里面提供的这些
// layout
const log4c_layout_type_t log4c_layout_type_basic = {
"basic",// 布局名称,可以替换到layout的type位置
basic_format,// 布局函数,可以在接下来介绍的API部分为layout设置type
};
const log4c_layout_type_t log4c_layout_type_basic_r = {
"basic_r",
basic_r_format,
};
const log4c_layout_type_t log4c_layout_type_dated_local_r = {
"dated_local_r",
dated_local_r_format,
};
const log4c_layout_type_t log4c_layout_type_dated_local = {
"dated_local",
dated_local_format,
};
const log4c_layout_type_t log4c_layout_type_dated_r = {
"dated_r",
dated_r_format,
};
const log4c_layout_type_t log4c_layout_type_dated = {
"dated",
dated_format,
};
appender 日志文件
<appender name="myrollingfileappender" type="rollingfile" logdir="." prefix="myprefix" layout="dated_time" rollingpolicy="myrollingpolicy" />
使用下面字符串中的内容替换 type
// 将日志信息写入内存映射文件(mmap)。内存映射文件是操作系统提供的一种将文件或设备映射到内存中的技术,允许程序像操作内存一样操作文件。
const log4c_appender_type_t log4c_appender_type_mmap = {
"mmap",
mmap_open,
mmap_append,
mmap_close,
};
// 将日志信息写入到文件中,并在日志文件大小达到一定限制时自动进行轮转(即生成新的日志文件)
const log4c_appender_type_t log4c_appender_type_rollingfile = {
"rollingfile",
rollingfile_open,
rollingfile_append,
rollingfile_close
};
// 将日志信息输出到一个流(如标准输出流、文件流等)。这种方式适用于将日志输出到控制台或文件等流设备。
const log4c_appender_type_t log4c_appender_type_stream = {
"stream",
stream_open,
stream_append,
stream_close,
};
// 这应该是 stream 的另一种实现,可能有不同的实现或配置,用于特殊场景。
const log4c_appender_type_t log4c_appender_type_stream2 = {
"stream2",
stream2_open,
stream2_append,
stream2_close,
};
// 将日志信息发送到操作系统的系统日志(通常是 syslog)。适用于需要将日志信息传递给系统日志守护进程进行集中管理的场景。
const log4c_appender_type_t log4c_appender_type_syslog = {
"syslog",
syslog_open,
syslog_append,
syslog_close,
};
logdir="."
当 type 为rollingfile
的时候设置日志存储位置
prefix="myprefix"
当 type 为rollingfile
的时候设置日志的前缀,通常轮转之后的文件是prefix.数字
rollingpolicy
指的是轮转策略
<rollingpolicy name="myrollingpolicy" type="sizewin" maxsize="1024" maxnum="3" />
库中只提供了一种通过文件大小进行轮转的策略
maxsize
表示每个文件最大容量
maxnum
轮转过程中保存最近3个文件
const log4c_rollingpolicy_type_t log4c_rollingpolicy_type_sizewin = {
"sizewin", // 写入 type 位置
sizewin_init,
sizewin_is_triggering_event,
sizewin_rollover,
sizewin_fini
};
catgory 用来管理appender
<category name="root" priority="error" appender="stdout"/>
priority
可以替换为下面的这些, 将下面注释中的字符串
进行替换
// priority —— 输出等级,值越小的等级越高
typedef enum {
/** fatal */ LOG4C_PRIORITY_FATAL = 000,
/** alert */ LOG4C_PRIORITY_ALERT = 100,
/** crit */ LOG4C_PRIORITY_CRIT = 200,
/** error */ LOG4C_PRIORITY_ERROR = 300,
/** warn */ LOG4C_PRIORITY_WARN = 400,
/** notice */ LOG4C_PRIORITY_NOTICE = 500,
/** info */ LOG4C_PRIORITY_INFO = 600,
/** debug */ LOG4C_PRIORITY_DEBUG = 700,
/** trace */ LOG4C_PRIORITY_TRACE = 800,
/** notset */ LOG4C_PRIORITY_NOTSET = 900,
/** unknown */ LOG4C_PRIORITY_UNKNOWN = 1000
} log4c_priority_level_t;
直接API
一般情况下只需要引用 log4c.h 这个头文件就可以了,不需要像我下面这样一个一个的列出来,如果在使用的时候发现没有再添加引用就可以了
安装到系统中,头文件引用方式如下
// #include "log4c.h"
// #include "log4c/appender.h"
// #include "log4c/appender_type_rollingfile.h"
// #include "log4c/rollingpolicy.h"
// #include "log4c/rollingpolicy_type_sizewin.h"
// #include "log4c/layout_type_dated.h"
未安装到系统中,头文件引用方式如下
#include "third/include/log4c.h"
#include "third/include/log4c/rc.h"
#include "third/include/log4c/appender.h"
#include "third/include/log4c/layout.h"
#include "third/include/log4c/category.h"
#include "third/include/log4c/appender_type_stream.h"
#include "third/include/log4c/appender_type_rollingfile.h"
#include "third/include/log4c/rollingpolicy.h"
#include "third/include/log4c/rollingpolicy_type_sizewin.h"
#include "third/include/log4c/layout_type_dated_local.h"
#include "third/include/log4c/layout_type_dated.h"
#include "third/include/log4c/layout_type_basic.h"
#include "third/include/log4c/priority.h"
log4c_category_t* mycat = NULL;
void create_log4c_API(char* dir,char* filename,long long size,int num){
// log4c初始化
if(log4c_init()){
puts("497 log4c_init error");
return;
}
// 创建category
mycat = log4c_category_new(__FILE__);
if(mycat == NULL){
puts("mycat is NULL");
return;
}
// 创建appender
log4c_appender_t* appender = log4c_appender_new("myappender");
if(appender == NULL){
puts("appender is NULL");
return;
}
// 设置appender类型
log4c_appender_set_type(appender, &log4c_appender_type_rollingfile);// 文件轮转类型
// 为category 设置 appender
log4c_category_set_appender(mycat,appender);
// 设置轮转的文件相关信息
rollingfile_udata_t * rollingfile_udata = rollingfile_make_udata();
// 设置目录
rollingfile_udata_set_logdir(rollingfile_udata,dir);
// 设置文件前缀
rollingfile_udata_set_files_prefix(rollingfile_udata,filename);
// 判断目录是否可写
if(access(dir,W_OK) == -1){
puts("no write permission");
return;
}
// 配置文件滚动策略(基于文件大小滚动)
log4c_rollingpolicy_t* rollingpolicy = log4c_rollingpolicy_new("sizewin");
// 为文件设置滚动策略
rollingfile_udata_set_policy(rollingfile_udata,rollingpolicy);
// 设置滚动策略参数
rollingpolicy_sizewin_udata_t* swup = sizewin_make_udata();
sizewin_udata_set_file_maxsize(swup, size); // 每个日志文件最大大小为1MB
sizewin_udata_set_max_num_files(swup, num); // 最多保留5个文件
// 为策略设置滚动策略参数
log4c_rollingpolicy_set_udata(rollingpolicy,swup);
// 初始化滚动策略
int result = log4c_rollingpolicy_init(rollingpolicy, rollingfile_udata);
if (result != 0) {
// 处理错误
puts("373 error");
return;
}
// 设置附加器的滚动策略
log4c_appender_set_udata(appender, rollingfile_udata);
// 创建输出格式
log4c_layout_t* mylayout = log4c_layout_new("mylayout");
log4c_layout_set_type(mylayout,&log4c_layout_type_dated);
// 为输出日志设置输出格式
log4c_appender_set_layout(appender,mylayout);
// 创建/打开日志文件,一般情况下是不需要明确的打开文件
// 在验证日志没有正确的写入是不是因为没有打开文件造成的时候,可以使用这个函数排除错误
// if(log4c_appender_open(appender) == 0){
// puts("537 file open success");
// }else{
// puts("failed to open");
// }
// 输出必须要设置日志等级
log4c_category_set_priority(mycat,LOG4C_PRIORITY_DEBUG);
// 输出日志
log4c_category_log(mycat,LOG4C_PRIORITY_INFO,"log4c_api 配置完成");
// log4c 销毁
log4c_fini();
}
log4c 创建和销毁
log4c_init(); // 创建
log4c_fini(); // 销毁
layout 日志输出格式
log4c_layout_t* mylayout = log4c_layout_new("mylayout");
创建layoutlog4c_layout_t* mylayout = log4c_layout_get("mylayout");
从配置文件中获取name
是mylayout
的layoutlog4c_layout_set_type(mylayout,&log4c_layout_type_dated);
设置输出格式
// layout
const log4c_layout_type_t log4c_layout_type_basic = {
"basic",
basic_format, // 布局函数,替换到第二个参数
};
const log4c_layout_type_t log4c_layout_type_basic_r = {
"basic_r",
basic_r_format,
};
const log4c_layout_type_t log4c_layout_type_dated_local_r = {
"dated_local_r",
dated_local_r_format,
};
const log4c_layout_type_t log4c_layout_type_dated_local = {
"dated_local",
dated_local_format,
};
const log4c_layout_type_t log4c_layout_type_dated_r = {
"dated_r",
dated_r_format,
};
const log4c_layout_type_t log4c_layout_type_dated = {
"dated",
dated_format,
};
log4c_appender_set_layout(appender,mylayout);
将layout绑定到appender上
appender 日志文件
log4c_appender_t* appender = log4c_appender_new("myappender");
创建log4c_appender_t* appender = log4c_appender_get("myappender");
获取配置文件中name
为myappender
的appender
log4c_appender_set_type(appender, &log4c_appender_type_rollingfile);
设置appender类型,下面的放到第二个参数的位置
// 将日志信息写入内存映射文件(mmap)。内存映射文件是操作系统提供的一种将文件或设备映射到内存中的技术,允许程序像操作内存一样操作文件。
const log4c_appender_type_t log4c_appender_type_mmap = {
"mmap",
mmap_open,
mmap_append,
mmap_close,
};
// 将日志信息写入到文件中,并在日志文件大小达到一定限制时自动进行轮转(即生成新的日志文件)
const log4c_appender_type_t log4c_appender_type_rollingfile = {
"rollingfile",
rollingfile_open,
rollingfile_append,
rollingfile_close
};
// 将日志信息输出到一个流(如标准输出流、文件流等)。这种方式适用于将日志输出到控制台或文件等流设备。
const log4c_appender_type_t log4c_appender_type_stream = {
"stream",
stream_open,
stream_append,
stream_close,
};
// 这应该是 stream 的另一种实现,可能有不同的实现或配置,用于特殊场景。
const log4c_appender_type_t log4c_appender_type_stream2 = {
"stream2",
stream2_open,
stream2_append,
stream2_close,
};
// 将日志信息发送到操作系统的系统日志(通常是 syslog)。适用于需要将日志信息传递给系统日志守护进程进行集中管理的场景。
const log4c_appender_type_t log4c_appender_type_syslog = {
"syslog",
syslog_open,
syslog_append,
syslog_close,
};
rollingfile_udata_t * rollingfile_udata = rollingfile_make_udata();
只能使用这种方式创建轮转的文件相关信息rollingfile_udata_set_logdir(rollingfile_udata,dir);
设置目录rollingfile_udata_set_files_prefix(rollingfile_udata,prefix);
设置文件前缀log4c_rollingpolicy_t* rollingpolicy = log4c_rollingpolicy_new("sizewin");
配置文件滚动策略(基于文件大小滚动)rollingpolicy_sizewin_udata_t* swup = sizewin_make_udata();
只能使用这种方式创建滚动策略参数sizewin_udata_set_file_maxsize(swup, size);
设置每个文件限定大小sizewin_udata_set_max_num_files(swup, num);
设置最多保留多少个轮转文件log4c_appender_set_layout(appender,mylayout);
为输出日志设置输出格式log4c_appender_set_udata(appender, rollingfile_udata);
设置附加器的滚动策略rollingfile_udata_set_policy(rollingfile_udata,rollingpolicy);
为文件设置滚动策略log4c_rollingpolicy_set_udata(rollingpolicy,swup);
为策略设置滚动策略参数log4c_rollingpolicy_init(rollingpolicy, rollingfile_udata);
初始化滚动策略
catgory 用来管理appender
log4c_category_t* mycat = log4c_category_new("mycategory")
创建log4c_category_t* mycat = log4c_category_get("mycategory")
从配置文件中获取name
为mycategory
的categorylog4c_category_set_priority(mycat,LOG4C_PRIORITY_DEBUG);
设置日志等级log4c_category_log(mycat,LOG4C_PRIORITY_INFO,"log4c_api 配置完成");
输出日志log4c_category_set_appender(mycat,appender);
设置appender
设置日志等级和输出日志部分都需要日志等级,可以使用下面的进行替换
// priority —— 输出等级,值越小的等级越高
typedef enum {
/** fatal */ LOG4C_PRIORITY_FATAL = 000,
/** alert */ LOG4C_PRIORITY_ALERT = 100,
/** crit */ LOG4C_PRIORITY_CRIT = 200,
/** error */ LOG4C_PRIORITY_ERROR = 300,
/** warn */ LOG4C_PRIORITY_WARN = 400,
/** notice */ LOG4C_PRIORITY_NOTICE = 500,
/** info */ LOG4C_PRIORITY_INFO = 600,
/** debug */ LOG4C_PRIORITY_DEBUG = 700,
/** trace */ LOG4C_PRIORITY_TRACE = 800,
/** notset */ LOG4C_PRIORITY_NOTSET = 900,
/** unknown */ LOG4C_PRIORITY_UNKNOWN = 1000
} log4c_priority_level_t;
网上的教程很少,AI的回答中使用的函数也都是log4c中没有的,我只能为后来者尽一些绵薄之力,文章讲解不清的地方请见谅,如果要想更精细的控制轮转需要把头埋进源码,希望对各位有帮助
参考
log4c 使用心得+总结