【小沐学C++】C++实现日志功能:log4c(Win10+VS2017+CMake)

🎈C++实现日志功能:简单实现及第三方库汇总🎈
🎈C++实现日志功能:log4c(Win10+VS2017)🎈
🎈C++实现日志功能:log4cplus(Win10+VS2017)🎈

1、log4c开源库简介

http://log4c.sourceforge.net/

  • Log4c is a library of C for flexible logging to files, syslog and other destinations. It is modeled after the Log for Java library (http://jakarta.apache.org/log4j/), staying as close to their API as is reasonable. Here is a short introduction to Log4j which describes the API, and design rationale.

  • Log4c 是一个 C 库,用于灵活地记录到文件、系统日志和其他目标。它以 Log for Java 库 ( http://jakarta.apache.org/log4j/ ) 为模型,尽可能接近其 API。这是对 Log4j 的简短介绍,它描述了 API 和设计原理。

  • Mark Mendel 以不同的理念开始了一个并行的 log4c 项目。该设计是面向宏观的,更轻更快,非常适合内核开发。Log4c 也可从 SourceForge ( http://www.sourceforge.net/projects/log4c/ ) 获得。这是正在进行的工作。

  • Last Update: 2016-01-30

  • Last Version: 1.2.4 ( 2013-10-03 )

2、Expat代码下载

因为log4c开源库使用到了另一个第三方库Expat,因此在编译log4c之前,先编译Expat的代码。

  • Welcome to Expat, a stream-oriented XML parser library written in C.
    Expat excels with files too large to fit RAM, and where performance and flexibility are crucial.

  • Expat 是一个用C语言开发的、用来解析XML文档的开发库,它最初是开源的、Mozilla 项目下的一个XML解析器。

  • Expat 是一个用于解析 XML 的 C 库,由 James Clark在 1997 年创立。Expat 是一个面向流的 XML 解析器。这意味着您在开始解析之前向解析器注册处理程序。当解析器发现正在解析的文档中的关联结构时,将调用这些处理程序。开始标记是您可以为其注册处理程序的结构类型的一个示例。

  • Expat 是免费软件。COPYING 您可以根据随此软件包分发的文件中包含的许可条款复制、分发和修改它 。该许可证与 MIT/X Consortium 许可证相同。

https://libexpat.github.io/
https://github.com/libexpat/libexpat/releases
在这里插入图片描述

3、Expat代码编译

将下载的源码文件“libexpat-R_2_4_4.zip”解压之后,
在这里插入图片描述
由于源码文件里已经提供了CMakeLists.txt,所有直接使用cmake加载脚本构建生成VS工程文件。
(1)方法1:直接运行cmake的图形界面进行傻瓜式操作,如下:
在这里插入图片描述

(2)方法2:使用大家常用的cmake的命令行操作,如下:

## 1、打开源代码文件夹
cd C:\Users\tomcat\Desktop\libexpat-R_2_4_4\expat
## 2、新建编译输出文件夹
mkdir build
## 3、进入编译输出文件夹
cd build
## 4、生成.sln工程文件
cmake ..
## 5、编译代码
cmake --build .
  • 生成.sln工程文件的其他写法:
cmake ..
cmake -G "Visual Studio 15" ..
cmake -G "Visual Studio 15 2017 " ..
cmake -G "Visual Studio 15 2017  Win64" ..
cmake -G "Visual Studio 15 2017" .. -A Win32
cmake -G "Visual Studio 15 2017" .. -A x64
  • 编译代码的其他写法:
cmake --build .
cmake --build . --config Debug
cmake --build . --config Release
cmake --build . --target ALL_BUILD --config Release
  • 输出彩色文字:
cmake -E cmake_echo_color --normal hello
cmake -E cmake_echo_color --black hello
cmake -E cmake_echo_color --red hello
cmake -E cmake_echo_color --green hello
cmake -E cmake_echo_color --yellow hello
cmake -E cmake_echo_color --blue hello
cmake -E cmake_echo_color --magenta hello
cmake -E cmake_echo_color --cyan hello
cmake -E cmake_echo_color --white hello

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

编译完毕之后,生成的dll和lib文件如下:
在这里插入图片描述
在win上编译程序release版本(默认debug输出),使用如下命令:

cmake --build . --config Release

在这里插入图片描述

4、log4c代码下载

https://sourceforge.net/projects/log4c/files/log4c/1.2.4/
在这里插入图片描述

5、log4c代码编译

将下载的源码文件“log4c-1.2.4.tar.gz”解压之后,
在这里插入图片描述

  • log4c 已成功编译并在以下平台上运行:

HP-UX release 11.00
Tru 64 release 4.0F and 5.1
Red Hat Linux Intel release 7.x, 8, 9
Red Hat Enterprise Linux 3, 4
Solaris Intel release 8, 9, 10
FreeBSD 6.1-RELEASE
AIX 5.3 (with xlc compiler)
Mac OS X
Windows X
…and other Linux distributions

  • log4c 应该在以下平台上编译和运行:

The BSD family
MS Windows

我们这里想在Windows上编译log4c,需要自己编写cmake脚本来构造VS工程。

5.1 编写脚本文件CMakeLists.txt

很多开源项目如KDE、VTK、OpenCV、Caffe等,都使用cmake来构建。要玩转这些项目,就需要掌握cmake。而且趋势是cmake会更加流行。
main.cc:

#include <iostream>
using namespace std;
 
int main(){
	cout << "Hello World!" << endl;
	return 0;
}

CMakeLists.txt的一般写法:

cmake_minimum_required (VERSION 2.8)
project(hello-world)
add_executable(hello main.cc)

首先我们也需要新建一个“CMakeLists.txt”在log4c的文件夹里面,如下:
在这里插入图片描述

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8.12)
project (log4c)

# add flag
add_definitions(-DHAVE_CONFIG_H)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)

# add var
set(CMAKE_DEBUG_POSTFIX d)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
    set(ARCH_POSTFIX "Win32")
else()
    set(ARCH_POSTFIX x64)
endif()


IF (CMAKE_BUILD_TYPE MATCHES "Release")
    SET(CMAKE_BUILD_POSTFIX "${CMAKE_RELEASE_POSTFIX}")
ELSEIF (CMAKE_BUILD_TYPE MATCHES "MinSizeRel")
    SET(CMAKE_BUILD_POSTFIX "${CMAKE_MINSIZEREL_POSTFIX}")
ELSEIF(CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
    SET(CMAKE_BUILD_POSTFIX "${CMAKE_RELWITHDEBINFO_POSTFIX}")
ELSEIF(CMAKE_BUILD_TYPE MATCHES "Debug")
    SET(CMAKE_BUILD_POSTFIX "${CMAKE_DEBUG_POSTFIX}")
ELSE()
    SET(CMAKE_BUILD_POSTFIX "")
ENDIF()

# add .c and .cpp
include_directories (./src ./src/log4c ./src/sd )
aux_source_directory (./src/log4c DIR_SRCS1)
aux_source_directory (./src/sd DIR_SRCS2)
list(REMOVE_ITEM DIR_SRCS1 "./src/log4c/appender_type_mmap.c") 
list(REMOVE_ITEM DIR_SRCS1 "./src/log4c/appender_type_mmap.h")  
list(REMOVE_ITEM DIR_SRCS1 "./src/log4c/appender_type_mmap.h")  
list(REMOVE_ITEM DIR_SRCS2 "./src/sd/sprintf.osf.c")  
list(REMOVE_ITEM DIR_SRCS2 "./src/sd/domnode.c")  

# add link dir
link_directories("./libexpat-R_2_4_4/lib/${ARCH_POSTFIX}")

# create dll(project1) or lib(project2)
add_library (log4c_shared SHARED ${DIR_SRCS1} ${DIR_SRCS2})
add_library (log4c_static STATIC ${DIR_SRCS1} ${DIR_SRCS2})
set_target_properties (log4c_shared PROPERTIES OUTPUT_NAME "log4c")
set_target_properties (log4c_static PROPERTIES OUTPUT_NAME "log4c_static")
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib/${ARCH_POSTFIX})
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/${ARCH_POSTFIX})
target_compile_definitions( log4c_shared PRIVATE LOG4C_EXPORTS )
target_compile_definitions( log4c_static PRIVATE LOG4C_EXPORTS )

