#include "util.h"
#include "dispatcher.h"
#include <vector>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <list>
//#define as_daemon
#ifndef _CONSOLELOGGER_H_
#define _CONSOLELOGGER_H_
/**********************************************************************************************************************/
// Console-, and Message Dispatching / Logging (With timestamping!)
/**********************************************************************************************************************/
//
// :: Usage ::
//
#define ConsoleLog ConsoleLogger::getLogger()-> //ease of acces!
//
//
// *Logging:
//
// ConsoleLog writeLine(<string/char*>); // sends out a message with "normal" loglevel
// ConsoleLog writeLine(<string/char*>, <loglevel>); // sends out a message with the chosen loglevel --> enum LOG_LEVEL
// ConsoleLog writeError(<string/char*>); // sends out a message with "Error" loglevel
// ConsoleLog writeTerminal(<string/char*>); // sends out a message with "Terminal" loglevel, which means it is
// // also printed on stdout
// ConsoleLog writeNetwork(<string/char*>); // sends out a message with "network" loglevel
// ConsoleLog writeChat(<string/char*>); // sends out a message with "Chat" loglevel
//
// *un/subscribing to the LogDispatcher
//
// ConsoleLog addListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod);
// callback signature --> typedef void (T::*callback)(ConsoleEntry); // with <U, T> as template // for more on ConsoleEntry, see later
// ConsoleLog removeListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod);
//
// *Misc
//
// ConsoleLog setLogPath(<string-path-to-log-directory>); // set the log directory (with a final /, the logfilename is appended.)
// ConsoleLog setLogName(<string-name>); // like the above, but for the filename.
// ConsoleLog dumpLog(DUMP_MODE);
//
// DUMP_FILE ::>> Dumps the whole log since the logger was started into the specified logfile. the file content gets overwritten
// DUMP_FILE_CONCAT ::>> The Same as above, but it will just append itself to the previously (if implemented) log which got \**
// ***\ read from the logfile which was present at logger start. if no log is found or logfile was not read, behaves as DUMP_FILE
// DUMP_TERMINAL ::>> Dumps the whole log into the terminal
// DUMP_ALL_LISTENERS ::>> Dumps the whole log to all listeners
//
// Alternatively, you can request a dump to a certain listener:
// ConsoleLog dump2Listener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); // it expects the same information as when subscribing
// // the PVS-Server console makes heavy use of this feature to implement its filters
//
//
// :: using the ConsoleEntry class ::
//
// *methods and members
//
//
// LOG_LEVEL getLevel() // returns the loglevel as LOG_LEVEL Enum-type
// QString getLine() // returns the complete line as shown in the logfile, with timestamp, loglevel prefix etc
// QString getMessage() // returns the message body, no gimmicks attached
// QString getPrefix() // returns the loglevel as string-represenation
// QString getTimeStamp() // returns the timestamp which was set at the creation of the object
//
//
//
//
//
//
/**********************************************************************************************************************/
// Typdef at bottom of file :
// typedef ConsoleLogger::ConsoleEntry LogEntry;
class ConsoleLogger
{
public:
enum LOG_LEVEL { LOG_NORMAL,
LOG_ERROR,
LOG_CHAT,
LOG_TERMINAL,
LOG_NETWORK
};
enum DUMP_MODE { DUMP_FILE,
DUMP_FILE_CONCAT,
DUMP_TERMINAL,
DUMP_ALL_LISTENERS,
};
class ConsoleEntry
{
public:
ConsoleEntry(QString timeStamp, QString message, LOG_LEVEL level)
{
setLine(timeStamp, message, level);
};
void setLine(QString timeStamp, QString message, LOG_LEVEL level)
{
_message = message;
_prefix = _prefixLine(level);
_timeStamp = timeStamp;
_line.append(QString("[ ").append(timeStamp));
_line.append(QString(" ] ").append(_prefix));
_line.append(QString(": ").append(message));
_level = level;
if ('\n' != _line[_line.size()-1] && '\n' != _line[_line.size()])
_line.push_back('\n'); // add an explicit newline char, so it looks better in the logfile
//#ifndef as_daemon
if (_level == LOG_TERMINAL) // may look strange here, but its quite central :-)
qDebug("%s", qPrintable(_line));
//#endif
};
LOG_LEVEL getLevel()
{
return _level;
};
QString getLine()
{
return _line;
};
QString getMessage()
{
return _message;
};
QString getPrefix()
{
return _prefix;
};
QString getTimeStamp()
{
return _timeStamp;
};
private:
QString _prefixLine(LOG_LEVEL level)
{
// switch anyone?
if (level == LOG_NORMAL)
return QString("PVS");
if (level == LOG_ERROR)
return QString("PVS ERROR");
if (level == LOG_TERMINAL)
return QString("PVS Terminal");
if (level == LOG_CHAT)
return QString("PVS Chat");
if (level == LOG_NETWORK)
return QString("PVS Network");
return QString("UNDEFINED");
};
QString _line; // the complete line with timestamp and everything
QString _message; // the message itself
QString _prefix; // just the prefix
QString _timeStamp; // just the timestamp
LOG_LEVEL _level;
};
class LogNotifyEntry
{
public:
virtual void fire(ConsoleEntry consoleEntry) {};
LogNotifyEntry() {};
};
#ifdef never
private:
template<class T>
class LogNotify : public LogNotifyEntry
{
public:
typedef void (T::*callback)(ConsoleEntry);
LogNotify(T* who, callback func )//void (T :: *func)(QString))
{
callee = who;
//callback = func;
myCB = func;
};
virtual void fire(ConsoleEntry consoleEntry)
{
if (callee)
(callee->*myCB)(consoleEntry);
};
T* getCallee()
{
return callee;
};
callback getCB()
{
return myCB;
};
private:
T *callee;
callback myCB;
};
public:
#endif
// interfaces for the dispatcher for easy of access ( --> ConsoleLog Makro)
template<class T> void addListener(T* who, void (T :: *func)(ConsoleEntry))
{
entryDispatcher.addListener(who, func);
};
template<class T> void removeListener(T* who, void (T :: *func)(ConsoleEntry))
{
entryDispatcher.removeListener(who, func);
};
template<class T> void dump2Listener(T* who, void (T :: *func)(ConsoleEntry))
{
for (int i = 0; i < int(_log.size()) ; i++)
(who->*func)(_log[i]);
};
int writeLine(QString message, LOG_LEVEL = LOG_NORMAL);
int writeline(const char* message, LOG_LEVEL = LOG_NORMAL);
int writeError(QString error);
int writeError(const char* error);
int writeTerminal(QString terminal);
int writeTerminal(const char* terminal);
int writeNetwork(QString network);
int writeNetwork(const char* network);
int writeChat(QString chat);
int writeChat(const char* chat);
void getLine(int lineNum, char* line);
void getLine(int lineNum, QString* line);
void setLogPath(QString logPath);
void setLogName(QString logName);
void dumpLog(DUMP_MODE mode = DUMP_FILE);
static ConsoleLogger* getLogger();
static int count;
private:
std::vector<ConsoleEntry>* _getLog()
{
return &_log;
};
static ConsoleLogger* _logger;
void _prepareLog();
void _writeLine2File(QString line);
void _writeLog(bool concat = false);
void _announceWrite(ConsoleEntry consoleEntry);
void _readLog(QString path = QString(""));
QString _getTimeStamp();
void _prefixLine(QString* line, LOG_LEVEL level = LOG_NORMAL);
ConsoleLogger();
~ConsoleLogger();
QString _logName;
QString _logPath;
bool _logFileGood, _fileRead;
// std::list<LogNotifyEntry*> _CBLog;
EventDispatcher<ConsoleEntry> entryDispatcher;
std::vector<ConsoleEntry> _log;
std::vector<ConsoleEntry> _prev_log;
std::ofstream _logFile;
};
typedef ConsoleLogger::ConsoleEntry LogEntry;
#endif