C + + realizes log function: log4cplus (VS2017+Win10)

Posted by scottd on Thu, 03 Feb 2022 00:51:06 +0100

1,log4cplus

https://sourceforge.net/projects/log4cplus/
https://github.com/log4cplus/log4cplus

  • log4cplus is a simple to use C++ logging API providing thread-safe, flexible, and arbitrarily granular control over log management and configuration. It is modelled after the Java log4j API.
  • log4cplus is an easy-to-use C + + logging API. log4cplus is flexible, powerful, easy to use and multi-threaded. By prioritizing the information, it can be oriented to the whole life cycle of program debugging, operation, testing, and maintenance; You can choose to output information to screens, files, or even remote servers; Regularly backup logs by specifying policies, and so on.
  • Last Update: 2021-08-09
  • Last Version: 2.0.7 ( 2021-08-09 )

1.1 basic elements

  • Layout: layout, which controls the format of the output message. log4cplus provides three types of Layouts,
    They are SimpleLayout, PatternLayout, and TTCCLayout.
  • Appender: a connector that works closely with the layout to output messages in a specific format to the attached device terminal (such as console and file).
  • Logger: logger, an entity that saves and tracks the changes of object log information. When you need to record an object, you need to generate a logger.

1.2 use steps

  1. Instantiate an appender object
  2. Instantiate a layout object
  3. Attach the layout object to the appender object
  4. Instantiate a logger object and call the static function: log4cplus::Logger::getInstance("logger_name")
  5. Attach the appender object to the logger object. If this step is omitted, the standard output (screen) appender object will be bound to the logger
  6. Set the priority of the logger. If this step is omitted, various limited level messages will be recorded

1.3 test examples

The following example is based on log4cplus2 0.7 for writing and testing.

Example 1: the simplest example.

#include "log4cplus/logger.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/loglevel.h"
#include <log4cplus/loggingmacros.h>
#include <log4cplus/initializer.h>
#include <log4cplus/configurator.h>
#include <iomanip>

using namespace std;
using namespace log4cplus;

int main()
{
	// Initialization and deinitialization.
	log4cplus::Initializer initializer;

	BasicConfigurator config;
	config.configure();

	Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main"));

	LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("Hello, World!"));
	return 0;
}

Example 2: ConsoleAppender.

#include <log4cplus/logger.h>
#include <log4cplus/initializer.h>
#include <log4cplus/consoleappender.h>
#include <log4cplus/loggingmacros.h>
#include <iomanip>

using namespace log4cplus;

int main()
{
	log4cplus::Initializer initializer;

	/* step 1: Instantiate an appender object */
	SharedAppenderPtr _append(new ConsoleAppender());
	_append->setName("append test");

	/* step 4: Instantiate a logger object */
	Logger _logger = Logger::getInstance("test");

	/* step 5: Attach the appender object to the logger  */
	_logger.addAppender(_append);

	/* step 6: Set a priority for the logger  */
	_logger.setLogLevel(ALL_LOG_LEVEL);

	/* log activity */
	LOG4CPLUS_TRACE(_logger, "This is" << " just a t" << "est." << std::endl);
	LOG4CPLUS_DEBUG(_logger, "Enteringloop#");

	return 0;
}

Example 3: ConsoleApp + simplelayout.

#include "log4cplus/logger.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/loglevel.h"
#include <log4cplus/loggingmacros.h>
#include <log4cplus/initializer.h>
#include <iomanip>

using namespace std;
using namespace log4cplus;

int main()
{
	log4cplus::Initializer initializer;
	 //helpers::LogLog::getLogLog()->setInternalDebugging(true);

	/* step 1:  Instantiate an appender object */
	helpers::SharedObjectPtr<Appender>  _append(new ConsoleAppender());

	_append->setName("append for  test");

	/* step 2:  Instantiate a layout object */
	/* step 3: Attach  the layout object to the appender */
	_append->setLayout(std::unique_ptr<Layout>(new SimpleLayout()));

	/* step 4:  Instantiate a logger object */
	Logger _logger = Logger::getInstance("test");

	/* step 5: Attach  the appender object to the logger  */
	_logger.addAppender(_append);

	/* log activity */
	LOG4CPLUS_DEBUG(_logger, "This  is the simple formatted log message...");
	LOG4CPLUS_DEBUG(_logger, "This is a bool: " << true);
	LOG4CPLUS_INFO(_logger, "This is a char: " << 'x');
	LOG4CPLUS_WARN(_logger, "The following message is empty:");

	return 0;
}

