C++ log4cplus 日志库使用

19 篇文章 3 订阅

一、介绍

1.1 log4cplus 介绍

log4cplus是一个易于使用的C++日志API,它提供了对日志管理和配置的线程安全、灵活和任意粒度的控制。它是以Java log4j API为模型的。

1.2 参考资料

1.3 工程示例

  • AsyncAppender 和 RollingFileAppender
    log4cplus.rootLogger=TRACE, DEBUG_MSGS, ERROR_MSGS
    
    log4cplus.appender.DEBUG_MSGS=log4cplus::AsyncAppender
    log4cplus.appender.DEBUG_MSGS.Appender=log4cplus::RollingFileAppender
    log4cplus.appender.DEBUG_MSGS.Appender.MaxFileSize=10MB
    log4cplus.appender.DEBUG_MSGS.Appender.MaxBackupIndex=2
    log4cplus.appender.DEBUG_MSGS.Appender.RollOverAfterClose=true
    log4cplus.appender.DEBUG_MSGS.Appender.Append=true
    log4cplus.appender.DEBUG_MSGS.Appender.File=/app/v2x_service/v2x_proxy/debug.log
    log4cplus.appender.DEBUG_MSGS.Appender.layout=log4cplus::PatternLayout
    log4cplus.appender.DEBUG_MSGS.Appender.layout.DateFormat=%Y-%m-%d %H:%M:%S.%q
    log4cplus.appender.DEBUG_MSGS.Appender.layout.ConversionPattern=%D{%Y-%m-%d %H:%M:%S.%q} [%p] [%b:%L] %m%n 
    log4cplus.appender.DEBUG_MSGS.Appender.filters.1=log4cplus::spi::LogLevelRangeFilter
    log4cplus.appender.DEBUG_MSGS.Appender.filters.1.LogLevelMin=DEBUG
    log4cplus.appender.DEBUG_MSGS.Appender.filters.1.LogLevelMax=DEBUG
    log4cplus.appender.DEBUG_MSGS.Appender.filters.1.AcceptOnMatch=true
    log4cplus.appender.DEBUG_MSGS.Appender.filters.2=log4cplus::spi::DenyAllFilter
    
    log4cplus.appender.ERROR_MSGS=log4cplus::AsyncAppender
    log4cplus.appender.ERROR_MSGS.Appender=log4cplus::RollingFileAppender
    log4cplus.appender.ERROR_MSGS.Appender.MaxFileSize=10MB
    log4cplus.appender.ERROR_MSGS.Appender.MaxBackupIndex=2
    log4cplus.appender.ERROR_MSGS.Appender.RollOverAfterClose=true
    log4cplus.appender.ERROR_MSGS.Appender.Append=true
    log4cplus.appender.ERROR_MSGS.Appender.File=/app/v2x_service/v2x_proxy/error.log
    log4cplus.appender.ERROR_MSGS.Appender.layout=log4cplus::PatternLayout
    log4cplus.appender.ERROR_MSGS.Appender.layout.DateFormat=%Y-%m-%d %H:%M:%S.%q
    log4cplus.appender.ERROR_MSGS.Appender.layout.ConversionPattern=%D{%Y-%m-%d %H:%M:%S.%q} [%p] [%b:%L] %m%n 
    log4cplus.appender.ERROR_MSGS.Appender.filters.1=log4cplus::spi::LogLevelRangeFilter
    log4cplus.appender.ERROR_MSGS.Appender.filters.1.LogLevelMin=ERROR
    log4cplus.appender.ERROR_MSGS.Appender.filters.1.LogLevelMax=ERROR
    log4cplus.appender.ERROR_MSGS.Appender.filters.1.AcceptOnMatch=true
    log4cplus.appender.ERROR_MSGS.Appender.filters.2=log4cplus::spi::DenyAllFilter
    
    

二、配置文件

2.1 概要

配置文件中总共包含4部分内容:Logger、Appender、layout、filter,逻辑关系如下。

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

举个例子

#声明一个Logger
#SetverLog = Logger名称
#ALL = 日志输出的级别
#ALL_MSGS = Appender对象,可以有多个对象
log4cplus.logger.SetverLog = ALL, ALL_MSGS, ALL_MSGS_1
 
#实例化Appender对象,即输出方式:输出到控制台还是文件
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender  
log4cplus.appender.ALL_MSGS.MaxFileSize=100MB
log4cplus.appender.ALL_MSGS.MaxBackupIndex=10
log4cplus.appender.ALL_MSGS.CreateDirs = true
log4cplus.appender.ALL_MSGS.ImmediateFlush = true
log4cplus.appender.ALL_MSGS.File=ServerLog/test.log
 
#日志文件的打印格式
log4cplus.appender.ALL_MSGS.layout=log4cplus::PatternLayout
log4cplus.appender.ALL_MSGS.layout.ConversionPattern=[%-5p %d{%y-%m-%d %H:%M:%S}] [%l]
 
