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
- Instantiate an appender object
- Instantiate a layout object
- Attach the layout object to the appender object
- Instantiate a logger object and call the static function: log4cplus::Logger::getInstance("logger_name")
- 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
- 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 (´▽ ') ノ (´▽ `) っ!!!