Example 4: ConsoleAppender+PatternLayout.

#include "log4cplus/logger.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/loglevel.h"
#include <log4cplus/loggingmacros.h>
#include <log4cplus/initializer.h>
#include <log4cplus/configurator.h>
#include <iomanip>

using namespace std;
using namespace log4cplus;

int main()
{
	// Initialization and deinitialization.
	log4cplus::Initializer initializer;

	//Appender
	helpers::SharedObjectPtr<Appender> _append(new ConsoleAppender(false, true));
	_append->setName(LOG4CPLUS_TEXT("Console"));

	//Layout
	std::string pattern = "%D{%m/%d/%y %H:%M:%S,%q} [%-5t] [%-5p] - %m%n";
	_append->setLayout(std::auto_ptr<Layout>(new PatternLayout(pattern)));

	//Logger
	Logger test = Logger::getInstance(LOG4CPLUS_TEXT("test"));
	test.addAppender(_append);

	for (int i = 0; i < 10; ++i)
	{
		LOG4CPLUS_DEBUG(test, "Entering loop #" << i);
	}

	// set log level
	test.setLogLevel(DEBUG_LOG_LEVEL);

	Logger test2 = Logger::getInstance(LOG4CPLUS_TEXT("test.subtest"));
	for (int i = 0; i < 5; ++i)
	{
		LOG4CPLUS_ERROR(test2, "click count ~" << i+100);
	}

	return 0;
}

Example 5: consoleprovider + ttcclayout.

#include <log4cplus/logger.h>
#include <log4cplus/initializer.h>
#include <log4cplus/consoleappender.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/property.h>
#include <iomanip>

using namespace log4cplus;

int main()
{
	log4cplus::Initializer initializer;

	/* step 1: Instantiate an appender object */
	SharedAppenderPtr _append(new ConsoleAppender());
	_append->setName("append test");

	/* step 2: Instantiate a layout object */
	/* step 3: Attach the layout object to the appender */
	tistringstream propsStream(
		LOG4CPLUS_TEXT("DateFormat=%m/%d/%y %H:%M:%S,%q\n")
		LOG4CPLUS_TEXT("CategoryPrefixing=true")
		LOG4CPLUS_TEXT("ThreadPrinting=true")
		LOG4CPLUS_TEXT("ContextPrinting=true")
		LOG4CPLUS_TEXT("Use_gmtime=false\n"));
	helpers::Properties props(propsStream);
	_append->setLayout(std::auto_ptr<Layout>(new TTCCLayout(props)));
	
	/* step 4: Instantiate a logger object */
	Logger _logger = Logger::getInstance("test");

	/* step 5: Attach the appender object to the logger  */
	_logger.addAppender(_append);

	/* log activity */
	LOG4CPLUS_TRACE(_logger, "This is" << " just a t" << "est." << std::endl);
	LOG4CPLUS_DEBUG(_logger, "Enteringloop#");

	return 0;
}

Example 6: FileAppender.

#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loglevel.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/initializer.h>
#include <log4cplus/fileappender.h>

using namespace std;
using namespace log4cplus;

int main()
{
	// Initialization and deinitialization.
	log4cplus::Initializer initializer;

	/*step1:Instantiateanappenderobject*/
	SharedAppenderPtr _append(new FileAppender("Test.log"));
	_append->setName("file_log_test");

	/*step4: Instantiate an logger object*/
	Logger _logger = Logger::getInstance("test.subtestof_filelog");

	/*step5: Attach the appender object to the logger*/
	_logger.addAppender(_append);

	/*log activity*/
	for (int i = 0; i < 5; ++i) {
		LOG4CPLUS_DEBUG(_logger, "Enteringloop#" << i << "Endline#");
	}

	return 0;
}

Example 7: FileAppender+PatternLayout.

#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loglevel.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/initializer.h>
#include <log4cplus/fileappender.h>