#日志输出的过滤器
log4cplus.appender.ALL_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.DEBUG_MSGS.filters.1.LogLevelToMatch=DEBUG
log4cplus.appender.DEBUG_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.DEBUG_MSGS.filters.2=log4cplus::spi::DenyAllFilter

2.2 Logger的定义和调用

  • rootLogger 根日志器:同一份配置,可指定1个
  • logger 日志器:同一份配置,可指定多个

2.2.1 rootLogger

配置

#ALL = 日志输出的级别
#RemoteServer, STDOUT, ALL_MSGS, 均为Appender对象
log4cplus.rootLogger=ALL, RemoteServer, STDOUT, ALL_MSGS

调用

log4cplus::initialize();	
log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("配置文件名称"));
log4cplus::Logger logger = log4cplus::Logger::getRoot(); 

2.2.2 logger

配置

log4cplus.logger.ClientLog = ALL, RemoteServer, STDOUT, ALL_MSGS
# ALL 日志级别
# RemoteServer, STDOUT, ALL_MSGS:多个appender

调用

log4cplus::initialize();	
log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("配置文件名称"));
log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("ClientLog"));

2.3 日志的级别和输出

2.3.1 日志级别

在这里插入图片描述

  • 可在 loglevel.cxx 查看

2.3.2 输出函数

在这里插入图片描述
代码

#include <log4cplus/consoleappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/logger.h>
#include <log4cplus/ndc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/thread/threads.h>
#include <log4cplus/helpers/sleep.h>
#include <log4cplus/streams.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/tracelogger.h>
#include <exception>
#include <iostream>
#include <string>
#include <log4cplus/configurator.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus::thread;
 
int
main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("config.txt"));
	Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("TestOutputMethod"));
	
	LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("111"));
	LOG4CPLUS_TRACE_STR(logger, LOG4CPLUS_TEXT("222"));
	LOG4CPLUS_TRACE_FMT(logger, LOG4CPLUS_TEXT("%d%d%d"), 3, 3, 3);
	{
		LOG4CPLUS_TRACE_METHOD(logger, LOG4CPLUS_TEXT("TestFunc"));
		LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("444"));
		LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("555"));
		LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("666"));
	}	
	LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("777"));
 
	log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestOutputMethod = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::FileAppender
 
# FileAppender 类属性
log4cplus.appender.Test.Threshold = ALL
log4cplus.appender.Test.File = Test/FileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.BufferSize = 1024
log4cplus.appender.Test.CreateDirs = true
log4cplus.appender.Test.Append = false

结果

TRACE - 111
TRACE - 222
TRACE - 333
TRACE - ENTER: TestFunc
TRACE - 444
TRACE - 555
TRACE - 666
TRACE - EXIT:  TestFunc
TRACE - 777

2.4 Appender

常用Appender类型

  • AsyncAppender:异步 Appender,异步日志记录功能,提高性能,需要包装其他 Appender使用。

  • ConsoleAppender:将日志信息输出到控制台或标准错误流。支持设置是否立即刷新输出流以及指定输出的 locale。

  • FileAppender:将日志信息输出到文件中。可以设置文件名、打开模式、是否立即刷新缓冲区等属性。

    • RollingFileAppender:按文件大小日志文件,在文件达到一定大小时进行滚动,创建新的日志文件,并保留一定数量的旧日志文件。
    • DailyRollingFileAppender:按日期记录日志文件,
    • 注意:貌似没办法两个结合,比如又按天数记录,又指定文件大小。
  • SocketAppender:通过网络将日志信息发送到远程服务器。

  • NullAppender:不输出任何日志信息,用于关闭日志记录或作为开发调试的占位符

2.4.1 Appender 家族

在这里插入图片描述
官网API当前支持:
在这里插入图片描述

2.4.2 Appender 类

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

2.4.3 AsyncAppender 类

在这里插入图片描述
代码

#include <log4cplus/consoleappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/logger.h>
#include <log4cplus/ndc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/thread/threads.h>
#include <log4cplus/helpers/sleep.h>
#include <log4cplus/streams.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/tracelogger.h>
#include <exception>
#include <iostream>
#include <string>
#include <log4cplus/configurator.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus::thread;
 
 
#define MILLIS_TO_NANOS 1000
#define NUM_THREADS 4
#define NUM_LOOPS 10
 
class SlowObject {
public:
	SlowObject()
		: logger(Logger::getInstance(LOG4CPLUS_TEXT("TestAsyncAppender")))
	{
		LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Init SlowObject"));
	}
 
	void doSomething()
	{
		LOG4CPLUS_TRACE_METHOD(logger, LOG4CPLUS_TEXT("In SlowObject::doSomething()"));
 
		{
			// 并没有测试出这个互斥有什么作用
			log4cplus::thread::MutexGuard guard(mutex);
 
			sleep(0, 75 * MILLIS_TO_NANOS);
			LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Actually doing 111111111..."));
			LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Actually doing 222222222..."));
			LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Actually doing 333333333..."));
			LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Actually doing 444444444..."));
		}
		log4cplus::thread::yield();
	}
 
