Log4cplus Study Notes (2)

Source: Internet
Author: User

Log4cplus is excellent in many aspects, but it is uncomfortable to use it in some places. I'm not happy with it until I continue to talk about it.
I will mention it a little and continue to introduce the knowledge about threads and sockets.

### Some improvements ###
1. The implementation mechanism of user-defined loglevel is not open enough
In article 5, I have introduced how to implement custom loglevel. To achieve better results, I even need to change log4cplus.
Source code. :(
2. The mechanism for generating logger objects can be improved.
When using logger, I often need to operate the same logger in different files and functions. Although log4cplus implements tree storage and
The logger generated by the name does not take full advantage of this feature to ensure the uniqueness of the logger object corresponding to the same name. For example, the following code:
    ... ...
   
    Logger logger1 = Logger::getInstance("test");
    Logger logger2 = Logger::getInstance("test");
    Logger * plogger1 = &logger1;
    Logger * plogger2 = &logger2;
STD: cout <"plogger1:" <plogger1 <STD: Endl <"plogger2:" <plogger2 <STD: Endl;

......


Running result:
plogger1: 0xbfffe5a0
plogger2: 0xbfffe580

It can be seen from the results that it is clearly the same logger, but each call will generate a logger copy, although the result is correct (because
The storage and operations are separated), but the resources are a little waste. I checked the log4cplus code and can actually be implemented as follows (schematic
):
#include <iostream></iostream>
#include <string></string>
#include
/* forward declaration */
class Logger;
class LoggerContainer
{
public:
    ~LoggerContainer();
    Logger * getinstance(const std::string & strLogger);
private:
    typedef std::map<:string,> LoggerMap;
    LoggerMap loggerPtrs;
};
class Logger
{
public:
     Logger() {std::cout << "ctor of Logger " << std::endl; }
    ~Logger() {std::cout << "dtor of Logger " << std::endl; }
    static Logger * getInstance( const std::string & strLogger)
    {
        static LoggerContainer defaultLoggerContainer;
        return defaultLoggerContainer.getinstance(strLogger);
    }
};
LoggerContainer::~LoggerContainer()
{
    /* release all ptr in LoggerMap */
    LoggerMap::iterator itr = loggerPtrs.begin();
    for( ; itr != loggerPtrs.end(); ++itr )
 {
     delete (*itr).second;
 }
}
Logger * LoggerContainer::getinstance(const std::string & strLogger)
{
   LoggerMap::iterator itr = loggerPtrs.find(strLogger);
   if(itr != loggerPtrs.end())
   {
       /* logger exist, just return it */
       return (*itr).second;
   }
   else
   {
       /* return a new logger */
       Logger * plogger = new Logger();
       loggerPtrs.insert(std::make_pair(strLogger, plogger));
       return plogger;
   }
}
int main()
{
    Logger * plogger1 = Logger::getInstance("test");
    Logger * plogger2 = Logger::getInstance("test");
    std::cout << "plogger1: " << plogger1 << std::endl << "plogger2: " << plogger2 << std::endl;
    return 0;
}

Running result:
ctor of Logger
plogger1: 0x804fc30
plogger2: 0x804fc30
dtor of Logger
The loggercontainer here is equivalent to the hierarchy class in log4cplus. The result shows that the same name can be used to obtain the same
Logger instance.

There are also some minor issues, such as the parameter input sequence of rollingfileappender and dailyrollingfileappender, which can be adjusted to the unified mode.
Wait.
This section describes how log4cplus processes and sockets are implemented.

(7)

After a short familiarization process, log4cplus has been successfully applied to my project, and the effect is good. :) besides
In addition to the function, the following describes the usage of threads and sockets provided by log4cplus.