using namespace std;
using namespace log4cplus;

int main()
{
	// Initialization and deinitialization.
	log4cplus::Initializer initializer;

	/* step 1: Instantiate an appender object */
	SharedAppenderPtr _append(new FileAppender("Test.log"));
	_append->setName("file_log_test");

	/* step 2: Instantiate a layout object */
	/* step 3: Attach the layout object to the appender */
	std::string pattern = "%D{%m/%d/%y %H:%M:%S,%q} [%-5t] [%-5p] - %m%n";
	_append->setLayout(std::auto_ptr<Layout>(new PatternLayout(pattern)));

	/* step 4:  Instantiate a logger object */
	Logger _logger = Logger::getInstance("test.subtestof_filelog");

	/* step 5: Attach the appender object to the  logger  */
	_logger.addAppender(_append);

	/* step 6: Set a priority for the logger  */
	_logger.setLogLevel(ALL_LOG_LEVEL);

	/*log activity*/
	for (int i = 0; i < 5; ++i) {
		//NDCContextCreator _context("loop");
		LOG4CPLUS_DEBUG(_logger, "Enteringloop#" << i << "Endline#");
	}

	return 0;
}

Example 8: RollingFileAppender+PatternLayout.

#include <log4cplus/logger.h>
#include <log4cplus/initializer.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/property.h>
#include <iomanip>

using namespace log4cplus;

int main()
{
	log4cplus::Initializer initializer;

	/* step 1: Instantiate an appender object */
	SharedAppenderPtr  _append(new RollingFileAppender("Test.log", 300 * 1024, 5));
	_append->setName("append test");

	/* step 2: Instantiate a layout object */
	/* step 3: Attach the layout object to the appender */
	std::string pattern = "%D{%m/%d/%y %H:%M:%S,%q} [%-5t] [%-5p] - %m%n";
	_append->setLayout(std::auto_ptr<Layout>(new PatternLayout(pattern)));
	
	/* step 4: Instantiate a logger object */
	Logger test = Logger::getInstance("test");

	/* step 5: Attach the appender object to the logger  */
	test.addAppender(_append);

	/* log activity */
	for (int i = 0; i < 100000; ++i) {
		LOG4CPLUS_DEBUG(test, "Entering  loop #" << i);
	}

	return 0;
}

Example 9: DailyRollingFileAppender+PatternLayout.

#include <log4cplus/logger.h>
#include <log4cplus/initializer.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/ndc.h>
#include <iomanip>

using namespace log4cplus;

int main()
{
	log4cplus::Initializer initializer;

	/* step 1: Instantiate an appender object */
	SharedAppenderPtr  _append(new  DailyRollingFileAppender("Test.log", MINUTELY, true, 5));
	_append->setName("append test");

	/* step 2: Instantiate a layout object */
	/* step 3: Attach the layout object to the appender */
	std::string pattern = "%D{%m/%d/%y %H:%M:%S,%q} [%-5t] [%-5p] - %m%n";
	_append->setLayout(std::auto_ptr<Layout>(new PatternLayout(pattern)));
	
	/* step 4: Instantiate a logger object */
	Logger test = Logger::getInstance("test");

	/* step 5: Attach the appender object to the logger  */
	test.addAppender(_append);

	/* log activity */
	for (int i = 0; i < 12*3; ++i) {
		//NDCContextCreator _context("loop");
		std::this_thread::sleep_for(std::chrono::seconds(5));
		LOG4CPLUS_DEBUG(test, "Entering  loop #" << i);
	}

	return 0;
}

Example 10: PropertyConfigurator

  • myconfig.properties:
log4cplus.rootLogger=TRACE, ALL_MSGS, TRACE_MSGS, DEBUG_INFO_MSGS, FATAL_MSGS

####################################################################
log4cplus.appender.logConsole=log4cplus::ConsoleAppender
log4cplus.appender.logConsole.Encoding=utf-8
log4cplus.appender.logConsole.layout=log4cplus::PatternLayout
log4cplus.appender.logConsole.layout.ConversionPattern=[%D{%Y-%m-%d %H:%M:%S}] %-5p %m %n