	~SlowObject()
	{
		LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Out SlowObject"));
	}
 
private:
	log4cplus::thread::Mutex mutex;
	Logger logger;
};
 
 
class TestThread : public AbstractThread {
public:
	TestThread(tstring const & n, SlowObject * so)
		: name(n)
		, slow(so)
		, logger(Logger::getInstance(LOG4CPLUS_TEXT("TestAsyncAppender")))
	{ }
 
	virtual void run();
 
private:
	tstring name;
	SlowObject * slow;
	Logger logger;
};
 
 
int
main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("config.txt"));
	try
	{
		auto_ptr<SlowObject> slowObject(new SlowObject());
		Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("TestAsyncAppender"));
 
		log4cplus::helpers::SharedObjectPtr<TestThread> threads[NUM_THREADS];
		int i = 0;
		for (i = 0; i<NUM_THREADS; ++i) {
			tostringstream s;
			s << "Thread-" << i;
			threads[i] = new TestThread(s.str(), slowObject.get());
		}
 
		for (i = 0; i<NUM_THREADS; ++i) {
			threads[i]->start();
		}
		LOG4CPLUS_DEBUG(logger, "All Threads started...");
 
		for (i = 0; i<NUM_THREADS; ++i) {
			while (threads[i]->isRunning()) {
				sleep(0, 200 * MILLIS_TO_NANOS);
			}
		}
		LOG4CPLUS_INFO(logger, "Exiting main()...");
	}
	catch (std::exception &e) {
		LOG4CPLUS_FATAL(Logger::getRoot(), "main()- Exception occured: " << e.what());
	}
	catch (...) {
		LOG4CPLUS_FATAL(Logger::getRoot(), "main()- Exception occured");
	}
 
 
	log4cplus::Logger::shutdown();
	return 0;
}
 
 
void
TestThread::run()
{
	try {
		LOG4CPLUS_WARN(logger, name + LOG4CPLUS_TEXT(" TestThread.run()- Starting..."));
 
		NDC& ndc = getNDC();
		NDCContextCreator _first_ndc(name);
 
		LOG4CPLUS_DEBUG(logger, "Entering Run()...");
		for (int i = 0; i<NUM_LOOPS; ++i) {
			NDCContextCreator _ndc(LOG4CPLUS_TEXT("loop"));
			slow->doSomething();
		}
 
		LOG4CPLUS_DEBUG(logger, "Exiting run()...");
 
		ndc.remove();
	}
	catch (std::exception const & e) {
		LOG4CPLUS_FATAL(logger, "TestThread.run()- Exception occurred: " << e.what());
	}
	catch (...) {
		LOG4CPLUS_FATAL(logger, "TestThread.run()- Exception occurred!!");
	}
	LOG4CPLUS_WARN(logger, name << " TestThread.run()- Finished");
} // end "run"

配置文件

log4cplus.logger.TestAsyncAppender = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::AsyncAppender
 
# AsyncAppender 类属性
log4cplus.appender.Test.QueueLimit = 1000
log4cplus.appender.Test.Appender = log4cplus::FileAppender
 
# FileAppender 类属性
log4cplus.appender.Test.Appender.Threshold = ALL
log4cplus.appender.Test.Appender.File = Test/FileAppenderLog.txt
log4cplus.appender.Test.Appender.ImmediateFlush = false
log4cplus.appender.Test.Appender.BufferSize = 1024
log4cplus.appender.Test.Appender.CreateDirs = true
log4cplus.appender.Test.Appender.Append = false
log4cplus.appender.Test.Appender.layout = log4cplus::TTCCLayout

结果