# add libexpat library
list(APPEND EXTRA_LIBS libexpat)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/libexpat-R_2_4_4/include")
target_link_libraries(log4c_shared PUBLIC ${EXTRA_LIBS})
target_include_directories(log4c_shared PUBLIC "${PROJECT_BINARY_DIR}" ${EXTRA_INCLUDES})
target_link_libraries(log4c_static PUBLIC ${EXTRA_LIBS})
target_include_directories(log4c_static PUBLIC "${PROJECT_BINARY_DIR}" ${EXTRA_INCLUDES})

# create project3
add_executable(test ./examples/ConsoleApplication1.cpp)

5.2 配置第三方库文件

将第三方库expat的相关编译好的文件放进来,如下:
在这里插入图片描述
在这里插入图片描述

5.3 添加测试工程

编写一个简单的测试文件“ConsoleApplication1.cpp”,放在log4c文件夹里的examples子文件夹里。
在这里插入图片描述

ConsoleApplication1.cpp:

#include <iostream>
#include "log4c.h"

#ifdef _DEBUG
#pragma comment(lib, "..\\lib\\Win32\\Debug\\log4cd.lib")
#else
#pragma comment(lib, "..\\lib\\Win32\\Release\\log4c.lib")
#endif

int main()
{
    std::cout << "Hello World!\n";
	log4c_init();

	log4c_category_t* mylog = log4c_category_get("framework");
	log4c_category_log(mylog, LOG4C_PRIORITY_DEBUG, "Hello World!");

	log4c_category_t* mycat = NULL;
	mycat = log4c_category_get("six13log.log.app.application2");

	log4c_category_log(mycat, LOG4C_PRIORITY_DEBUG, "Debugging app 2");
	log4c_category_log(mycat, LOG4C_PRIORITY_ERROR,
		"some error from app2 at line %d in file %s",
		__LINE__, __FILE__);

	log4c_fini();
}