### NDC ###
First, let's take a look at the embedded diagnostic context (nested diagnostic context) in log4cplus, that is, NDC. For the log system,
When there may be more than one input source, but only one output, it is often necessary to distinguish the source of the message to be output, such as the server processing from different
This judgment is required when the client sends messages. NDC can mark (STAMP) the information displayed in the staggered manner to make the identification work look like
It's easier. This mark is unique to the thread and uses the local storage mechanism of the thread.
Data, or TSD ). After reading the source code, the definition is as follows:
linux pthread
#   define LOG4CPLUS_THREAD_LOCAL_TYPE pthread_key_t*
#   define LOG4CPLUS_THREAD_LOCAL_INIT ::log4cplus::thread::createPthreadKey()
#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) pthread_getspecific(*key)
#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) pthread_setspecific(*key, value)
#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) pthread_key_delete(*key)
win32
#   define LOG4CPLUS_THREAD_LOCAL_TYPE DWORD
#   define LOG4CPLUS_THREAD_LOCAL_INIT TlsAlloc()
#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) TlsGetValue(key)
#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) /
       TlsSetValue(key, static_cast<lpvoid></lpvoid>(value))
#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) TlsFree(key)

It is relatively simple to use. In a thread:
    NDC& ndc = log4cplus::getNDC();
    ndc.push("ur ndc string");
    LOG4CPLUS_DEBUG(logger, "this is a NDC test");
......

NDC. Pop ();

......

Log4cplus_debug (logger, "There shocould be no NDC ...");
NDC. Remove ();

When the output format (layout) is set to ttcclayout, the output is as follows:
10-21-04 21:32:58, [3392] DEBUG test <ur string="" ndc=""></ur> - this is a NDC test
10-21-04 21:32:58, [3392] DEBUG test <> - There should be no NDC...
You can also use NDC (% x) in the Custom output format, for example:
    ... ...
   
    std::string pattern = "NDC:[%x]  - %m %n";
    std::auto_ptr<layout></layout> _layout(new PatternLayout(pattern));
......

Log4cplus_debug (_ logger, "This is the first log message ...")
NDC & NDC = log4cplus: getndc ();
NDC. Push ("ur NDC string ");
Log4cplus_warn (_ logger, "this is the second log message ...")
NDC. Pop ();
NDC. Remove ();

......

The output is as follows:
NDC:[]  - This is the FIRST log message...
NDC:[ur ndc string]  - This is the SECOND log message...

Another simpler method is to directly use ndccontextcreator in the thread:
Ndccontextcreator _ first_ndc ("ur NDC string ");
Log4cplus_debug (logger, "This is a NDC test ")

You do not need to explicitly call push/pop. In case of an exception, you can ensure that the call of push and pop matches.

### Thread ###
The thread is a by-product in log4cplus and only implements the most basic functions. It is also very simple to use.
Reload the run function in the derived class:
class TestThread : public AbstractThread
{
public:
    virtual void run();
};
void TestThread::run()
{
    /* do sth. */
    ... ...
}
The log4cplus thread does not consider synchronization or deadlocks and has mutex. The small functions that implement thread switching are quite chic:
void log4cplus::thread::yield()
{
#if defined(LOG4CPLUS_USE_PTHREADS)
    ::sched_yield();
#elif defined(LOG4CPLUS_USE_WIN32_THREADS)
    ::Sleep(0);
#endif
}

### Socket ###
Sockets are also a by-product in log4cplus. In namespace log4cplus: helpers, logs are recorded in C/S mode.
1. What the client needs to do:
/* Define a etappender hook */
Sharedappenderptr _ append (New socketappender (host, 8888, "servername "));
/* Add _ append to logger */
Logger: getroot (). addappender (_ append );
/* The socketappender type does not require layout. You can directly call the macro to send the information to loggerserver */
Log4cplus_info (logger: getroot (), "this is a test :")

[Note] the macro call actually calls socketappender: append, which has a data transmission Convention, that is, sending
The total length of a subsequent data, and then the actual data is sent:
    ... ...
    SocketBuffer buffer = convertToBuffer(event, serverName);
    SocketBuffer msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE);
    msgBuffer.appendSize_t(buffer.getSize());
    msgBuffer.appendBuffer(buffer);
  
    ... ...

2. What the server-side program needs to do:
/* Define a serversocket */
Serversocket (port );
/* Call the accept function to create a new socket to connect to the client */
Socket sock = serversocket. Accept ();