71 [6608] INFO TestAsyncAppender <> - Init SlowObject
73 [10984] WARN TestAsyncAppender <> - Thread-0 TestThread.run()- Starting...
73 [6608] DEBUG TestAsyncAppender <> - All Threads started...
74 [3936] WARN TestAsyncAppender <> - Thread-1 TestThread.run()- Starting...
75 [10984] DEBUG TestAsyncAppender <Thread-0> - Entering Run()...
75 [3928] WARN TestAsyncAppender <> - Thread-3 TestThread.run()- Starting...
74 [4160] WARN TestAsyncAppender <> - Thread-2 TestThread.run()- Starting...
75 [3936] DEBUG TestAsyncAppender <Thread-1> - Entering Run()...
75 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
76 [3928] DEBUG TestAsyncAppender <Thread-3> - Entering Run()...
76 [4160] DEBUG TestAsyncAppender <Thread-2> - Entering Run()...
76 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
76 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
76 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
76 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
76 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
77 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
77 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
77 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
77 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
77 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
77 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
78 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
78 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
78 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
78 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
78 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
78 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
78 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
79 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
79 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
79 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
79 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
79 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
79 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
79 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
80 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
80 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
80 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
80 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
80 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
80 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
80 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
80 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
81 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
81 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
81 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
81 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
81 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
81 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
82 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
82 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
82 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
82 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
82 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
82 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
82 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
83 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
83 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
83 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
83 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
83 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
83 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
83 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
84 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
84 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
84 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
84 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
84 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
84 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
85 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
85 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
85 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
85 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
85 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
85 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
85 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
86 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
86 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
86 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
86 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
86 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
86 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
87 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
87 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
87 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
87 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
87 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
87 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
87 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
88 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
88 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
88 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
88 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
88 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
88 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
88 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
88 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
89 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
89 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
89 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
89 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
89 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
89 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
89 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
89 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
90 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
90 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
90 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
90 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
90 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
90 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
91 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
91 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
91 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
91 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
91 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
91 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
91 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
92 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
92 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
92 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
92 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
92 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
92 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
92 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
93 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
93 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
93 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
93 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
93 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
93 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
93 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
93 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
94 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
94 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
94 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
94 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
94 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
94 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
95 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
95 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
95 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
95 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
95 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
95 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
95 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
95 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
96 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
96 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
96 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
96 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
96 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
96 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
96 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
96 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
97 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
97 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
97 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
97 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
97 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
97 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
97 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
97 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
98 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
98 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
98 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
98 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
98 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
98 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
98 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
98 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
99 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
99 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
99 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
99 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
99 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
99 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
99 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
100 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
100 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
100 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
100 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
100 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
100 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
100 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
101 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
101 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
101 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
101 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
101 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
101 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
101 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
101 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
102 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
102 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
102 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
102 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
102 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
102 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
102 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
102 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
103 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
103 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
103 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
103 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
103 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
103 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
103 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
104 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
104 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
104 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
104 [10984] TRACE TestAsyncAppender <Thread-0 loop> - ENTER: In SlowObject::doSomething()
104 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
104 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
104 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
105 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
105 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
105 [3936] TRACE TestAsyncAppender <Thread-1 loop> - ENTER: In SlowObject::doSomething()
105 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
105 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
105 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
105 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
105 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
106 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
106 [3928] TRACE TestAsyncAppender <Thread-3 loop> - ENTER: In SlowObject::doSomething()
106 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
106 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
106 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
106 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 111111111...
106 [4160] TRACE TestAsyncAppender <Thread-2 loop> - ENTER: In SlowObject::doSomething()
106 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 222222222...
107 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 333333333...
107 [10984] INFO TestAsyncAppender <Thread-0 loop> - Actually doing 444444444...
107 [10984] TRACE TestAsyncAppender <Thread-0 loop> - EXIT:  In SlowObject::doSomething()
107 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 111111111...
107 [10984] DEBUG TestAsyncAppender <Thread-0> - Exiting run()...
107 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 222222222...
107 [10984] WARN TestAsyncAppender <> - Thread-0 TestThread.run()- Finished
108 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 333333333...
108 [3936] INFO TestAsyncAppender <Thread-1 loop> - Actually doing 444444444...
109 [3936] TRACE TestAsyncAppender <Thread-1 loop> - EXIT:  In SlowObject::doSomething()
109 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 111111111...
109 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 222222222...
109 [3936] DEBUG TestAsyncAppender <Thread-1> - Exiting run()...
109 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 333333333...
109 [3936] WARN TestAsyncAppender <> - Thread-1 TestThread.run()- Finished
109 [3928] INFO TestAsyncAppender <Thread-3 loop> - Actually doing 444444444...
110 [3928] TRACE TestAsyncAppender <Thread-3 loop> - EXIT:  In SlowObject::doSomething()
110 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 111111111...
110 [3928] DEBUG TestAsyncAppender <Thread-3> - Exiting run()...
110 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 222222222...
110 [3928] WARN TestAsyncAppender <> - Thread-3 TestThread.run()- Finished
110 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 333333333...
111 [4160] INFO TestAsyncAppender <Thread-2 loop> - Actually doing 444444444...
111 [4160] TRACE TestAsyncAppender <Thread-2 loop> - EXIT:  In SlowObject::doSomething()
111 [4160] DEBUG TestAsyncAppender <Thread-2> - Exiting run()...
111 [4160] WARN TestAsyncAppender <> - Thread-2 TestThread.run()- Finished
112 [6608] INFO TestAsyncAppender <> - Exiting main()...
112 [6608] INFO TestAsyncAppender <> - Out SlowObject

2.4.4 FileAppenderBase 类

在这里插入图片描述

2.4.5 FileAppender 类

没有额外的附加属性。

#include <iostream>
#include <log4cplus/ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus/helpers/sleep.h>
#include <log4cplus/helpers/pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("config.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestFileAppender"));
	
	LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("TRACE-LOG-TEST"));
	LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
	LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
	LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
	LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
	LOG4CPLUS_FATAL(logger, LOG4CPLUS_TEXT("FATAL-LOG-TEST"));
 
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件:

log4cplus.logger.TestFileAppender = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::FileAppender
 
# Appender 类属性
log4cplus.appender.Test.Threshold = ALL
 
# FileAppenderBase 类属性
log4cplus.appender.Test.File = Test/FileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = true
log4cplus.appender.Test.Append = true
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.CreateDirs = true
 
# FileAppender 类属性
# 空

结果

TRACE - TRACE-LOG-TEST
DEBUG - DEBUG-LOG-TEST
INFO - INFO-LOG-TEST
WARN - WARN-LOG-TEST
ERROR - ERROR-LOG-TEST
FATAL - FATAL-LOG-TEST

2.4.6 RollingFileAppender 类

通过控制每个文件大小以及总文件数量控制日志的量
在这里插入图片描述
代码

#include <iostream>
#include <log4cplus/ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus/helpers/sleep.h>
#include <log4cplus/helpers/pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("config.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestRollingFileAppender"));
	
	for (int i = 0; i < 5000; i++)
	{
		LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("TRACE-LOG-TEST"));
		LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
		LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
		LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
		LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
		LOG4CPLUS_FATAL(logger, LOG4CPLUS_TEXT("FATAL-LOG-TEST"));
	}
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestRollingFileAppender = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::RollingFileAppender
 
# Appender 类属性
log4cplus.appender.Test.Threshold = ALL
 
# FileAppenderBase 类属性
log4cplus.appender.Test.File = Test/RollingFileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = true
log4cplus.appender.Test.Append = true
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.CreateDirs = true
 
# RollingFileAppender 类属性
log4cplus.appender.Test.MaxFileSize = 1kb
log4cplus.appender.Test.MaxBackupIndex = 3

结果
在这里插入图片描述
结果说明

MaxBackupIndex 是指最大的滚动备份数量,备份文件会以“文件名.n”的格式存在。举例MaxBackupIndex=3,则有三个备份文件。注意此处 RollingFileAppenderLog.txt 大小不为0, 备份文件大小最小是200kb。

2.4.7 DailyRollingFileAppender 类

在这里插入图片描述
代码

#include <iostream>
#include <log4cplus/ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus/helpers/sleep.h>
#include <log4cplus/helpers/pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("config.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestDailyRollingFileAppender"));
	
	//for (int i = 0; i < 5000; i++)
	{
		LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("TRACE-LOG-TEST"));
		LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
		LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
		LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
		LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
		LOG4CPLUS_FATAL(logger, LOG4CPLUS_TEXT("FATAL-LOG-TEST"));
	}
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestDailyRollingFileAppender = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::DailyRollingFileAppender
 
# Appender 类属性
log4cplus.appender.Test.Threshold = ALL
 
# FileAppenderBase 类属性
log4cplus.appender.Test.File = Test/DailyRollingFileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = true
log4cplus.appender.Test.Append = true
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.CreateDirs = true
 
# DailyRollingFileAppender 类属性
log4cplus.appender.Test.Schedule = DAILY
log4cplus.appender.Test.MaxBackupIndex = 3
log4cplus.appender.Test.RollOnClose = true
#log4cplus.appender.Test.DatePattern = 3

结果
在这里插入图片描述
结果说明

  • Schedule 是说明按天生成文件,新文件会以文件名.Schedule 的形式存在。
  • MaxBackupIndex 同 RollingFileAppender 的 MaxBackupIndex,只不过是按天刷新统计数量。
  • RollOnClose = true 则在每次关闭程序时 DailyRollingFileAppenderLog.txt 大小为0,区别于 RollingFileAppender 的滚动文件。
  • DatePattern 自定义滚动文件的日期格式,如果在上面配置文件最后增加 DatePattern 属性,输出文件名会改变。
log4cplus.logger.TestDailyRollingFileAppender = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::DailyRollingFileAppender
 
# Appender 类属性
log4cplus.appender.Test.Threshold = ALL
 
# FileAppenderBase 类属性
log4cplus.appender.Test.File = Test/DailyRollingFileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = true
log4cplus.appender.Test.Append = true
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.CreateDirs = true
 
# DailyRollingFileAppender 类属性
log4cplus.appender.Test.Schedule = DAILY
log4cplus.appender.Test.MaxBackupIndex = 3
log4cplus.appender.Test.RollOnClose = true
log4cplus.appender.Test.DatePattern = %Y k %m kk %d.TestDatePattern

在这里插入图片描述
注意:需要改变系统时间做测试~

2.4.8 SocketAppender 类

在这里插入图片描述
客户端

#include <iostream>
#include <log4cplus/ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus/helpers/sleep.h>
#include <log4cplus/helpers/pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("client_config"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("ClientLog"));
	for (int i = 0; i < 10; i++)
	{
		LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("TRACE-LOG-TEST ") << i);
	}
	log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.ClientLog = ALL, RemoteServer
 
