原文:http://www.cppblog.com/tx7do/articles/11719.html
日志系统的另一个基本功能就是能够让使用者按照自己的意愿来控制什么时候,哪些log信息可以输出。
如果能够让用户在任意时刻设置允许输出的LogLevel的信息就好了,log4cplus通过LogLevelManager、
LogLog、Filter三种方式实现了上述功能。
### 优先级控制 ###
在研究LogLevelManager之前,首先介绍一下log4cplus中logger的存储机制,在log4cplus中,所有
logger都通过一个层次化的结构(其实内部是hash表)来组织的,有一个Root级别的logger,可以通
过以下方法获取:
Logger root = Logger::getRoot();
用户定义的logger都有一个名字与之对应,比如:
Logger test = Logger::getInstance("test");
可以定义该logger的子logger:
Logger subTest = Logger::getInstance("test.subtest");
注意Root级别的logger只有通过getRoot方法获取,Logger::getInstance("root")获得的是它的
子对象而已。有了这些具有父子关系的logger之后可分别设置其LogLevel,比如:
root.setLogLevel( ... );
Test.setLogLevel( ... );
subTest.setLogLevel( ... );
logger的这种父子关联性会体现在优先级控制方面,log4cplus将输出的log信息按照LogLevel
(从低到高)分为:
NOT_SET_LOG_LEVEL ( -1) :接受缺省的LogLevel,如果有父logger则继承它的LogLevel
ALL_LOG_LEVEL ( 0) :开放所有log信息输出
TRACE_LOG_LEVEL ( 0) :开放trace信息输出(即ALL_LOG_LEVEL)
DEBUG_LOG_LEVEL (10000) :开放debug信息输出
INFO_LOG_LEVEL (20000) :开放info信息输出
WARN_LOG_LEVEL (30000) :开放warning信息输出
ERROR_LOG_LEVEL (40000) :开放error信息输出
FATAL_LOG_LEVEL (50000) :开放fatal信息输出
OFF_LOG_LEVEL (60000) :关闭所有log信息输出
LogLevelManager负责设置logger的优先级,各个logger可以通过setLogLevel设置自己的优先级,
当某个logger的LogLevel设置成NOT_SET_LOG_LEVEL时,该logger会继承父logger的优先级,另外,
如果定义了重名的多个logger, 对其中任何一个的修改都会同时改变其它logger,我们举例说明:
〖例6〗
#include "log4cplus/logger.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/loglevel.h"
#include <iostream>
using namespace std;
using namespace log4cplus;
int main()
{
SharedAppenderPtr _append(new ConsoleAppender());
_append->setName("test");
Logger::getRoot().addAppender(_append);
Logger root = Logger::getRoot();
Logger test = Logger::getInstance("test");
Logger subTest = Logger::getInstance("test.subtest");
LogLevelManager& llm = getLogLevelManager();
cout << endl << "Before Setting, Default LogLevel" << endl;
LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
cout << endl << "Setting test.subtest to WARN" << endl;
subTest.setLogLevel(WARN_LOG_LEVEL);
LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
cout << endl << "Setting test.subtest to TRACE" << endl;
test.setLogLevel(TRACE_LOG_LEVEL);
LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()))
cout << endl << "Setting test.subtest to NO_LEVEL" << endl;
subTest.setLogLevel(NOT_SET_LOG_LEVEL);
LOG4CPLUS_FATAL(root, "root: " << llm.toString(root.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test.subtest: " << llm.toString(subTest.getChainedLogLevel()) << '\n')
cout << "create a logger test_bak, named \"test_\", too. " << endl;
Logger test_bak = Logger::getInstance("test");
cout << "Setting test to INFO, so test_bak also be set to INFO" << endl;
test.setLogLevel(INFO_LOG_LEVEL);
LOG4CPLUS_FATAL(root, "test: " << llm.toString(test.getChainedLogLevel()))
LOG4CPLUS_FATAL(root, "test_bak: " << llm.toString(test_bak.getChainedLogLevel()))
return 0;
}
输出结果:
Before Setting, Default LogLevel
FATAL - root: DEBUG
FATAL - test: DEBUG
FATAL - test.subtest: DEBUG
Setting test.subtest to WARN
FATAL - root: DEBUG
FATAL - test: DEBUG
FATAL - test.subtest: WARN
Setting test.subtest to TRACE
FATAL - root: DEBUG
FATAL - test: TRACE
FATAL - test.subtest: WARN
Setting test.subtest to NO_LEVEL
FATAL - root: DEBUG
FATAL - test: TRACE
FATAL - test.subtest: TRACE
create a logger test_bak, named "test_", too.
Setting test to INFO, so test_bak also be set to INFO
FATAL - test: INFO
FATAL - test_bak: INFO
下面的例子演示了如何通过设置LogLevel来控制用户的log信息输出:
〖例7〗
#include "log4cplus/logger.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/loglevel.h"
#include <iostream>
using namespace std;
using namespace log4cplus;
void ShowMsg(void)
{
LOG4CPLUS_TRACE(Logger::getRoot(),"info")
LOG4CPLUS_DEBUG(Logger::getRoot(),"info")
LOG4CPLUS_INFO(Logger::getRoot(),"info")
LOG4CPLUS_WARN(Logger::getRoot(),"info")
LOG4CPLUS_ERROR(Logger::getRoot(),"info")
LOG4CPLUS_FATAL(Logger::getRoot(),"info")
}
int main()
{
SharedAppenderPtr _append(new ConsoleAppender());
_append->setName("test");
_append->setLayout(std::auto_ptr(new TTCCLayout()));
Logger root = Logger::getRoot();
root.addAppender(_append);
cout << endl << "all-log allowed" << endl;
root.setLogLevel(ALL_LOG_LEVEL);
ShowMsg();
cout << endl << "trace-log and above allowed" << endl;
root.setLogLevel(TRACE_LOG_LEVEL);
ShowMsg();
cout << endl << "debug-log and above allowed" << endl;
root.setLogLevel(DEBUG_LOG_LEVEL);
ShowMsg();
cout << endl << "info-log and above allowed" << endl;
root.setLogLevel(INFO_LOG_LEVEL);
ShowMsg();
cout << endl << "warn-log and above allowed" << endl;
root.setLogLevel(WARN_LOG_LEVEL);
ShowMsg();
cout << endl << "error-log and above allowed" << endl;
root.setLogLevel(ERROR_LOG_LEVEL);
ShowMsg();
cout << endl << "fatal-log and above allowed" << endl;
root.setLogLevel(FATAL_LOG_LEVEL);
ShowMsg();
cout << endl << "log disabled" << endl;
root.setLogLevel(OFF_LOG_LEVEL);
ShowMsg();
return 0;
}
输出结果:
all-log allowed
10-17-04 10:11:40,587 [1075298944] TRACE root <> - info
10-17-04 10:11:40,590 [1075298944] DEBUG root <> - info
10-17-04 10:11:40,591 [1075298944] INFO root <> - info
10-17-04 10:11:40,591 [1075298944] WARN root <> - info
10-17-04 10:11:40,592 [1075298944] ERROR root <> - info
10-17-04 10:11:40,592 [1075298944] FATAL root <> - info
trace-log and above allowed
10-17-04 10:11:40,593 [1075298944] TRACE root <> - info
10-17-04 10:11:40,593 [1075298944] DEBUG root <> - info
10-17-04 10:11:40,594 [1075298944] INFO root <> - info
10-17-04 10:11:40,594 [1075298944] WARN root <> - info
10-17-04 10:11:40,594 [1075298944] ERROR root <> - info
10-17-04 10:11:40,594 [1075298944] FATAL root <> - info
debug-log and above allowed
10-17-04 10:11:40,595 [1075298944] DEBUG root <> - info
10-17-04 10:11:40,595 [1075298944] INFO root <> - info
10-17-04 10:11:40,596 [1075298944] WARN root <> - info
10-17-04 10:11:40,596 [1075298944] ERROR root <> - info
10-17-04 10:11:40,596 [1075298944] FATAL root <> - info
info-log and above allowed
10-17-04 10:11:40,597 [1075298944] INFO root <> - info
10-17-04 10:11:40,597 [1075298944] WARN root <> - info
10-17-04 10:11:40,597 [1075298944] ERROR root <> - info
10-17-04 10:11:40,598 [1075298944] FATAL root <> - info
warn-log and above allowed
10-17-04 10:11:40,598 [1075298944] WARN root <> - info
10-17-04 10:11:40,598 [1075298944] ERROR root <> - info
10-17-04 10:11:40,599 [1075298944] FATAL root <> - info
error-log and above allowed
10-17-04 10:11:40,599 [1075298944] ERROR root <> - info
10-17-04 10:11:40,600 [1075298944] FATAL root <> - info
fatal-log and above allowed
10-17-04 10:11:40,600 [1075298944] FATAL root <> - info
log disabled
用户也可以自行定义LogLevel,操作比较简单,首先要定义LEVEL值,比如HELLO_LOG_LEVEL定义如下:
/* DEBUG_LOG_LEVEL < HELLO_LOG_LEVEL < INFO_LOG_LEVEL */
const LogLevel HELLO_LOG_LEVEL = 15000;
然后定义以下宏即可:
/* define MACRO LOG4CPLUS_HELLO */
#define LOG4CPLUS_HELLO(logger, logEvent) \
if(logger.isEnabledFor(HELLO_LOG_LEVEL)) { \
log4cplus::tostringstream _log4cplus_buf; \
_log4cplus_buf << logEvent; \
logger.forcedLog(HELLO_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \
}
不过log4cplus没有提供给用户一个接口来实现LEVEL值与字符串的转换,所以当带格式输出LogLevel字符
串时候会显示"UNKNOWN", 不够理想。比如用TTCCLayout控制输出的结果可能会如下所示:
10-17-04 11:17:51,124 [1075298944] UNKNOWN root <> - info
而不是期望的以下结果:
10-17-04 11:17:51,124 [1075298944] HELLO root <> - info
要想实现第二种结果,按照log4cplus现有的接口机制,只能改其源代码后重新编译,方法是在loglevel.cxx
中加入:
#define _HELLO_STRING LOG4CPLUS_TEXT("HELLO")
然后修改log4cplus::tstring defaultLogLevelToStringMethod(LogLevel ll)函数,增加一个判断:
case HELLO_LOG_LEVEL: return _HELLO_STRING;
重新编译log4cplus源代码后生成库文件,再使用时即可实现满意效果。
### 调试模式 ###
即通过loglog来控制输出调试、警告或错误信息,见例4,这里不再赘述。
### 基于脚本配置来过滤log信息 ###
除了通过程序实现对log环境的配置之外,log4cplus通过PropertyConfigurator类实现了基于脚本配置的功能。
通过脚本可以完成对logger、appender和layout的配置,因此可以解决怎样输出,输出到哪里的问题,我将在
全文的最后一部分中提到多线程环境中如何利用脚本配置来配合实现性能测试,本节将重点介绍基脚本实现过
滤log信息的功能。
首先简单介绍一下脚本的语法规则:
包括Appender的配置语法和logger的配置语法,其中:
1.Appender的配置语法:
(1)设置名称:
/*设置方法*/
log4cplus.appender.appenderName=fully.qualified.name.of.appender.class
例如(列举了所有可能的Appender,其中SocketAppender后面会讲到):
log4cplus.appender.append_1=log4cplus::ConsoleAppender
log4cplus.appender.append_2=log4cplus::FileAppender
log4cplus.appender.append_3=log4cplus::RollingFileAppender
log4cplus.appender.append_4=log4cplus::DailyRollingFileAppender
log4cplus.appender.append_4=log4cplus::SocketAppender
(2)设置Filter:
包括选择过滤器和设置过滤条件,可选择的过滤器包括:LogLevelMatchFilter、LogLevelRangeFilter、
和StringMatchFilter:
对LogLevelMatchFilter来说,过滤条件包括LogLevelToMatch和AcceptOnMatch(true|false), 只有
当log信息的LogLevel值与LogLevelToMatch相同,且AcceptOnMatch为true时才会匹配。
LogLevelRangeFilter来说,过滤条件包括LogLevelMin、LogLevelMax和AcceptOnMatch,只有当log信息
的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为true时才会匹配。
对StringMatchFilter来说,过滤条件包括StringToMatch和AcceptOnMatch,只有当log信息的LogLevel值
与StringToMatch对应的LogLevel值与相同, 且AcceptOnMatch为true时会匹配。
过滤条件处理机制类似于IPTABLE的Responsibility chain,(即先deny、再allow)不过执行顺序刚好相反,
后写的条件会被先执行,比如:
log4cplus.appender.append_1.filters.1=log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.append_1.filters.1.LogLevelToMatch=TRACE
log4cplus.appender.append_1.filters.1.AcceptOnMatch=true
#log4cplus.appender.append_1.filters.2=log4cplus::spi::DenyAllFilter
会首先执行filters.2的过滤条件,关闭所有过滤器,然后执行filters.1,仅匹配TRACE信息。
(3)设置Layout
可以选择不设置、TTCCLayout、或PatternLayout
如果不设置,会输出简单格式的log信息。
设置TTCCLayout如下所示:
log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout
设置PatternLayout如下所示:
log4cplus.appender.append_1.layout=log4cplus::PatternLayout
log4cplus.appender.append_1.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p - %m%n
2.logger的配置语法
包括rootLogger和non-root logger。
对于rootLogger来说:
log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...
对于non-root logger来说:
log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...
脚本方式使用起来非常简单,只要首先加载配置即可(urconfig.properties是自行定义的配置文件):
PropertyConfigurator::doConfigure("urconfig.properties");
下面我们通过例子体会一下log4cplus强大的基于脚本过滤log信息的功能。
〖例8〗
/*
* urconfig.properties
*/
log4cplus.rootLogger=TRACE, ALL_MSGS, TRACE_MSGS, DEBUG_INFO_MSGS, FATAL_MSGS
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.ALL_MSGS.File=all_msgs.log
log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.TRACE_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.TRACE_MSGS.File=trace_msgs.log
log4cplus.appender.TRACE_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.TRACE_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.TRACE_MSGS.filters.1.LogLevelToMatch=TRACE
log4cplus.appender.TRACE_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.TRACE_MSGS.filters.2=log4cplus::spi::DenyAllFilter
log4cplus.appender.DEBUG_INFO_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.DEBUG_INFO_MSGS.File=debug_info_msgs.log
log4cplus.appender.DEBUG_INFO_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.DEBUG_INFO_MSGS.filters.1=log4cplus::spi::LogLevelRangeFilter
log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMin=DEBUG
log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMax=INFO
log4cplus.appender.DEBUG_INFO_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.DEBUG_INFO_MSGS.filters.2=log4cplus::spi::DenyAllFilter
log4cplus.appender.FATAL_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.FATAL_MSGS.File=fatal_msgs.log
log4cplus.appender.FATAL_MSGS.layout=log4cplus::TTCCLayout
log4cplus.appender.FATAL_MSGS.filters.1=log4cplus::spi::StringMatchFilter
log4cplus.appender.FATAL_MSGS.filters.1.StringToMatch=FATAL
log4cplus.appender.FATAL_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.FATAL_MSGS.filters.2=log4cplus::spi::DenyAllFilter
/*
* main.cpp
*/
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/helpers/stringhelper.h>
using namespace log4cplus;
static Logger logger = Logger::getInstance("log");
void printDebug()
{
LOG4CPLUS_TRACE_METHOD(logger, "::printDebug()");
LOG4CPLUS_DEBUG(logger, "This is a DEBUG message");
LOG4CPLUS_INFO(logger, "This is a INFO message");
LOG4CPLUS_WARN(logger, "This is a WARN message");
LOG4CPLUS_ERROR(logger, "This is a ERROR message");
LOG4CPLUS_FATAL(logger, "This is a FATAL message");
}
int main()
{
Logger root = Logger::getRoot();
PropertyConfigurator::doConfigure("urconfig.properties");
printDebug();
return 0;
}
运行结果:
1. all_msgs.log
10-17-04 14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug()
10-17-04 14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message
10-17-04 14:55:25,873 [1075298944] INFO log <> - This is a INFO message
10-17-04 14:55:25,873 [1075298944] WARN log <> - This is a WARN message
10-17-04 14:55:25,874 [1075298944] ERROR log <> - This is a ERROR message
10-17-04 14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message
10-17-04 14:55:25,875 [1075298944] TRACE log <> - EXIT: ::printDebug()
2. trace_msgs.log
10-17-04 14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug()
10-17-04 14:55:25,875 [1075298944] TRACE log <> - EXIT: ::printDebug()
3. debug_info_msgs.log
10-17-04 14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message
10-17-04 14:55:25,873 [1075298944] INFO log <> - This is a INFO message
4. fatal_msgs.log
10-17-04 14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message
本部分详细介绍了如何有选择地控制log信息的输出,最后一部分我们将介绍一下多线程、
和C/S模式下该如何操作,顺便提一下NDC的概念。
相关推荐
`log4cplus`是一个专门为C++设计的开源日志系统,它提供了一种高效、灵活的方式来管理应用程序中的日志输出。本篇文章将详细介绍`log4cplus`及其封装类`log`,并探讨如何在项目中有效利用这些工具。 首先,`log4c...
log4cplus是C++编写的开源的日志系统,功能非常全面,用到自己开发的工程中会比较专业的,:),本文介绍了log4cplus基本概念,以及如何安装,配置。 ### 简介 ### log4cplus是C++编写的开源的日志系统,前身是java...
log4cplus是C++编写的开源日志系统,前身是java编写的log4j日志系统。log4cplus具有线程安全、灵活、以及多粒度控制的特点,通过将信息划分优先级使其可以面向程序调试、运行、测试、和维护等全生命周期; 你可以...
Log4CPlus是一个基于C++的日志记录框架,它的设计灵感来源于Java的Log4j,因此在命名上也带有明显的Log4j痕迹。这个开源项目为C++开发者提供了一个强大、灵活且高效的日志处理解决方案,能够帮助程序员方便地记录...
4. **编写日志信息**:使用logger对象的`LOG4CPLUS_TRACE`, `LOG4CPLUS_DEBUG`, `LOG4CPLUS_INFO`, `LOG4CPLUS_WARN`, `LOG4CPLUS_ERROR`和`LOG4CPLUS_FATAL`宏记录不同级别的日志。 5. **运行时配置**:log4cplus...
Log4cplus是一个开源的日志库,其主要特点是简单易用、可配置性强,支持多种输出方式,包括文件、控制台、网络等。它允许用户通过简单的API设置日志级别,控制输出信息的详细程度,同时提供了线程安全的多进程、多...
`log4cplus`是一个开源的日志记录库,它为C++程序员提供了类似Java的log4j功能。这个项目的核心目标是实现一个高效、灵活的日志系统,支持多线程、多进程环境,并能够方便地定制日志输出格式和存储位置。本工程即...
**log4cplus** 是一个基于C++的开源日志框架,它的设计灵感来源于Java社区中的log4j,旨在提供一种高效、灵活且易于使用的日志记录解决方案。这个框架允许开发者在C++程序中方便地记录调试信息,帮助追踪代码问题、...
`log4cplus`是一个用C++编写的开源日志系统,它为开发者提供了一套强大的日志记录工具,便于在各种环境下管理和追踪应用程序的运行状态。该库的设计灵感来源于Java的`log4j`,并将其特性移植到了C++环境中,旨在实现...
log4cplus开源库为C++开发者提供了强大且灵活的日志记录解决方案,其Ver1.1.1版本在稳定性、性能和易用性上都有优秀表现。通过配置文件和API,开发者能够轻松管理日志,提升开发效率,确保系统的可维护性和稳定性。...
1. **初始化**:在程序启动时,需要调用Log4Cplus的初始化函数,配置日志系统的基本参数,如日志文件路径、日志级别等。 2. **创建Logger**:根据需要创建Logger实例,通常按照模块或者功能划分。 3. **设置日志...
**log4cplus** 是一个基于C++的日志记录库,它受到了Java的log4j项目的启发,旨在为C++开发者提供一个功能强大、高效且易于使用的日志记录框架。这个开源项目的主要目标是简化应用程序的日志管理,帮助开发者轻松地...
标题"log4cplus-1.2.1 vs2017编译"指的是一项工程,其中将开源的日志库log4cplus版本1.2.1与Microsoft Visual Studio 2017 (简称VS2017或vc15)相结合,进行了编译工作,目的是为了在32位环境下生成可直接使用的二...
log4cplus 是一个 C++ 编写的开源日志系统,前身是 Java 编写的 log4j 日志系统。log4cplus 具有线程安全、灵活、以及多粒度控制的特点,通过将信息划分优先级使其可以面向程序调试、运行、测试、和维护等全生命周期...
log4cplus是一款开源的日志框架,它为C++开发人员提供了类似于log4j的功能,使得开发者可以方便地记录日志信息。log4cplus支持多种平台,包括Windows、Linux等操作系统,并且提供了丰富的API接口来满足不同场景下的...
log4cplus是一款专为C++设计的开源日志框架,其前身源自Java语言的log4j日志系统。log4cplus以其强大的线程安全性、灵活性及多级别的日志控制能力著称,非常适合应用于程序的开发、调试、测试乃至后期的维护阶段。它...
log4cplus是一个开源的日志记录框架,它提供了灵活的配置机制,支持多种日志输出方式,包括文件、控制台、网络等。它具备多线程支持,性能高效,且易于集成到现有项目中。其命名中的“4”表示与log4j的紧密关系,“c...
Log4Cplus 是一个流行的开源日志记录框架,专为C++设计,提供类似Java的Log4j的功能。它使得在C++应用程序中进行日志记录变得简单而高效。这个开发包是64位版本,包括了Debug和Release模式下的库文件以及DLL运行库,...
Log4cplus是一个开源的日志库,其设计灵感来源于Java的Log4j,它提供了类似于Log4j的功能,包括灵活的日志级别控制、多种输出方式(如文件、控制台、数据库等)、自定义布局格式等。Log4cplus适用于C++开发者,可以...
Log4cplus是一款专为C++设计的开源日志系统,其前身是基于Java的log4j系统。这款工具由Tad E. Smith开发,并受到Apache Software License的保护。Log4cplus提供了强大的日志记录功能,包括但不限于: - **线程安全...