####################################################################
log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.Encoding=utf-8
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
log4cplus.appender.STDOUT.layout.ConversionPattern=%D{[%Y-%m-%d %H:%M:%S.%q]} [%-5p] [%c{2}] - %m [%l]%n

####################################################################
#Appender output location types include: file output setting log append to the end of the file
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender
#Set output log path
log4cplus.appender.ALL_MSGS.File=./log/all_msgs.log
log4cplus.appender.ALL_MSGS.CreateDirs=true
#Set log file size
log4cplus.appender.ALL_MSGS.MaxFileSize=1024KB
#Set the maximum number of generated logs
log4cplus.appender.ALL_MSGS.MaxBackupIndex=20
#The log output format is a pattern layout device with lexical analysis function
log4cplus.appender.ALL_MSGS.layout=log4cplus::PatternLayout
log4cplus.appender.ALL_MSGS.layout.ConversionPattern=@@@[%d %d{%Z %Q}][pthread_id:%t][%l][%-5p][%c{2}] - %m%n 
#log4cplus.appender.ALL_MSGS.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p - %m%n

####################################################################
log4cplus.appender.TRACE_MSGS=log4cplus::RollingFileAppender
log4cplus.appender.TRACE_MSGS.File=./log/trace_msgs.log
log4cplus.appender.TRACE_MSGS.CreateDirs=true
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=./log/debug_info_msgs.log
log4cplus.appender.DEBUG_INFO_MSGS.CreateDirs=true
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::TimeBasedRollingFileAppender
log4cplus.appender.FATAL_MSGS.FilenamePattern=./log/fatal_msgs.%d{yyyyMMdd}.log
log4cplus.appender.FATAL_MSGS.Schedule=DAILY
log4cplus.appender.FATAL_MSGS.MaxHistory=365

log4cplus.appender.FATAL_MSGS.Append=true
log4cplus.appender.FATAL_MSGS.RollOnClose=false
log4cplus.appender.FATAL_MSGS.CreateDirs=true

#Set log file size
log4cplus.appender.FATAL_MSGS.MaxFileSize=10MB
log4cplus.appender.FATAL_MSGS.MaxBackupIndex=5
log4cplus.appender.FATAL_MSGS.Encoding=utf-8

log4cplus.appender.FATAL_MSGS.layout=log4cplus::PatternLayout
log4cplus.appender.FATAL_MSGS.layout.ConversionPattern=[%D{%Y-%m-%d %H:%M:%S}] %-5p %m %n	

#Matching the same log level, only INFO logs are entered into this file
log4cplus.appender.FATAL_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.FATAL_MSGS.filters.1.LogLevelToMatch=FATAL
log4cplus.appender.FATAL_MSGS.filters.1.AcceptOnMatch=true
log4cplus.appender.FATAL_MSGS.filters.2=log4cplus::spi::DenyAllFilter

####################################################################
log4cplus.appender.RemoteServer=log4cplus::SocketAppender
log4cplus.appender.RemoteServer.host=192.168.1.130
log4cplus.appender.RemoteServer.port=9000

log4cplus.appender.RemoteServer2=log4cplus::SocketAppender
log4cplus.appender.RemoteServer2.host=192.168.1.131
log4cplus.appender.RemoteServer2.port=9001

  • main.cxx:
#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.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("myconfig.properties");
	printDebug();

	return 0;
}

Example 11: SocketAppender

  • Server side server:
#include <iostream>

#include <log4cplus/config.h>
#include <log4cplus/configurator.h>
#include <log4cplus/consoleappender.h>
#include <log4cplus/socketappender.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/socket.h>
#include <log4cplus/thread/threads.h>
#include <log4cplus/spi/loggerimpl.h>
#include <log4cplus/spi/loggingevent.h>

#ifdef _DEBUG
#pragma comment(lib, "log4cplusD.lib")
#else
#pragma comment(lib, "log4cplus.lib")
#endif

using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus::thread;

namespace loggingserver
{
	class ClientThread : public AbstractThread
	{
	public:

		ClientThread(Socket clientsock) : _clientsock(std::move(clientsock)) {
			cout << "Received a client connection!" << endl;
		}

		~ClientThread() {
			cout << "Client  connection closed." << endl;
		}