log4cplus.appender.RemoteServer=log4cplus::SocketAppender
log4cplus.appender.RemoteServer.host=localhost
log4cplus.appender.RemoteServer.port=9000
log4cplus.appender.RemoteServer.ServerName=ThisIsServerName

服务端

#include <cstdlib>
#include <iostream>
#include <log4cplus/configurator.h>
#include <log4cplus/socketappender.h>
#include <log4cplus/helpers/socket.h>
#include <log4cplus/thread/threads.h>
#include <log4cplus/spi/loggingevent.h>
#include <log4cplus\helpers\pointer.h>
 
namespace loggingserver
{
 
	class ClientThread : public log4cplus::thread::AbstractThread
	{
	public:
		ClientThread(log4cplus::helpers::Socket clientsock)
			: clientsock(clientsock)
		{
			std::cout << "Received a client connection!!!!" << std::endl;
		}
 
		~ClientThread()
		{
			std::cout << "Client connection closed." << std::endl;
		}
 
		virtual void run();
 
	private:
		log4cplus::helpers::Socket clientsock;
	};
 
 
	void
	ClientThread::run()
	{
			while (1) {
				if (!clientsock.isOpen()) {
					return;
				}
				log4cplus::helpers::SocketBuffer msgSizeBuffer(sizeof(unsigned int));
				if (!clientsock.read(msgSizeBuffer)) {
					return;
				}
 
				unsigned int msgSize = msgSizeBuffer.readInt();
 
				log4cplus::helpers::SocketBuffer buffer(msgSize);
				if (!clientsock.read(buffer)) {
					return;
				}
 
				log4cplus::spi::InternalLoggingEvent event
					= log4cplus::helpers::readFromBuffer(buffer);
				
				log4cplus::tstring strLoggerName = event.getLoggerName();// strLoggerName = ClientLog
				log4cplus::tstring strLoggerNDC = event.getNDC();// strLoggerNDC = ThisIsServerName
 
				log4cplus::Logger logger
					= log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("SetverLog"));
				logger.callAppenders(event);
			}
		}
 
}
 
 
 
int
main(int argc, char** argv)
{
	int port = 9000;
	log4cplus::PropertyConfigurator config(LOG4CPLUS_C_STR_TO_TSTRING("server_config"));
	config.configure();
 
	log4cplus::helpers::ServerSocket serverSocket(port);
	if (!serverSocket.isOpen()) {
		std::cout << "Could not open server socket, maybe port "
			<< port << " is already in use." << std::endl;
		return 2;
	}
 
	while (1) {
		loggingserver::ClientThread *thr =
			new loggingserver::ClientThread(serverSocket.accept());
		thr->start();
	}
 
	return 0;
}
 

配置文件

log4cplus.logger.SetverLog = ALL, FileOut
 
log4cplus.appender.FileOut = log4cplus::FileAppender
log4cplus.appender.FileOut.File = D:\\FileAppenderLog.txt
log4cplus.appender.FileOut.ImmediateFlush = true
log4cplus.appender.FileOut.Append = true
log4cplus.appender.FileOut.ImmediateFlush = true
log4cplus.appender.FileOut.CreateDirs = true

输出

TRACE - TRACE-LOG-TEST 0
TRACE - TRACE-LOG-TEST 1
TRACE - TRACE-LOG-TEST 2
TRACE - TRACE-LOG-TEST 3
TRACE - TRACE-LOG-TEST 4
TRACE - TRACE-LOG-TEST 5
TRACE - TRACE-LOG-TEST 6
TRACE - TRACE-LOG-TEST 7
TRACE - TRACE-LOG-TEST 8
TRACE - TRACE-LOG-TEST 9

2.5 layout

在这里插入图片描述

  1. SimpleLayout
    • 描述:SimpleLayout 是一种最简单的日志格式化方式,它通常只包括日志级别和消息文本。这种布局设计得非常轻量级,适合那些不需要复杂格式化信息的场合(不包含时间戳等)。
    • 输出示例:[DEBUG] This is a debug message.
  2. PatternLayout
    • 最为灵活的 Layout 类型,允许用户通过模式字符串(Conversion Pattern)自定义日志的输出格式。模式字符串可以包含各种转换说明符,如日期时间、日志级别、线程名、日志消息等。
    • log4cplus::PatternLayout Class Reference
    • 转换说明符:
      %d:表示日期时间,可以自定义格式。
      %p:表示日志级别。
      %c:表示日志器的名称。
      %m:表示日志消息。
      %n:表示换行符。
      还有更多其他的转换说明符,如线程名、进程ID等。
    • 输出示例:[2023-04-05 14:23:45] [DEBUG] myapp - This is a debug message.
  3. TTCCLayout
    • 描述:TTCCLayout 的全称是 Time, Thread, Category, and Cost (Time in milliseconds), 它提供了一种详细的日志格式,通常用于需要完整上下文信息的场景。这种布局包含了时间戳、线程名、日志器名称以及日志消息。
    • 输出示例:2023-04-05 14:23:45,123 - myapp - [Thread 12345] - DEBUG - This is a debug message.

