]> gitweb.hamatoma.de Git - crepublib/commitdiff
ReMemoryAppender, ReSlaveAppender, prefixChar in logging
authorhama <hama@siduction.net>
Sun, 8 Mar 2015 12:13:30 +0000 (13:13 +0100)
committerhama <hama@siduction.net>
Sun, 8 Mar 2015 12:13:30 +0000 (13:13 +0100)
base/ReAppenders.cpp
base/ReAppenders.hpp
base/ReLogger.cpp
base/ReLogger.hpp
base/rebase.hpp
cunit/cuReLogger.cpp
cunit/testall.cpp
net/ReTCP.cpp
net/ReTCP.hpp

index b0862ba9fcb4e6bc09d8f42664a187d64bb0bc78..a7c5ba8f4dbb37cb2a31b37da38ed7481eaa42f3 100644 (file)
@@ -24,6 +24,24 @@ ReMemoryAppender::ReMemoryAppender(int maxLines) :
 }
 ReMemoryAppender::~ReMemoryAppender(){
 }
+
+/**
+ * Joins the stored messages to one string.
+ *
+ * @param buffer       IN/OUT the result buffer
+ * @param append       <code>true</code>the buffer will not truncated before storage
+ * @return                     <code>buffer</code> (for chaining)
+ */
+ReByteBuffer& ReMemoryAppender::join(ReByteBuffer& buffer, bool append){
+       ReByteBuffer current;
+       if (! append)
+               buffer.setLength(0);
+       for (int ix = count() - 1; ix >= 0; ix--){
+               get(ix, current);
+               buffer.append(current).appendChar('\n');
+       }
+       return buffer;
+}
 /**
  * Stores a logging message.
  *
@@ -32,10 +50,38 @@ ReMemoryAppender::~ReMemoryAppender(){
  */
 void ReMemoryAppender::say(ReLogger* logger, const char* message){
        int theCount = count();
-       if (theCount > m_maxLines)
+       if (theCount >= m_maxLines)
                remove(theCount - 1);
        // we store in reverse order:
        add(0, message != NULL ? message : logger->asCString());
 }
 
-
+/**
+ * Constructor.
+ *
+ * @param masterLogger the central logger which really does the work
+ * @param charPrefix   '\0' or a character which marks each line of the log
+ *                                             written with this appender. It makes it possible
+ *                                             to distinct the threads in the log
+ */
+ReSlaveAppender::ReSlaveAppender(ReLogger* masterLogger, char charPrefix) :
+       m_masterLogger(masterLogger),
+       m_charPrefix(charPrefix) {
+}
+/**
+ * Destructor.
+ */
+ReSlaveAppender::~ReSlaveAppender(){
+}
+/**
+ * Writes the message to the master logger.
+ *
+ * @param logger       the caller
+ * @param message      the logging message to store
+ */
+void ReSlaveAppender::say(ReLogger* logger, const char* message){
+       ReByteBuffer buffer(logger->standardPrefix(m_charPrefix));
+       buffer.append(message);
+       m_masterLogger->say(logger->currentMode(),
+               logger->currentLocation(), buffer.str());
+}
index 212a3e6496fe6d6f08000b6e79c8b9914a67d6f6..7c65df28a6df797f3115860e93f8e409dd649d4b 100644 (file)
@@ -16,6 +16,9 @@
 
 /**
  * Implements an appender which stores the logging messages.
+ *
+ * The lines are stored in reverse order (the line with index 0 is the last written line):
+ * This makes removing of the last message more efficient: no packing is necessary.
  */
 class ReMemoryAppender: public ReAppender, public ReSeqArray {
 public:
@@ -23,8 +26,31 @@ public:
        ~ReMemoryAppender();
 public:
        virtual void say(ReLogger* logger, const char* message);
+       ReByteBuffer& join(ReByteBuffer& buffer, bool append = false);
 protected:
        int m_maxLines;
 };
 