		virtual void run()
		{
			while (1) {
				if (!_clientsock.isOpen()) {
					return;
				}

				SocketBuffer msgSizeBuffer(sizeof(unsigned int));
				if (!_clientsock.read(msgSizeBuffer)) {
					return;
				}

				unsigned int msgSize = msgSizeBuffer.readInt();
				SocketBuffer buffer(msgSize);
				if (!_clientsock.read(buffer)) {
					return;
				}

				spi::InternalLoggingEvent event = readFromBuffer(buffer);
				Logger logger = Logger::getInstance(event.getLoggerName());
				logger.callAppenders(event);

				cout << "getLoggerName: " << event.getLoggerName() ;
				cout << ", getLogLevel: " << event.getLogLevel();
				cout << ", getMessage: " << event.getMessage()  << endl;
			}

		}

	private:
		Socket _clientsock;
	};
}

int main(int argc, char** argv)
{
	/*if (argc < 3) {
		cout << "Usage: port  config_file" << endl;
		return 1;
	}

	int port = atoi(argv[1]);
	tstring configFile = LOG4CPLUS_C_STR_TO_TSTRING(argv[2]);
	*/
	int port = 9998;
	tstring configFile = LOG4CPLUS_C_STR_TO_TSTRING("myconfig.properties");

	PropertyConfigurator config(configFile);
	config.configure();

	ServerSocket serverSocket(port);

	while (1) {
		loggingserver::ClientThread* thr = new loggingserver::ClientThread(serverSocket.accept());
		thr->start();
	}

	return 0;
}
  • client:
#include <log4cplus/log4cplus.h>
#include <iomanip>

using namespace std;
using namespace log4cplus;

int main(int argc, char **argv)
{
    log4cplus::Initializer initializer;

    std::this_thread::sleep_for (std::chrono::seconds (1));
    tstring serverName = (argc > 1
        ? LOG4CPLUS_C_STR_TO_TSTRING(argv[1]) : tstring());
    tstring host = LOG4CPLUS_TEXT("localhost");
    SharedAppenderPtr append_1(new SocketAppender(host, 9998, serverName));
    append_1->setName( LOG4CPLUS_TEXT("First") );
    Logger::getRoot().addAppender(append_1);

    Logger root = Logger::getRoot();
    Logger test = Logger::getInstance( LOG4CPLUS_TEXT("socket.test") );

    LOG4CPLUS_DEBUG(root,
                    "This is"
                    << " a reall"
                    << "y long message." << endl
                    << "Just testing it out" << endl
                    << "What do you think?");
    test.setLogLevel(NOT_SET_LOG_LEVEL);
    LOG4CPLUS_DEBUG(test, "This is a bool: " << true);
    LOG4CPLUS_INFO(test, "This is a char: " << 'x');
    LOG4CPLUS_INFO(test, "This is a short: " << static_cast<short>(-100));
    LOG4CPLUS_INFO(test, "This is a unsigned short: "
        << static_cast<unsigned short>(100));
    std::this_thread::sleep_for (std::chrono::microseconds (500));
    LOG4CPLUS_INFO(test, "This is a int: " << 1000);
    LOG4CPLUS_INFO(test, "This is a unsigned int: " << 1000u);
    LOG4CPLUS_INFO(test, "This is a long(hex): " << hex << 100000000l);
    LOG4CPLUS_INFO(test, "This is a unsigned long: " << 100000000ul);
    LOG4CPLUS_WARN(test, "This is a float: " << 1.2345f);
    LOG4CPLUS_ERROR(test,
                    "This is a double: "
                    << setprecision(15)
                    << 1.2345234234);
    LOG4CPLUS_FATAL(test,
                    "This is a long double: "
                    << setprecision(15)
                    << 123452342342.342L);


    return 0;
}

Screenshot of server-side operation results:

follow-up

If you think these words are a little useful, you can praise the author; ╮( ̄▽ ̄)╭
If you feel that the author doesn't write very well / / / (ㄒ o ㄒ) / /, leave a message in the comments and the author will continue to improve. o_O???
Thank you guys (´▽ ') ノ (´▽ `) っ!!!

Topics: C++ log VS2017