2.5.1 PatternLayout

在这里插入图片描述
代码

#include <iostream>
#include <log4cplus\ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus\helpers\sleep.h>
#include <log4cplus\helpers\pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("PatternLayout.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestPatternLayout"));
 
	NDCContextCreator _first_ndc(LOG4CPLUS_TEXT("This-is-Thread-Name"));
 
	LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
	LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
	LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
	LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
        
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestPatternLayout = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::FileAppender
log4cplus.appender.Test.File = Test/FileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = true
log4cplus.appender.Test.Append = true
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.CreateDirs = true
 
# layout类属性
log4cplus.appender.Test.layout = log4cplus::PatternLayout
log4cplus.appender.Test.layout.NDCMaxDepth = 5
log4cplus.appender.Test.layout.ConversionPattern = %d{%Y-%m-%d} %F-%L-%M <%x> %m %n

结果

2020-04-27 ..\..\tests\appender_test\main.cxx-23-int __cdecl main(void) <This-is-Thread-Name> DEBUG-LOG-TEST 
2020-04-27 ..\..\tests\appender_test\main.cxx-24-int __cdecl main(void) <This-is-Thread-Name> INFO-LOG-TEST 
2020-04-27 ..\..\tests\appender_test\main.cxx-25-int __cdecl main(void) <This-is-Thread-Name> WARN-LOG-TEST 
2020-04-27 ..\..\tests\appender_test\main.cxx-26-int __cdecl main(void) <This-is-Thread-Name> ERROR-LOG-TEST 

2.5.2 SimpleLayout

代码

#include <iostream>
#include <log4cplus\ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus\helpers\sleep.h>
#include <log4cplus\helpers\pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("SimpleLayout.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestSimpleLayout"));
	
	NDCContextCreator _first_ndc(LOG4CPLUS_TEXT("This-is-Thread-Name"));
 
	LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
	LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
	LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
	LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
 
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestSimpleLayout = ALL, Test
log4cplus.appender.Test = log4cplus::FileAppender
log4cplus.appender.Test.File = Test.log
log4cplus.appender.Test.layout = log4cplus::SimpleLayout

输出结果

DEBUG - DEBUG-LOG-TEST
INFO - INFO-LOG-TEST
WARN - WARN-LOG-TEST
ERROR - ERROR-LOG-TEST

2.5.3 TTCCLayout

在这里插入图片描述
代码

#include <iostream>
#include <log4cplus\ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus\helpers\sleep.h>
#include <log4cplus\helpers\pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("TTCCLayout.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestTTCCLayout"));	
 
	NDCContextCreator _first_ndc(LOG4CPLUS_TEXT("This-is-Thread-Name"));
 
	LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
	LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
	LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
	LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
 
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestTTCCLayout = ALL, Test
log4cplus.appender.Test = log4cplus::FileAppender
log4cplus.appender.Test.File = Test.log
log4cplus.appender.Test.layout = log4cplus::TTCCLayout
log4cplus.appender.Test.layout.DateFormat = %Y-%m@%d

输出结果

  • 格式:时间 线程ID Logger名称 线程名称 日志内容
2020-04@19 [8844] DEBUG TestSimpleLayout <This-is-Thread-Name> - DEBUG-LOG-TEST
2020-04@19 [8844] INFO TestSimpleLayout <This-is-Thread-Name> - INFO-LOG-TEST
2020-04@19 [8844] WARN TestSimpleLayout <This-is-Thread-Name> - WARN-LOG-TEST
2020-04@19 [8844] ERROR TestSimpleLayout <This-is-Thread-Name> - ERROR-LOG-TEST

2.5.4 转换标识符

在这里插入图片描述
关于日期时间输出的转换标志符可用在三个地方

  1. DailyRollingFileAppender 中的 DatePattern,格式为 %Y-%m-%d
  2. TTCCLayout 中的 DateFormat,格式为 %Y-%m-%d
  3. PatternLayout 中的 ConversionPattern,格式为 %d{%Y-%m-%d}

在这里插入图片描述

2.6 filter

在这里插入图片描述

  • LogLevelMatchFilter:根据特定的日志级别进行过滤
    • 过滤条件包括LogLevelToMatch和AcceptOnMatch(true|false), 只有当日志的LogLevel值与LogLevelToMatch相同,且AcceptOnMatch为true时才会匹配。
  • LogLevelRangeFilter:根据根据日志级别的范围进行过滤。
    • 过滤条件包括LogLevelMin、LogLevelMax和AcceptOnMatch,只有当日志的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为true时才会匹配。
  • StringMatchFilter:根据日志内容是否包含特定字符串进行过滤。
    • 过滤条件包括StringToMatch和AcceptOnMatch,只有当日志包含StringToMatch字符串 且AcceptOnMatch为true时会匹配。
  • DenyAllFilter:过滤掉所有消息。