5.4 新建文件config.h

将log4c子文件夹src里面的“config.h.in”文件,复制出一份,改名为config.h。
通过将config.h内容修改如下:

/* src/config.h.in.  Generated from configure.in by autoheader.  */

/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
   systems. This function is required for `alloca.c' support on those systems.
   */
#undef CRAY_STACKSEG_END

/* Define to 1 if using `alloca.c'. */
#undef C_ALLOCA

/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA

/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
   */
#undef HAVE_ALLOCA_H

/* Define to 1 if you have the <alloc.h> header file. */
#undef HAVE_ALLOC_H

/* Define to 1 if you have the declaration of `gmtime_r', and to 0 if you
   don't. */
#undef HAVE_DECL_GMTIME_R

/* Define to 1 if you have the declaration of `localtime_r', and to 0 if you
   don't. */
#undef HAVE_DECL_LOCALTIME_R

/* Define to 1 if you have the declaration of `sleep', and to 0 if you don't.
   */
#undef HAVE_DECL_SLEEP

/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H

/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT

/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H

/* Define to 1 if you have the `gethostname' function. */
#undef HAVE_GETHOSTNAME

/* Define to 1 if you have the <getopt.h> header file. */
#undef HAVE_GETOPT_H

/* Define to 1 if you have the `getpagesize' function. */
#undef HAVE_GETPAGESIZE

/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY

/* Define to 1 if you have the `gmtime_r' function. */
#undef HAVE_GMTIME_R

/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H

/* Define to 1 if you have the <langinfo.h> header file. */
#undef HAVE_LANGINFO_H

/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H

/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R

/* Define to 1 if you have the <malloc.h> header file. */
//#undef HAVE_MALLOC_H
#define HAVE_MALLOC_H