Then you can use the sock for data read/write, as shown in the following figure:
SocketBuffer msgSizeBuffer(sizeof(unsigned int));
if(!clientsock.read(msgSizeBuffer))
{
    return;
}
unsigned int msgSize = msgSizeBuffer.readInt();
SocketBuffer buffer(msgSize);
if(!clientsock.read(buffer))
{
    return;
}
To display the read data normally, you need to convert the contents stored in socketbuffer to internalloggingevent format:
spi::InternalLoggingEvent event = readFromBuffer(buffer);
Then output:
Logger logger = logger: getinstance (event. getloggername ());
Logger. callappenders (event );
[Note] read/write is implemented in blocking mode, which means that the call will not be returned until the number of received or sent messages is satisfied.

 

Three log4cplus routines

Http://log4cplus.sourceforge.net/codeexamples.html
Three built-in routines

Hello world example
# Include <log4cplus/logger. h>
# Include <log4cplus/aggregator. h>
# Include <iomanip>

Using namespace log4cplus;

Int
Main ()
{
Basicconfigurator config;
Config. Configure ();

Logger logger = logger: getinstance ("Main ");
Log4cplus_warn (logger, "Hello, world! ");
Return 0;
}
Ostream example (show how to write logging messages .)
# Include <log4cplus/logger. h>
# Include <log4cplus/aggregator. h>
# Include <iomanip>

Using namespace STD;
Using namespace log4cplus;

Int
Main ()
{
Basicconfigurator config;
Config. Configure ();
Logger logger = logger: getinstance ("logger ");

Log4cplus_warn (logger, "this is"
<"A reall"
<"Y long message." <Endl
<"Just testing it out" <Endl
<"What do you think? ")
Log4cplus_warn (logger, "This is a bool:" <true)
Log4cplus_warn (logger, "This is a char:" <'X ')
Log4cplus_warn (logger, "this is a short:" <(short)-100)
Log4cplus_warn (logger, "This is a unsigned short:" <(unsigned short) 100)
Log4cplus_warn (logger, "This is a INT:" <(INT) 1000)
Log4cplus_warn (logger, "This is a unsigned INT:" <(unsigned INT) 1000)
Log4cplus_warn (logger, "this is a long (HEX):" Log4cplus_warn (logger, "This is a unsigned long :"
<(Unsigned long) 100000000)
Log4cplus_warn (logger, "This is a float:" <(float) 1.2345)
Log4cplus_warn (logger, "This is a double :"
<Setprecision (15)
<(Double) 1.2345234234)
Log4cplus_warn (logger, "this is a long double :"
<Setprecision (15)
<(Long Double) 123452342342.342)

Return 0;
}

Loglevel example (shows how log messages can be filtered at runtime by adjusting the loglevel .)
# Include <log4cplus/logger. h>
# Include <log4cplus/aggregator. h>
# Include <iostream>

Using namespace STD;
Using namespace log4cplus;

Logger logger = logger: getinstance ("Main ");

Void printmessages ()
{
Log4cplus_trace (logger, "printmessages ()");
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 ()
{
Basicconfigurator config;
Config. Configure ();

Logger. setloglevel (trace_log_level );
Cout <"*** calling printmessages () with trace set: ***" <Endl;
Printmessages ();

Logger. setloglevel (debug_log_level );
Cout <"/n *** calling printmessages () with debug set: ***" <Endl;
Printmessages ();

Logger. setloglevel (info_log_level );
Cout <"/n *** calling printmessages () with info set: ***" <Endl;
Printmessages ();

Logger. setloglevel (warn_log_level );
Cout <"/n *** calling printmessages () with warn set: ***" <Endl;
Printmessages ();

Logger. setloglevel (error_log_level );
Cout <"/n *** calling printmessages () with error set: ***" <Endl;
Printmessages ();

Logger. setloglevel (fatal_log_level );
Cout <"/n *** calling printmessages () with fatal set: ***" <Endl;
Printmessages ();

Return 0;
}

Log4cplus Study Notes (2)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.