C++实现日志功能:简单实现及第三方库汇总
C++实现日志功能:log4c(Win10+VS2017)
C++实现日志功能:log4cplus(Win10+VS2017)
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 )
因为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
将下载的源码文件“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 .
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
https://sourceforge.net/projects/log4c/files/log4c/1.2.4/
将下载的源码文件“log4c-1.2.4.tar.gz”解压之后,
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
The BSD family
MS Windows
我们这里想在Windows上编译log4c,需要自己编写cmake脚本来构造VS工程。
很多开源项目如KDE、VTK、OpenCV、Caffe等,都使用cmake来构建。要玩转这些项目,就需要掌握cmake。而且趋势是cmake会更加流行。
main.cc:
#include
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)
编写一个简单的测试文件“ConsoleApplication1.cpp”,放在log4c文件夹里的examples子文件夹里。
ConsoleApplication1.cpp:
#include
#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();
}
将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 header file. */
//#undef HAVE_MALLOC_H
#define HAVE_MALLOC_H
/* Define to 1 if you have the 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 header file. */
//#undef HAVE_STDARG_H
#define HAVE_STDARG_H
/* Define to 1 if you have the header file. */
//#undef HAVE_STDDEF_H
#define HAVE_STDDEF_H
/* Define to 1 if you have the header file. */
//#undef HAVE_STDINT_H
#define HAVE_STDINT_H
/* Define to 1 if you have the 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 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 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
配置文件内容使用XML语法,以及以固定名称log4crc命名。根元素是< log4c >,可以通过属性控制配置文件版本界面"version"。它支持以下 4 个元素:“< config >、< category >、< appender > 和< layout >”。
这是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>
在编译的过程中,当然还会出现一些比较容易修改的小错误,这里就不再详细说明了。有不懂的小伙伴可以留言予以解答。
如果你觉得这些文字有一点点用处,可以给作者点个赞;╮( ̄▽ ̄)╭
如果你感觉作者写的不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进。o_O???
谢谢各位小伙伴们啦( ´ ▽ ‘)ノ ( ´ ▽ ` )っ!!!