From 4880e31562d1ab558a9bae3e804dce7120545e22 Mon Sep 17 00:00:00 2001 From: Murat Seker Date: Sun, 19 Jul 2020 15:37:47 +0200 Subject: [PATCH] Make logger thread safe (#885) --- assets/webconfig/js/content_logging.js | 1 - include/hyperion/AuthManager.h | 3 +- include/utils/Logger.h | 83 +++--- libsrc/api/JsonAPI.cpp | 2 +- libsrc/flatbufserver/FlatBufferConnection.cpp | 2 +- libsrc/hyperion/ComponentRegister.cpp | 2 +- libsrc/hyperion/Grabber.cpp | 2 +- libsrc/hyperion/SettingsManager.cpp | 2 +- libsrc/utils/DefaultSignalHandler.cpp | 91 ++++-- libsrc/utils/Logger.cpp | 281 ++++++++++-------- 10 files changed, 276 insertions(+), 193 deletions(-) diff --git a/assets/webconfig/js/content_logging.js b/assets/webconfig/js/content_logging.js index 4ffbfeff..94209845 100644 --- a/assets/webconfig/js/content_logging.js +++ b/assets/webconfig/js/content_logging.js @@ -4,7 +4,6 @@ requestLoggingStart(); $(document).ready(function() { - var messages; var loguplmess = ""; var reportUrl = 'https://report.hyperion-project.org/#'; diff --git a/include/hyperion/AuthManager.h b/include/hyperion/AuthManager.h index fb4607d8..89ed6a88 100644 --- a/include/hyperion/AuthManager.h +++ b/include/hyperion/AuthManager.h @@ -5,6 +5,7 @@ //qt #include +#include class AuthTable; class MetaTable; @@ -258,4 +259,4 @@ private slots: /// @brief Check if there are timeouts for failed login attempts /// void checkAuthBlockTimeout(); -}; \ No newline at end of file +}; diff --git a/include/utils/Logger.h b/include/utils/Logger.h index 1c3168ae..a57a21ab 100644 --- a/include/utils/Logger.h +++ b/include/utils/Logger.h @@ -3,29 +3,33 @@ // QT includes #include #include +#include +#include +#include +#include // stl includes #include #include -#include -#include #ifdef _WIN32 #include #endif #include +#define LOG_MESSAGE(severity, logger, ...) (logger)->Message(severity, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) + // standard log messages -#define Debug(logger, ...) (logger)->Message(Logger::DEBUG , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define Info(logger, ...) (logger)->Message(Logger::INFO , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define Warning(logger, ...) (logger)->Message(Logger::WARNING, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define Error(logger, ...) (logger)->Message(Logger::ERRORR , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define Debug(logger, ...) LOG_MESSAGE(Logger::DEBUG , logger, __VA_ARGS__) +#define Info(logger, ...) LOG_MESSAGE(Logger::INFO , logger, __VA_ARGS__) +#define Warning(logger, ...) LOG_MESSAGE(Logger::WARNING, logger, __VA_ARGS__) +#define Error(logger, ...) LOG_MESSAGE(Logger::ERRORR , logger, __VA_ARGS__) // conditional log messages -#define DebugIf(condition, logger, ...) if (condition) (logger)->Message(Logger::DEBUG , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define InfoIf(condition, logger, ...) if (condition) (logger)->Message(Logger::INFO , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define WarningIf(condition, logger, ...) if (condition) (logger)->Message(Logger::WARNING , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define ErrorIf(condition, logger, ...) if (condition) (logger)->Message(Logger::ERRORR , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define DebugIf(condition, logger, ...) if (condition) Debug(logger, __VA_ARGS__) +#define InfoIf(condition, logger, ...) if (condition) Info(logger, __VA_ARGS__) +#define WarningIf(condition, logger, ...) if (condition) Warning(logger, __VA_ARGS__) +#define ErrorIf(condition, logger, ...) if (condition) Error(logger, __VA_ARGS__) // ================================================================ @@ -35,62 +39,68 @@ class Logger : public QObject public: enum LogLevel { - UNSET, - DEBUG, - INFO, - WARNING, - ERRORR, - OFF + UNSET = 0, + DEBUG = 1, + INFO = 2, + WARNING = 3, + ERRORR = 4, + OFF = 5 }; - typedef struct + struct T_LOG_MESSAGE { QString appName; QString loggerName; QString function; unsigned int line; QString fileName; - time_t utime; + uint64_t utime; QString message; LogLevel level; QString levelString; - } T_LOG_MESSAGE; + }; - static Logger* getInstance(QString name="", LogLevel minLevel=Logger::INFO); - static void deleteInstance(QString name=""); - static void setLogLevel(LogLevel level, QString name=""); - static LogLevel getLogLevel(QString name=""); + static Logger* getInstance(const QString & name = "", LogLevel minLevel=Logger::INFO); + static void deleteInstance(const QString & name = ""); + static void setLogLevel(LogLevel level, const QString & name = ""); + static LogLevel getLogLevel(const QString & name = ""); void Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...); - void setMinLevel(LogLevel level) { _minLevel = level; } - LogLevel getMinLevel() { return _minLevel; } + void setMinLevel(LogLevel level) { _minLevel = static_cast(level); } + LogLevel getMinLevel() { return static_cast(int(_minLevel)); } + QString getName() const { return _name; } + QString getAppName() const { return _appname; } signals: void newLogMessage(Logger::T_LOG_MESSAGE); protected: - Logger( QString name="", LogLevel minLevel=INFO); + Logger(const QString & name="", LogLevel minLevel = INFO); ~Logger(); private: - static std::map *LoggerMap; - static LogLevel GLOBAL_MIN_LOG_LEVEL; + void write(const Logger::T_LOG_MESSAGE & message) const; - QString _name; - QString _appname; - LogLevel _minLevel; - bool _syslogEnabled; - unsigned _loggerId; + static QMutex MapLock; + static QMap LoggerMap; + static QAtomicInteger GLOBAL_MIN_LOG_LEVEL; + + const QString _name; + const QString _appname; + const bool _syslogEnabled; + const unsigned _loggerId; + + /* Only non-const member, hence the atomic */ + QAtomicInteger _minLevel; }; - class LoggerManager : public QObject { Q_OBJECT public: static LoggerManager* getInstance(); - QVector* getLogMessageBuffer() { return &_logMessageBuffer; } + const QList* getLogMessageBuffer() const { return &_logMessageBuffer; } public slots: void handleNewLogMessage(const Logger::T_LOG_MESSAGE&); @@ -101,8 +111,7 @@ signals: protected: LoggerManager(); - static LoggerManager* _instance; - QVector _logMessageBuffer; + QList _logMessageBuffer; const int _loggerMaxMsgBufferSize; }; diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 51ac6d5a..1265fbf9 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -1548,7 +1548,7 @@ void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE &msg) if (!_streaming_logging_activated) { _streaming_logging_activated = true; - QVector *logBuffer = LoggerManager::getInstance()->getLogMessageBuffer(); + const QList *logBuffer = LoggerManager::getInstance()->getLogMessageBuffer(); for (int i = 0; i < logBuffer->length(); i++) { message["appName"] = logBuffer->at(i).appName; diff --git a/libsrc/flatbufserver/FlatBufferConnection.cpp b/libsrc/flatbufserver/FlatBufferConnection.cpp index 966ee342..ec28f59b 100644 --- a/libsrc/flatbufserver/FlatBufferConnection.cpp +++ b/libsrc/flatbufserver/FlatBufferConnection.cpp @@ -12,7 +12,7 @@ FlatBufferConnection::FlatBufferConnection(const QString& origin, const QString , _origin(origin) , _priority(priority) , _prevSocketState(QAbstractSocket::UnconnectedState) - , _log(Logger::getInstance("FLATBUFCONNECTION")) + , _log(Logger::getInstance("FLATBUFCONN")) , _registered(false) { QStringList parts = address.split(":"); diff --git a/libsrc/hyperion/ComponentRegister.cpp b/libsrc/hyperion/ComponentRegister.cpp index 5f6d1514..5a38a6bd 100644 --- a/libsrc/hyperion/ComponentRegister.cpp +++ b/libsrc/hyperion/ComponentRegister.cpp @@ -7,7 +7,7 @@ using namespace hyperion; ComponentRegister::ComponentRegister(Hyperion* hyperion) : _hyperion(hyperion) - , _log(Logger::getInstance("ComponentRegister")) + , _log(Logger::getInstance("COMPONENTREG")) { // init all comps to false QVector vect; diff --git a/libsrc/hyperion/Grabber.cpp b/libsrc/hyperion/Grabber.cpp index bf6527ed..c0954043 100644 --- a/libsrc/hyperion/Grabber.cpp +++ b/libsrc/hyperion/Grabber.cpp @@ -14,7 +14,7 @@ Grabber::Grabber(QString grabberName, int width, int height, int cropLeft, int c , _cropTop(0) , _cropBottom(0) , _enabled(true) - , _log(Logger::getInstance(grabberName)) + , _log(Logger::getInstance(grabberName.toUpper())) { Grabber::setVideoMode(VideoMode::VIDEO_2D); Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom); diff --git a/libsrc/hyperion/SettingsManager.cpp b/libsrc/hyperion/SettingsManager.cpp index 3f9425b7..51a3291d 100644 --- a/libsrc/hyperion/SettingsManager.cpp +++ b/libsrc/hyperion/SettingsManager.cpp @@ -16,7 +16,7 @@ QJsonObject SettingsManager::schemaJson; SettingsManager::SettingsManager(const quint8& instance, QObject* parent) : QObject(parent) - , _log(Logger::getInstance("SettingsManager")) + , _log(Logger::getInstance("SETTINGSMGR")) , _sTable(new SettingsTable(instance, this)) { // get schema diff --git a/libsrc/utils/DefaultSignalHandler.cpp b/libsrc/utils/DefaultSignalHandler.cpp index 4fec4596..2b5c6324 100644 --- a/libsrc/utils/DefaultSignalHandler.cpp +++ b/libsrc/utils/DefaultSignalHandler.cpp @@ -16,6 +16,35 @@ namespace DefaultSignalHandler { +struct Signal +{ + int number; + const char * name; +}; + +const Signal ALL_SIGNALS[] = { + { SIGABRT, "SIGABRT" }, + { SIGBUS, "SIGBUS" }, + { SIGFPE, "SIGFPE" }, + { SIGILL, "SIGILL" }, + { SIGSEGV, "SIGSEGV" }, + { SIGTERM, "SIGTERM" }, + { SIGHUP, "SIGHUP" }, + { SIGINT, "SIGINT" }, + { SIGPIPE, "SIGPIPE" }, +}; + +void write_to_stderr(const char* data, size_t size) +{ + int res = write(STDERR_FILENO, data, size); + + Q_UNUSED(res); +} + +void write_to_stderr(const char* data) +{ + write_to_stderr(data, strlen(data)); +} std::string decipher_trace(const std::string &trace) { @@ -70,26 +99,48 @@ void print_trace() free(symbols); } +void install_default_handler(int signum) +{ + struct sigaction action{}; + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_DFL; + (void)sigaction(signum, &action, nullptr); +} + /* Note that this signal handler is not async signal safe ! * Ideally a signal handler should only flip a bit and defer * heavy work to some kind of bottom-half processing. */ void signal_handler(int signum, siginfo_t * /*info*/, void * /*context*/) { - Logger* log = Logger::getInstance("SIGNAL"); + const char * name = "UNKNOWN SIGNAL"; - char *name = strsignal(signum); - if (name) - { - Info(log, "Signal received : %s", name); + for (const auto& s : ALL_SIGNALS) { + if (s.number == signum) { + name = s.name; + break; + } } + write_to_stderr("\n"); + write_to_stderr("Hyperion caught signal :"); + write_to_stderr(name); + write_to_stderr("\n"); + + /* Anything below here is unsafe ! */ + switch(signum) { + case SIGBUS: case SIGSEGV: case SIGABRT: case SIGFPE : print_trace(); - exit(1); + + /* Don't catch our own signal */ + install_default_handler(signum); + + kill(getpid(), signum); + return; case SIGINT : case SIGTERM: case SIGPIPE: @@ -101,10 +152,7 @@ void signal_handler(int signum, siginfo_t * /*info*/, void * /*context*/) QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); // Reset signal handler to default (in case this handler is not capable of stopping) - struct sigaction action{}; - action.sa_handler = SIG_DFL; - sigaction(signum, &action, nullptr); - + install_default_handler(signum); } } @@ -116,17 +164,20 @@ namespace DefaultSignalHandler void install() { #ifndef _WIN32 - struct sigaction action{}; - action.sa_sigaction = signal_handler; - action.sa_flags = SA_RESTART | SA_SIGINFO; + Logger* log = Logger::getInstance("CORE"); - sigaction(SIGHUP , &action, nullptr); - sigaction(SIGFPE , &action, nullptr); - sigaction(SIGINT , &action, nullptr); - sigaction(SIGTERM, &action, nullptr); - sigaction(SIGABRT, &action, nullptr); - sigaction(SIGSEGV, &action, nullptr); - sigaction(SIGPIPE, &action, nullptr); + struct sigaction action{}; + sigemptyset(&action.sa_mask); + action.sa_sigaction = signal_handler; + action.sa_flags |= SA_SIGINFO; + + for (const auto& s : ALL_SIGNALS) + { + if (sigaction(s.number, &action, nullptr)!= 0) + { + Error(log, "Failed to install handler for %s]\n", s.name); + } + } #endif // _WIN32 } } // namespace DefaultSignalHandler diff --git a/libsrc/utils/Logger.cpp b/libsrc/utils/Logger.cpp index 896ec62a..ef3d5507 100644 --- a/libsrc/utils/Logger.cpp +++ b/libsrc/utils/Logger.cpp @@ -11,99 +11,33 @@ #include #pragma comment(lib, "Shlwapi.lib") #endif +#include #include +#include +#include #include -static const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" }; +QMutex Logger::MapLock { QMutex::Recursive }; +QMap Logger::LoggerMap { }; +QAtomicInteger Logger::GLOBAL_MIN_LOG_LEVEL { static_cast(Logger::UNSET)}; + +namespace +{ +const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" }; #ifndef _WIN32 -static const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR }; +const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR }; #endif -static unsigned int loggerCount = 0; -static unsigned int loggerId = 0; -std::map *Logger::LoggerMap = nullptr; -Logger::LogLevel Logger::GLOBAL_MIN_LOG_LEVEL = Logger::UNSET; -LoggerManager* LoggerManager::_instance = nullptr; -int _repeatCount = 0; -Logger::T_LOG_MESSAGE _repeatMessage; -const int _maxRepeatCountSize = 200; +const size_t MAX_IDENTIFICATION_LENGTH = 22; -Logger* Logger::getInstance(QString name, Logger::LogLevel minLevel) -{ - qRegisterMetaType(); - Logger* log = nullptr; - if (LoggerMap == nullptr) - { - LoggerMap = new std::map; - } +QAtomicInteger LoggerCount = 0; +QAtomicInteger LoggerId = 0; - if (LoggerMap->find(name) == LoggerMap->end()) - { - log = new Logger(name,minLevel); - LoggerMap->insert(std::pair(name,log)); // compat version, replace it with following line if we have 100% c++11 - //LoggerMap->emplace(name,log); // not compat with older linux distro's e.g. wheezy - connect(log, &Logger::newLogMessage, LoggerManager::getInstance(), &LoggerManager::handleNewLogMessage); - } - else - { - log = LoggerMap->at(name); - } +const int MaxRepeatCountSize = 200; +QThreadStorage RepeatCount; +QThreadStorage RepeatMessage; - return log; -} - -void Logger::deleteInstance(QString name) -{ - if (LoggerMap == nullptr) - return; - - if (name.isEmpty()) - { - std::map::iterator it; - for (it = LoggerMap->begin(); it != LoggerMap->end(); it++) - { - delete it->second; - } - LoggerMap->clear(); - } - else if (LoggerMap->find(name) != LoggerMap->end()) - { - delete LoggerMap->at(name); - LoggerMap->erase(name); - } - -} - -void Logger::setLogLevel(LogLevel level,QString name) -{ - if (name.isEmpty()) - { - GLOBAL_MIN_LOG_LEVEL = level; - } - else - { - Logger* log = Logger::getInstance(name,level); - log->setMinLevel(level); - } -} - -Logger::LogLevel Logger::getLogLevel(QString name) -{ - if (name.isEmpty()) - { - return GLOBAL_MIN_LOG_LEVEL; - } - - Logger* log = Logger::getInstance(name); - return log->getMinLevel(); -} - -Logger::Logger (QString name, LogLevel minLevel) - : QObject() - , _name(name) - , _minLevel(minLevel) - , _syslogEnabled(true) - , _loggerId(loggerId++) +QString getApplicationName() { #ifdef __GLIBC__ const char* _appname_char = program_invocation_short_name; @@ -121,32 +55,132 @@ Logger::Logger (QString name, LogLevel minLevel) else _appname_char = "unknown"; #endif - _appname = QString(_appname_char).toLower(); + return QString(_appname_char).toLower(); - loggerCount++; +} +} // namespace - if (_syslogEnabled && loggerCount == 1) +Logger* Logger::getInstance(const QString & name, Logger::LogLevel minLevel) +{ + QMutexLocker lock(&MapLock); + + Logger* log = LoggerMap.value(name, nullptr); + if (log == nullptr) { - #ifndef _WIN32 - openlog (_appname_char, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0); - #endif + log = new Logger(name, minLevel); + LoggerMap.insert(name, log); // compat version, replace it with following line if we have 100% c++11 + //LoggerMap.emplace(name, log); // not compat with older linux distro's e.g. wheezy + connect(log, &Logger::newLogMessage, LoggerManager::getInstance(), &LoggerManager::handleNewLogMessage); + } + + return log; +} + +void Logger::deleteInstance(const QString & name) +{ + QMutexLocker lock(&MapLock); + + if (name.isEmpty()) + { + for (auto logger : LoggerMap) + delete logger; + + LoggerMap.clear(); + } + else + { + delete LoggerMap.value(name, nullptr); + LoggerMap.remove(name); + } +} + +void Logger::setLogLevel(LogLevel level, const QString & name) +{ + if (name.isEmpty()) + { + GLOBAL_MIN_LOG_LEVEL = static_cast(level); + } + else + { + Logger* log = Logger::getInstance(name, level); + log->setMinLevel(level); + } +} + +Logger::LogLevel Logger::getLogLevel(const QString & name) +{ + if (name.isEmpty()) + { + return static_cast(int(GLOBAL_MIN_LOG_LEVEL)); + } + + Logger* log = Logger::getInstance(name); + return log->getMinLevel(); +} + +Logger::Logger (const QString & name, LogLevel minLevel) + : QObject() + , _name(name) + , _appname(getApplicationName()) + , _syslogEnabled(true) + , _loggerId(LoggerId++) + , _minLevel(static_cast(minLevel)) +{ + qRegisterMetaType(); + + int count = LoggerCount.fetchAndAddOrdered(1); + + if (_syslogEnabled && count == 1) + { +#ifndef _WIN32 + openlog (_appname.toLocal8Bit(), LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0); +#endif } } Logger::~Logger() { //Debug(this, "logger '%s' destroyed", QSTRING_CSTR(_name) ); - loggerCount--; + + int count = LoggerCount.fetchAndSubOrdered(1); #ifndef _WIN32 - if (loggerCount == 0) + if (_syslogEnabled && count == 0) closelog(); #endif } +void Logger::write(const Logger::T_LOG_MESSAGE & message) const +{ + QString location; + if (message.level == Logger::DEBUG) + { + location = QString("%1:%2:%3() | ") + .arg(message.fileName) + .arg(message.line) + .arg(message.function); + } + + QString name = message.appName + " " + message.loggerName; + name.resize(MAX_IDENTIFICATION_LENGTH, ' '); + + const QDateTime timestamp = QDateTime::fromMSecsSinceEpoch(message.utime); + + std::cout << QString("%1 %2 : <%3> %4%5") + .arg(timestamp.toString("yyyy-MM-ddThh:mm:ss.zzz")) + .arg(name) + .arg(LogLevelStrings[message.level]) + .arg(location) + .arg(message.message) + .toStdString() + << std::endl; +} + void Logger::Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...) { - if ( (GLOBAL_MIN_LOG_LEVEL == Logger::UNSET && level < _minLevel) // no global level, use level from logger - || (GLOBAL_MIN_LOG_LEVEL > Logger::UNSET && level < GLOBAL_MIN_LOG_LEVEL) ) // global level set, use global level + Logger::LogLevel globalLevel = static_cast(int(GLOBAL_MIN_LOG_LEVEL)); + + if ( (globalLevel == Logger::UNSET && level < _minLevel) // no global level, use level from logger + || (globalLevel > Logger::UNSET && level < globalLevel) ) // global level set, use global level return; const size_t max_msg_length = 1024; @@ -156,38 +190,35 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u vsnprintf (msg, max_msg_length, fmt, args); va_end (args); - auto repeatedSummary = [=] + const auto repeatedSummary = [&] { - Logger::T_LOG_MESSAGE repMsg = _repeatMessage; - repMsg.message = "Previous line repeats " + QString::number(_repeatCount) + " times"; - - emit newLogMessage(repMsg); - - std::cout << QString("[" + repMsg.appName + " " + repMsg.loggerName + "] <" + LogLevelStrings[repMsg.level] + "> " + repMsg.message).toStdString() << std::endl; + Logger::T_LOG_MESSAGE repMsg = RepeatMessage.localData(); + repMsg.message = "Previous line repeats " + QString::number(RepeatCount.localData()) + " times"; + repMsg.utime = QDateTime::currentMSecsSinceEpoch(); + write(repMsg); #ifndef _WIN32 if ( _syslogEnabled && repMsg.level >= Logger::WARNING ) - syslog (LogLevelSysLog[repMsg.level], "Previous line repeats %d times", _repeatCount); + syslog (LogLevelSysLog[repMsg.level], "Previous line repeats %d times", RepeatCount.localData()); #endif - _repeatCount = 0; + RepeatCount.setLocalData(0); }; - if (_repeatMessage.loggerName == _name - && _repeatMessage.function == QString(func) - && _repeatMessage.line == line - && _repeatMessage.message == QString(msg)) + if (RepeatMessage.localData().loggerName == _name && + RepeatMessage.localData().function == func && + RepeatMessage.localData().message == msg && + RepeatMessage.localData().line == line) { - if (_repeatCount >= _maxRepeatCountSize) + if (RepeatCount.localData() >= MaxRepeatCountSize) repeatedSummary(); else - _repeatCount++; - - return; + RepeatCount.setLocalData(RepeatCount.localData() + 1); } else { - if (_repeatCount) repeatedSummary(); + if (RepeatCount.localData()) + repeatedSummary(); Logger::T_LOG_MESSAGE logMsg; @@ -196,25 +227,17 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u logMsg.function = QString(func); logMsg.line = line; logMsg.fileName = FileUtils::getBaseName(sourceFile); - time(&(logMsg.utime)); + logMsg.utime = QDateTime::currentMSecsSinceEpoch(); logMsg.message = QString(msg); logMsg.level = level; logMsg.levelString = LogLevelStrings[level]; - emit newLogMessage(logMsg); - - QString location; - if ( level == Logger::DEBUG ) - { - location = "<" + logMsg.fileName + ":" + QString::number(line)+":"+ logMsg.function + "()> "; - } - - std::cout << QString("[" + _appname + " " + _name + "] <" + LogLevelStrings[level] + "> " + location + msg).toStdString() << std::endl; + write(logMsg); #ifndef _WIN32 if ( _syslogEnabled && level >= Logger::WARNING ) syslog (LogLevelSysLog[level], "%s", msg); #endif - _repeatMessage = logMsg; + RepeatMessage.setLocalData(logMsg); } } @@ -222,14 +245,15 @@ LoggerManager::LoggerManager() : QObject() , _loggerMaxMsgBufferSize(200) { + _logMessageBuffer.reserve(_loggerMaxMsgBufferSize); } -void LoggerManager::handleNewLogMessage(const Logger::T_LOG_MESSAGE &msg) +void LoggerManager::handleNewLogMessage(const Logger::T_LOG_MESSAGE & msg) { - _logMessageBuffer.append(msg); + _logMessageBuffer.push_back(msg); if (_logMessageBuffer.length() > _loggerMaxMsgBufferSize) { - _logMessageBuffer.erase(_logMessageBuffer.begin()); + _logMessageBuffer.pop_front(); } emit newLogMessage(msg); @@ -237,7 +261,6 @@ void LoggerManager::handleNewLogMessage(const Logger::T_LOG_MESSAGE &msg) LoggerManager* LoggerManager::getInstance() { - if (_instance == nullptr) - _instance = new LoggerManager(); - return _instance; + static LoggerManager instance; + return &instance; }