过滤条件处理机制类似于Linux中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信息。

2.6.1 LogLevelRangeFilter

根据根据日志级别的范围进行过滤,只有当日志的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为true时才会匹配。
在这里插入图片描述
代码

#include <iostream>
#include <log4cplus\ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus\helpers\sleep.h>
#include <log4cplus\helpers\pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("Filter.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestFilter"));
 
	//NDCContextCreator _first_ndc(LOG4CPLUS_TEXT("This-is-Thread-Name"));
 
	LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("TRACE-LOG-TEST"));
	LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
	LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
	LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
	LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
	LOG4CPLUS_FATAL(logger, LOG4CPLUS_TEXT("FATAL-LOG-TEST"));
 
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestFilter = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::FileAppender
log4cplus.appender.Test.File = Test/FileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = true
log4cplus.appender.Test.Append = false
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.CreateDirs = true
 
# Layout类属性
log4cplus.appender.Test.layout = log4cplus::SimpleLayout
 
# Filter属性
log4cplus.appender.Test.filters.1 = log4cplus::spi::LogLevelRangeFilter
log4cplus.appender.Test.filters.1.LogLevelMin = TRACE
log4cplus.appender.Test.filters.1.LogLevelMax = INFO
log4cplus.appender.Test.filters.1.AcceptOnMatch = true
log4cplus.appender.Test.filters.2 = log4cplus::spi::DenyAllFilter

结果

TRACE - TRACE-LOG-TEST
DEBUG - DEBUG-LOG-TEST
INFO - INFO-LOG-TEST

2.6.2 LogLevelMatchFilter

根据特定的日志级别进行过滤,只有当日志的LogLevel值与LogLevelToMatch相同,且AcceptOnMatch为true时才会匹配。

在这里插入图片描述
代码

#include <iostream>
#include <log4cplus\ndc.h>
#include <log4cplus/logger.h>
#include <log4cplus\helpers\sleep.h>
#include <log4cplus\helpers\pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
 
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
 
int main()
{
	log4cplus::initialize();
	log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("Filter.txt"));
	log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TestFilter"));
 
	//NDCContextCreator _first_ndc(LOG4CPLUS_TEXT("This-is-Thread-Name"));
 
	LOG4CPLUS_TRACE(logger, LOG4CPLUS_TEXT("TRACE-LOG-TEST"));
	LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG-LOG-TEST"));
	LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO-LOG-TEST"));
	LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN-LOG-TEST"));
	LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR-LOG-TEST"));
	LOG4CPLUS_FATAL(logger, LOG4CPLUS_TEXT("FATAL-LOG-TEST"));
 
        log4cplus::Logger::shutdown();
	return 0;
}

配置文件

log4cplus.logger.TestFilter = ALL, Test
 
# 创建Appender对象
log4cplus.appender.Test = log4cplus::FileAppender
log4cplus.appender.Test.File = Test/FileAppenderLog.txt
log4cplus.appender.Test.ImmediateFlush = true
log4cplus.appender.Test.Append = false
log4cplus.appender.Test.ImmediateFlush = false
log4cplus.appender.Test.CreateDirs = true
 
# Layout类属性
log4cplus.appender.Test.layout = log4cplus::SimpleLayout
 
# Filter属性
log4cplus.appender.Test.filters.1 = log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.Test.filters.1.LogLevelToMatch = TRACE
log4cplus.appender.Test.filters.1.AcceptOnMatch = true
log4cplus.appender.Test.filters.2 = log4cplus::spi::DenyAllFilter

结果

TRACE - TRACE-LOG-TEST

三、使用

2.1 log4cplus 编译和交叉编译

log4cplus是一个易于使用的C++11日志API,它提供了对日志管理和配置的线程安全、灵活和任意粒度的控制。它是以Java log4j API为模型的。

2.1.1 源码下载

2.1.2 配置编译参数、编译安装

  • x64 本机编译

    ./configure --prefix=$PWD/install_x64 --enable-static
    make -j
    make install
    
  • imx6q 交叉编译 (./configure -h 查看手册)

    export CC="arm-fslc-linux-gnueabi-gcc  -march=armv7-a -mthumb -mfpu=neon -mfloat-abi=hard --sysroot=/opt/fslc-x11/2.4.4/sysroots/armv7at2hf-neon-fslc-linux-gnueabi"
    export CXX="arm-fslc-linux-gnueabi-g++  -march=armv7-a -mthumb -mfpu=neon -mfloat-abi=hard --sysroot=/opt/fslc-x11/2.4.4/sysroots/armv7at2hf-neon-fslc-linux-gnueabi"
    ./configure --prefix=$PWD/install_imx6q --host=arm-fslc-linux-gnueabi --enable-static
    make -j
    make install
    

2.1.3 使用

  • 配置文件
  • API 接口(可不用配置文件)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值