#include "util.h" #include "dispatcher.h" #include #include #include #include #include //#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(); // sends out a message with "normal" loglevel // ConsoleLog writeLine(, ); // sends out a message with the chosen loglevel --> enum LOG_LEVEL // ConsoleLog writeError(); // sends out a message with "Error" loglevel // ConsoleLog writeTerminal(); // sends out a message with "Terminal" loglevel, which means it is // // also printed on stdout // ConsoleLog writeNetwork(); // sends out a message with "network" loglevel // ConsoleLog writeChat(); // sends out a message with "Chat" loglevel // // *un/subscribing to the LogDispatcher // // ConsoleLog addListener(, &myClass::myMethod); // callback signature --> typedef void (T::*callback)(ConsoleEntry); // with as template // for more on ConsoleEntry, see later // ConsoleLog removeListener(, &myClass::myMethod); // // *Misc // // ConsoleLog setLogPath(); // set the log directory (with a final /, the logfilename is appended.) // ConsoleLog setLogName(); // 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(, &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 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 void addListener(T* who, void (T :: *func)(ConsoleEntry)) { entryDispatcher.addListener(who, func); }; template void removeListener(T* who, void (T :: *func)(ConsoleEntry)) { entryDispatcher.removeListener(who, func); }; template 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* _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 _CBLog; EventDispatcher entryDispatcher; std::vector _log; std::vector _prev_log; std::ofstream _logFile; }; typedef ConsoleLogger::ConsoleEntry LogEntry; #endif