/* Define to 1 if you have the <memory.h> header file. */
//#undef HAVE_MEMORY_H

/* Define to 1 if you have the `memset' function. */
//#undef HAVE_MEMSET

/* Define to 1 if you have a working `mmap' system call. */
#undef HAVE_MMAP

/* Define to 1 if you have the `munmap' function. */
#undef HAVE_MUNMAP

/* Define to 1 if you have the `nl_langinfo' function. */
#undef HAVE_NL_LANGINFO

/* Define to 1 if you have the <pthread.h> header file. */
#undef HAVE_PTHREAD_H

/* Define to 1 if you have the `sbrk' function. */
#undef HAVE_SBRK

/* Define to 1 if you have the `sleep' function. */
#undef HAVE_SLEEP

/* Define to 1 if you have the <stdarg.h> header file. */
//#undef HAVE_STDARG_H
#define HAVE_STDARG_H

/* Define to 1 if you have the <stddef.h> header file. */
//#undef HAVE_STDDEF_H
#define HAVE_STDDEF_H

/* Define to 1 if you have the <stdint.h> header file. */
//#undef HAVE_STDINT_H
#define HAVE_STDINT_H

/* Define to 1 if you have the <stdlib.h> header file. */
//#undef HAVE_STDLIB_H
#define HAVE_STDLIB_H

/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP

/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR

/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H

/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H

/* Define to 1 if you have the `strncasecmp' function. */
#undef HAVE_STRNCASECMP

/* Define to 1 if you have the `strrchr' function. */
#undef HAVE_STRRCHR

/* Define to 1 if you have the `strstr' function. */
#undef HAVE_STRSTR

/* Define to 1 if you have the <syslog.h> header file. */
#undef HAVE_SYSLOG_H

/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H

/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H

/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H

/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H

/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H

/* Define to 1 if you have the `utime' function. */
#undef HAVE_UTIME

/* Define to 1 if you have the <utime.h> header file. */
#undef HAVE_UTIME_H

/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
#undef HAVE_UTIME_NULL

/* Define to 1 if you have the <varargs.h> header file. */
#undef HAVE_VARARGS_H

/* Define to 1 if you have the `vprintf' function. */
#undef HAVE_VPRINTF

/* Define to the sub-directory in which libtool stores uninstalled libraries.
   */
#undef LT_OBJDIR

/* Name of package */
#undef PACKAGE

/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT

/* Define to the full name of this package. */
#undef PACKAGE_NAME

/* Define to the full name and version of this package. */
#undef PACKAGE_STRING

/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME

/* Define to the home page for this package. */
#undef PACKAGE_URL

/* Define to the version of this package. */
#undef PACKAGE_VERSION

/* If using the C implementation of alloca, define if you know the
   direction of stack growth for your system; otherwise it will be
   automatically deduced at runtime.
	STACK_DIRECTION > 0 => grows toward higher addresses
	STACK_DIRECTION < 0 => grows toward lower addresses
	STACK_DIRECTION = 0 => direction of growth unknown */
#undef STACK_DIRECTION

/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS

/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME

/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME

/* Version number of package */
//#undef VERSION
#define VERSION "1.2.4"
#define LOG4C_RCPATH "d:"

/* build log4c with initialization constructors */
#undef WITH_CONSTRUCTORS

/* Define if we found pthread.h libpthread */
#undef WITH_ROLLINGFILE

/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
   `char[]'. */
#undef YYTEXT_POINTER

/* "POSIXandGNU extensions" */
#undef _GNU_SOURCE

/* Enable automatic reread of log4crc file */
#undef __ENABLE_REREAD__

/* Define to empty if `const' does not conform to ANSI C. */
#undef const

/* Define to `__inline__' or `__inline' if that's what the C compiler
   calls it, or to nothing if 'inline' is not supported under any name.  */
#ifndef __cplusplus
#undef inline
#endif

/* Define to `unsigned int' if <sys/types.h> does not define. */
//#undef size_t

