void ReSlaveAppender::say(ReLogger* logger, const char* message) {
ReByteBuffer buffer(logger->standardPrefix(m_charPrefix));
buffer.append(message == NULL ? logger->asCString() : message);
- m_masterLogger->say(logger->currentMode(), logger->currentLocation(),
- buffer.str());
+ m_masterLogger->say(logger->currentMode(), 0, buffer.str());
}
return *this;
}
+/**
+ * Appends data as string or as binary (hexdump).
+ *
+ * If data contains non ASCII char the data will be treated as binary.
+ *
+ * @param data the data to append
+ * @param length -1 (<code>strlen()</code>) or the length of data
+ * @param maxLength the maximal count of appended chars
+ * @return <code>*this</code> (chaining)
+ */
+ReByteBuffer& ReByteBuffer::appendDump(const char* data, size_t length, int maxLength){
+ if (length == size_t(-1)){
+ length = strlen(data);
+ }
+ if (length > maxLength)
+ length = maxLength;
+ // test if text or binary:
+ bool isBinary = false;
+ unsigned char cc;
+ for (int ii = 0; ii < length; ii++){
+ if ( (cc = (unsigned char) data[ii]) > 126
+ || (cc < ' ' && cc != '\n' && cc != '\r' && cc != '\t')){
+ isBinary = true;
+ break;
+ }
+ }
+ if (! isBinary)
+ append(data, length);
+ else
+ appendHexDump(data, length / 5);
+ return *this;
+}
/**
* Appends a hexadecimal dump of a memory array.
*
}
ReByteBuffer& appendFix(const char* data, size_t length, int maxLength,
int minLength = 0, const char* separator = "*", char padding = ' ');
+ ReByteBuffer& appendDump(const char* data, size_t length = -1, int maxLength = 80);
ReByteBuffer& appendHexDump(const char* data, size_t length = -1,
int offset = 0, int bytePerLine = 16, const char* offsetFormat =
"%04x: ", bool withAscii = true, int groupWidth = 1, int gapBehind =
*/
ReStreamAppender::~ReStreamAppender() {
if (m_stream != NULL) {
- fclose(m_stream);
+ if (m_stream != stdout && m_stream != stderr)
+ fclose(m_stream);
m_stream = NULL;
}
}
}
/** @brief Constructor.
+ *
+ * @param isGlobal <code>true</code>: the local will be the global logger
*/
ReLogger::ReLogger(bool isGlobal) :
ReVarArgs(),
*
* 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.
+ * @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
*/
*
* 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.
+ * @param mode the mode controlling the issuing of the logging.
+ * this mode will be compared to the settings of the appenders
+ * @param location The identification of the call.<br>
+ * 0: no prefix with date and location will be part of the message
+ * @param message the message to log
*
* @return true
*/
* <strong>Note:</strong><br />
* Don't forget to finish the argument list with ReVarArgs::end()!
*
- * @param mode The mode controlling the issuing of the logging.
- * This mode will be compared to the settings of the appenders.
- * @param location The identification of the call.
- * @param message The message to log.
+ * @param mode the mode controlling the issuing of the logging.
+ * This mode will be compared to the settings of the appenders
+ * @param location the identification of the call.<br>
+ * 0: no prefix with date and location will be part of the message
+ * @param message the message to log
*
* @return true
*/
}
/** Adds an appender to the appender list.
*
- * @param appender The appender.
+ * @param appender the appender.
*/
void ReLogger::addAppender(ReAppender* appender) {
if (m_appenderListLength >= m_appenderListSize)
/** Adds standard appenders to the appender list.
*
- * @param console true: A console appender will be added.
- * @param file NULL: No file appender.
- * Otherwise: A file appender will be appended.
- * @param maxFiles The maximal count of log files produced by the file appender.
- * @param masSize The maximal size of one log file produced by the file appender.
+ * @param console <code>true</code>: a console appender will be added
+ * @param file NULL: no file appender<br>
+ * otherwise: A file appender will be appended
+ * @param maxFiles the maximal count of log files produced by the file appender
+ * @param masSize the maximal size of one log file produced by the file appender
*/
void ReLogger::addStandardAppenders(bool console, const char* file,
int maxFiles, int maxSize) {
* Most of the appenders will use this prefix.
* It will be build on demand.
*
- * @return The standard prefix.
+ * @return the standard prefix
*/
const char* ReLogger::standardPrefix(char charPrefix) {
- if (m_standardPrefix[0] == 0) {
+ if (m_standardPrefix[0] == 0 && m_location != 0) {
char cc;
- switch (m_mode & LOG_CLASS_ALL) {
+ int level = (m_mode & LOG_CLASS_ALL);
+ switch (level) {
case LOG_ABORT:
cc = '#';
break;
case LOG_WARNING:
cc = '+';
break;
+ case LOG_DEBUG:
+ cc = '_';
+ break;
default:
cc = ' ';
break;
enum ReLogClass {
LOG_ABORT = 1,
LOG_ERROR = 2,
- LOG_WARNING = 4,
- LOG_INFO = 8,
-
+ LOG_WARNING = 3,
+ LOG_INFO = 4,
+ LOG_DEBUG = 5,
LOG_CLASS_ALL = 0xf
};
/*
*\r
* @param id the thread id\r
* @param masterLogger the logger for error handling\r
- * @param starter the instance which has started the thread\r
+ * @param pool the instance which has started the thread\r
*/\r
bool ReThread::prepareToRun(int id, ReLogger* masterLogger,\r
- ReThreadPool* starter) {\r
+ ReThreadPool* pool) {\r
bool rc = false;\r
if (m_pool != NULL) {\r
- globalLogger()->say(LOG_ERROR | CAT_LIB, LC_PREPARE_TO_RUN_1,\r
- i18n("setMasterLogger() is called multiple times"));\r
+ ReLogger* current = masterLogger == NULL ? globalLogger() : masterLogger;\r
+ current->sayF(LOG_ERROR | CAT_LIB, LC_PREPARE_TO_RUN_1,\r
+ i18n("prepareToRun($1) is called multiple times")).arg(id).end();\r
} else {\r
m_threadId = id;\r
- if (m_appender == NULL)\r
- m_appender = new ReSlaveAppender(masterLogger,\r
- '0' + (id % ('z' - '0' + 1)));\r
- else\r
+ if (m_appender != NULL){\r
m_appender->setMasterLogger(masterLogger);\r
- m_pool = starter;\r
+ } else {\r
+ m_appender = new ReSlaveAppender(masterLogger,\r
+ '@' + (id % ('z' - '@' + 1)));\r
+ m_threadLogger.addAppender(m_appender);\r
+ }\r
+ m_pool = pool;\r
rc = true;\r
}\r
return rc;\r
public:\r
virtual void process() = 0;\r
};\r
+/** Returns the minimum of 2 values.\r
+ * @param a first value\r
+ * @param b 2nd value\r
+ * @return minimum of a and b\r
+ */\r
+inline int min(int a, int b){\r
+ return a < b ? a : b;\r
+}\r
+/** Returns the maximum of 2 values.\r
+ * @param a first value\r
+ * @param b 2nd value\r
+ * @return maximum of a and b\r
+ */\r
+inline int max(int a, int b){\r
+ return a < b ? a : b;\r
+}\r
#include "base/ReMutex.hpp"\r
#include "base/ReByteBuffer.hpp"\r
#include "base/ReVarArgs.hpp"\r
public:
virtual void run() {
ReLogger* theLogger = logger();
- int location = 999;
+ int location = 60999;
if (strcmp(m_task, "server") == 0) {
theLogger->say(LOG_INFO | CAT_LIB, location, "starting server...");
ReLogger logger(false);
}
}
void speedTest(ReLogger* logger, bool upload) {
- int location = 998;
+ int location = 60998;
const char* direction = upload ? "upload" : "download";
logger->sayF(LOG_INFO | CAT_LIB, location, "$1 client started..").arg(
direction).end();
private:
void run() {
ReLogger logger(false);
+ int location = 60997;
logger.addStandardAppenders(true, NULL, 0, 0);
- ReThreadPool threadStarter(1, &logger);
- threadStarter.startThread(new TCPThread("server"));
- threadStarter.startThread(new TCPThread("echo"));
- threadStarter.startThread(new TCPThread("upload"));
- threadStarter.startThread(new TCPThread("download"));
- threadStarter.waitForAlmostAll(1, 20);
+ logger.say(LOG_INFO | CAT_LIB, location, "TCP test");
+ ReThreadPool pool(4, &logger);
+ pool.startThread(new TCPThread("server"));
+ pool.startThread(new TCPThread("echo"));
+ pool.startThread(new TCPThread("upload"));
+ pool.startThread(new TCPThread("download"));
+ pool.waitForAlmostAll(1, 20000);
ReTCPStopClient stopper(&logger);
stopper.stopServer(s_port);
}
LC_CONNECT_2, // 50516
LC_CONNECT_3, // 50517
LC_TCP_CONNECTION_1, // 50518
+ LC_WRITE_2, // 50519
+ LC_RECEIVE_5, // 50520
};
#if defined __WIN32__
m_name.appendChar(':').appendInt(port);
}
+/**
+ * Receives a message.
+ *
+ * @param command OUT: the received command
+ * @param data OUT: the received data
+ */
void ReTCPConnection::receive(ReByteBuffer& command, ReByteBuffer& data) {
command.setLength(8);
int received = recv(m_handleSocket, command.buffer(), 8, 0);
m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK,
LC_RECEIVE_4, i18n("too few bytes read: $1/$2 [$3]")).arg(
readBytes).arg(received).arg(m_peerName).end();
+ } else {
+ m_loggerOwner->logger()->sayF(LOG_DEBUG | CAT_NETWORK, LC_RECEIVE_5,
+ i18n("received: $1 bytes in $2 round(s) [$3]: $4")).arg(length).arg(rounds).arg(
+ m_peerName).arg(ReByteBuffer().appendDump(data.str(), data.length(), 80).str()).end();
}
command.setLength(0);
if (readBytes >= 8) {
int sent = 0;
int rest = length;
const char* buf = m_toSend.str();
+ int rounds = 0;
while (rest > 0) {
+ rounds++;
if ((sent = ::send(m_handleSocket, buf, rest, 0)) > 0) {
buf += sent;
rest -= sent;
break;
}
}
+ if (rest == 0)
+ m_loggerOwner->logger()->sayF(LOG_DEBUG | CAT_NETWORK, LC_WRITE_2,
+ i18n("sent: $1 bytes in $2 round(s): $3")).arg(length).arg(rounds)
+ .arg(ReByteBuffer().appendDump(data, length, 80).str()).end();
}
/**