+/**
+ * This appender writes the messages to another logger.
+ *
+ * This is useful in multithreaded applications: There is one "normal logger"
+ * in the main thread and each other thread have its own logger with a
+ * <code>ReSlaveAppender</code> which write to the main logger.
+ *
+ * Reason: Because of the architecture of the argument handling
+ * (<code>say().arg().end()</code> it is not possible to protect the argument
+ * preparation in a thread safe manner.
+ */
+class ReSlaveAppender : public ReAppender {
+public:
+       ReSlaveAppender(ReLogger* masterLogger, char charPrefix = '\0');
+       virtual ~ReSlaveAppender();
+public:
+public:
+       virtual void say(ReLogger* logger, const char* message);
+private:
+       ReLogger* m_masterLogger;
+       char m_charPrefix;
+};
 #endif /* BASE_REAPPENDERS_HPP_ */
index eaf997f3a7aa4d8bec46d4f3ce07445d11c6d539..99a15033fbaa6d54396ae4e7efabb2c95420f927 100644 (file)
@@ -120,7 +120,7 @@ ReStreamAppender::~ReStreamAppender() {
  * @param message              The message to write.
  */
 void ReStreamAppender::say(ReLogger* logger, const char* message) {
-       const char* prefix = logger->getStandardPrefix();
+       const char* prefix = logger->standardPrefix();
        if (m_stream != NULL) {
                fputs(prefix, m_stream);
                if (message != NULL)
@@ -262,7 +262,10 @@ ReLogger::ReLogger(bool isGlobal) :
            m_location(0),
            m_stdConsoleAppender(NULL),
            m_stdFileAppender(NULL),
-           m_locationOfOpenSayF(0) {
+           m_locationOfOpenSayF(0),
+           m_mutex(),
+           m_charPrefix('\0') {
+       sem_init(&m_mutex, 0, 1);
        if (isGlobal) {
                delete m_globalLogger;
                m_globalLogger = this;
@@ -282,6 +285,7 @@ ReLogger::~ReLogger() {
        m_appenderListSize = 0;
        if (m_globalLogger == this)
                m_globalLogger = NULL;
+       sem_destroy(&m_mutex);
 }
 /** @brief Issues a log message.
  *
@@ -296,6 +300,7 @@ ReLogger::~ReLogger() {
  */
 bool ReLogger::say(ReClassCategoryGranularity mode, ReLogLocation location,
     const char* message) {
+       sem_wait(&m_mutex);
        m_mode = mode;
        m_location = location;
        m_standardPrefix[0] = '\0';
@@ -305,8 +310,39 @@ bool ReLogger::say(ReClassCategoryGranularity mode, ReLogLocation location,
                if (app->accept(mode))
                        app->say(this, message);
        }
+       sem_post(&m_mutex);
        return true;
 }
+/** @brief Issues a log message.
+ *
+ * The message will be put to all appenders which accept the log message.
+ *
+ * @param mode         The mode controlling the issuing of the logging.
+ *                                     This mode will be compared to the settings of the appenders.
+ * @param position     The identification of the call.
+ * @param message      The message to log.
+ *
+ * @return true
+ */
+bool ReLogger::say(char prefix, ReClassCategoryGranularity mode,
+               ReLogLocation location, const char* message) {
+       sem_wait(&m_mutex);
+       char safePrefix = m_charPrefix;
+       m_charPrefix = prefix;
+       m_mode = mode;
+       m_location = location;
+       m_standardPrefix[0] = '\0';
+
+       for (size_t ii = 0; ii < m_appenderListLength; ii++) {
+               ReAppender* app = m_appenderList[ii];
+               if (app->accept(mode))
+                       app->say(this, message);
+       }
+       m_charPrefix = safePrefix;
+       sem_post(&m_mutex);
+       return true;
+}
+
 /** @brief Issues a formatted log message.
  *
  * The message will be put to all appenders which accept the log message.
@@ -321,7 +357,8 @@ bool ReLogger::say(ReClassCategoryGranularity mode, ReLogLocation location,
  * @return true
  */
 ReVarArgs& ReLogger::sayF(ReClassCategoryGranularity mode,
-    ReLogLocation location, const char* format) {
+               ReLogLocation location, const char* format) {
+       sem_wait(&m_mutex);
        if (m_locationOfOpenSayF != 0) {
                char message[128];
                _snprintf(message, sizeof message,
@@ -333,6 +370,7 @@ ReVarArgs& ReLogger::sayF(ReClassCategoryGranularity mode,
        m_location = location;
        m_standardPrefix[0] = '\0';
        reset(format);
+       sem_post(&m_mutex);
        return *this;
 }
 /** Adds an appender to the appender list.
@@ -377,7 +415,7 @@ void ReLogger::addStandardAppenders(bool console, const char* file,
  *
  * @return The standard prefix.
  */
-const char* ReLogger::getStandardPrefix(void) {
+const char* ReLogger::standardPrefix(char charPrefix) {
        if (m_standardPrefix[0] == 0) {
                char cc;
                switch (m_mode & LOG_CLASS_ALL) {
@@ -395,10 +433,14 @@ const char* ReLogger::getStandardPrefix(void) {
                        break;
                }
                m_standardPrefix[0] = cc;
-
+               int start = 1;
+               if (charPrefix == '\0')
+                       charPrefix = m_charPrefix;
+               if (charPrefix != '\0')
+                       m_standardPrefix[start++] = charPrefix;
                time_t now = time(NULL);
                struct tm* now1 = localtime(&now);
-               strftime(m_standardPrefix + 1, sizeof m_standardPrefix - 1,
+               strftime(m_standardPrefix + start, sizeof m_standardPrefix - start,
                    "%Y.%m.%d %H:%M:%S", now1);
                size_t len = strlen(m_standardPrefix);
                char* ptr = m_standardPrefix + len;
index e09086d866b795fce601e183f59aac020455ab8e..6ec0321af6c4c61ca44e6f2e8bbe8abac724cf35 100644 (file)
@@ -147,19 +147,29 @@ private:
        // Not accessible, not implemented!
        ReLogger& operator =(const ReLogger& source);
 public:
+       void addAppender(ReAppender* appender);
+       void addStandardAppenders(bool console, const char* file, int fileCount = 5,
+           int fileSize = 1000100);
+       virtual void end(void);
        bool say(ReClassCategoryGranularity mode, ReLogLocation location,
            const char* message);
+       bool say(char prefix, ReClassCategoryGranularity mode, ReLogLocation location,
+           const char* message);
        ReVarArgs& sayF(ReClassCategoryGranularity mode, ReLogLocation location,
            const char* format);
-       virtual void end(void);
-
-       void addAppender(ReAppender* appender);
-
-       const char* getStandardPrefix(void);
-       ReClassCategoryGranularity getCurrentMode(void) const;
-       int getCurrentPosition(void) const;
-       void addStandardAppenders(bool console, const char* file, int fileCount = 5,
-           int fileSize = 1000100);
+       /** Returns the current mode of the logging call.
+        * @return      the current mode (class, category and granularity)
+        */
+       inline ReClassCategoryGranularity currentMode(void) const{
+               return m_mode;
+       }
+       /** Returns the current location of the logging call.
+        * @return      the current location
+        */
+       inline ReLogLocation currentLocation(void) const{
+               return m_location;
+       }
+       const char* standardPrefix(char prefix = '\0');
 protected:
        ReAppender** m_appenderList;
        size_t m_appenderListSize;
@@ -170,6 +180,10 @@ protected:
        ReAppender* m_stdConsoleAppender;
        ReFileAppender* m_stdFileAppender;
        int m_locationOfOpenSayF;
+       sem_t m_mutex;
+       char m_charPrefix;
+private:
+
 };
 
 inline ReLogger* globalLogger() {
index 4e3dc9c8247e310e01d9a0551822b113e9e87c55..9f0e26ebe2a60dfa82d68132f24bb811dfbffc35 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdarg.h>
 #include <limits.h>
 #include <pthread.h>
+#include <semaphore.h>
+
 #define __LITTLE_ENDIAN__
 //#define __BIG_ENDIAN__
 
index 22d16dfa23ac4609b2b8a638094b5312d8da83ea..e024cc3eae16c1bee7a5d43f7910275a8ffbc015 100644 (file)
@@ -16,6 +16,7 @@ public:
        }
 private:
        void run() {
+               testSlaveAppender();
                testMemoryAppender();
                testBase();
        }
@@ -36,20 +37,53 @@ private:
                globalLogger()->say(CAT_LIB, __LINE__, "globalLogger()");
        }
        void testMemoryAppender(){
+               ReLogger logger(false);
                ReMemoryAppender appender(3);
-               appender.say(NULL, "1");
-               appender.say(NULL, "2");
-               appender.say(NULL, "3");
+               logger.addAppender(&appender);
+               appender.say(NULL, "x1");
+               appender.say(NULL, "x2");
+               appender.say(NULL, "x3");
                ReByteBuffer line;
                checkEqu(3U, appender.count());
-               checkEqu("1", appender.get(0, line));
-               checkEqu("2", appender.get(1, line));
-               checkEqu("3", appender.get(2, line));
-               appender.say(NULL, "4");
+               checkT(appender.get(2, line));
+               checkT(line.indexOf("x1", 2) >= 0);
+               checkT(appender.get(1, line));
+               checkT(line.indexOf("x2", 2) >= 0);
+               checkT(appender.get(0, line));
+               checkT(line.indexOf("x3", 2) >= 0);
+               appender.say(NULL, "x4");
                checkEqu(3U, appender.count());
-               checkEqu("2", appender.get(0, line));
-               checkEqu("3", appender.get(1, line));
-               checkEqu("4", appender.get(2, line));
+               checkT(appender.get(2, line));
+               checkT(line.indexOf("x2", 2) >= 0);
+               checkT(appender.get(1, line));
+               checkT(line.indexOf("x3", 2) >= 0);
+               checkT(appender.get(0, line));
+               checkT(line.indexOf("x4", 2) >= 0);
+               ReByteBuffer all;
+               checkEqu(3, appender.join(all).count("\n"));
+       }
+       void testSlaveAppender(){
+               ReLogger masterLogger(false);
+               ReMemoryAppender memoryAppender(10);
+               masterLogger.addAppender(&memoryAppender);
+
+               ReLogger slave1(false);
+               ReSlaveAppender slaveAppender1(&masterLogger, '$');
+               slave1.addAppender(&slaveAppender1);
+
+               ReLogger slave2(false);
+               ReSlaveAppender slaveAppender2(&masterLogger, '%');
+               slave2.addAppender(&slaveAppender2);
+
+               slave1.say(LOG_INFO | CAT_TEST, 9999, "slave1");
+               slave2.say(LOG_INFO | CAT_TEST, 9999, "slave2");
+               ReByteBuffer line;
+               memoryAppender.get(0, line);
+               checkT(line.indexOf('%') >= 0);
+               checkT(line.indexOf("slave2", -1) >= 0);
+               memoryAppender.get(1, line);
+               checkT(line.indexOf('$') >= 0);
+               checkT(line.indexOf("slave1", -1) >= 0);
        }
 };
 extern void testReLogger(void);
index 532ef92c1c19ebb8a2eed969f0c0277d6b4dfd59..0d79d1b5432179aed6fc4193f619176a900a5233 100644 (file)
@@ -85,12 +85,12 @@ void testMath() {
 }
 void testAll() {
        try {
-               testNet();
+               //testNet();
                if (s_testAll) {
                        testString();
                        testMath();
                        testOs();
-                       testNet();
+                       //testNet();
                        testBase();
                }
        } catch (ReException e) {
index 8792a73e5b67afb40c39a78889029dcd42bc6e4c..364a0c872accbdea5103fe7770ab4afaa5d6e3d3 100644 (file)
@@ -211,10 +211,12 @@ void ReTCPConnection::send(const char* command, const char* message,
  * @param id           an identifier for logging
  * @param logger       the logger for error handling
  */
-ReTCPServerConnection::ReTCPServerConnection(int id, ReLogger* logger,
+ReTCPServerConnection::ReTCPServerConnection(int id, ReLogger* masterLogger,
        ReTCPServer* server) :
-           ReTCPConnection(id, logger),
-           m_server(server){
+           ReTCPConnection(id, new ReLogger(false)),
+           m_server(server),
+           m_slaveAppender(masterLogger, '0' + id % ('z' - '0' + 1)){
+       m_logger->addAppender(&m_slaveAppender);
 }
 
 /**
index c0d7195599ac42ff10f83af7c5fa09989f261947..0149a6bf6c51f35f63c5e694ef6831a4cb813c80 100644 (file)
@@ -127,6 +127,7 @@ public:
        void handleConnection();
 private:
        ReTCPServer* m_server;
+       ReSlaveAppender m_slaveAppender;
 };
 class ReNetCommandHandler;
 /**