/* Trying to use __va_copy on non-C89 systems */
//#undef va_copy

5.5 cmake生成VS工程

在这里插入图片描述
在这里插入图片描述

5.6 配置文件log4crc

配置文件内容使用XML语法,以及以固定名称log4crc命名。根元素是< log4c >,可以通过属性控制配置文件版本界面"version"。它支持以下 4 个元素:“< config >、< category >、< appender > 和< layout >”。

  • < config> 元素控制全局 log4c 配置。它有 3 个子元素。< nocleanup> 标志禁止 log4c 析构函数例程。 元素设置用于格式化log4c_logging_event_t对象的缓冲区大小。如果设置为 0,则分配是动态的( 元素当前未使用)。
  • < category> 元素有 3 个可能的属性: category “name”、 category"priority"和 category “appender”。未来的版本将处理每个类别的多个附加程序。
  • < appender> 元素有 3 个可能的属性: appender “name”、 appender"type"和 appender “layout”。
  • < layout> 元素有 2 个可能的属性: layout"name"和 layout “type”。

这是log4crc配置文件示例:

<?xml 版本= “1.0”编码= “ISO-8859-1”?>
<!DOCTYPE log4c SYSTEM "" >
<log4c>
        <配置>
                <bufsize>0</bufsize>
                <调试级别= “0” />
                <nocleanup>0</nocleanup>
        </配置>
        <!-- 根类==========================================-->
        <类别名称= “根”优先级= “通知” />
        <!--默认附加程序 ======================================-->
        <appender name= "stdout" type= "stream" layout= "basic" />
        <appender name= "stderr" type= "stream" layout= "dated" />
        <appender 名称= “系统日志”类型= “系统日志”布局= “基本” />
        <!--默认布局 ========================================-->
        <布局名称= “基本”类型= “基本” />
        <布局名称= “过时”类型= “过时” />
</log4c>

XML 似乎是在 C API 中保持 log4j 配置功能的最佳选择。

而我们这里测试使用的log4crc文件的内容如下:

<?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="notice"/>
    <category name="six13log.log" priority="error" appender="stdout" />

	<rollingpolicy name="myrollingpolicy" type="sizewin" maxsize="1024" maxnum="10" />

	<appender name="myrollingfileappender" type="rollingfile" logdir="." prefix="myprefix" layout="dated" rollingpolicy="myrollingpolicy" />
	
	<appender name="stdout" type="stream" layout="basic"/>
	<appender name="stderr" type="stream" layout="dated"/>
	<appender name="syslog" type="syslog" layout="basic"/>

	<appender name="s13file" type="s13_file" layout="basic"/>
	<appender name="plain_stderr" type="s13_stderr" layout="none"/>
	<appender name="cat_stderr" type="s13_stderr" layout="catlayout"/>
	<appender name="xml_stderr" type="s13_stderr" layout="xmllayout"/>
        <appender name="user_stderr" type="s13_stderr" layout="userlayout"/>

	<layout name="basic" type="basic"/>
	<layout name="dated" type="dated"/>
	
	<layout name="catlayout" type="s13_cat"/>
	<layout name="xmllayout" type="s13_xml"/>
        <layout name="none" type="s13_none"/>
	<layout name="userlayout" type="s13_userloc"/>
	
	<category name="six13log.log.app.application2" priority="debug" appender="cat_stderr" />
	<category name="six13log.log.app.application3" priority="debug" appender="user_stderr" />
        <category name="six13log.log.app" priority="debug" appender="myrollingfileappender" />

</log4c>

5.7 VS2017编译

在编译的过程中,当然还会出现一些比较容易修改的小错误,这里就不再详细说明了。有不懂的小伙伴可以留言予以解答。
在这里插入图片描述
在这里插入图片描述

后续

如果你觉得这些文字有一点点用处,可以给作者点个赞;╮( ̄▽ ̄)╭
如果你感觉作者写的不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进。o_O???
谢谢各位小伙伴们啦( ´ ▽ ‘)ノ ( ´ ▽ ` )っ!!!

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值