From 73406c982bd721c6aad6f8c2dec2aa3729197e79 Mon Sep 17 00:00:00 2001 From: redPanther Date: Sat, 26 Nov 2016 22:34:46 +0100 Subject: [PATCH] global logbuffer (#297) * - implement a global logbuffer - providerrs232 reduce log spam * logger add signal and start json push * implement logger notifier ... need some cleanup --- include/utils/Logger.h | 49 +++++++++++- libsrc/jsonserver/JsonClientConnection.cpp | 58 +++++++++++++- libsrc/jsonserver/JsonClientConnection.h | 12 ++- libsrc/leddevice/ProviderRs232.cpp | 2 +- libsrc/utils/CMakeLists.txt | 92 ++++++++++++---------- libsrc/utils/Logger.cpp | 92 +++++++++++++++++----- libsrc/utils/Profiler.cpp | 12 +-- 7 files changed, 247 insertions(+), 70 deletions(-) diff --git a/include/utils/Logger.h b/include/utils/Logger.h index aca65aef..2b04857b 100644 --- a/include/utils/Logger.h +++ b/include/utils/Logger.h @@ -1,9 +1,17 @@ #pragma once +// QT includes +#include +#include + +// stl includes #include #include #include #include +#include + + // standard log messages //#define _FUNCNAME_ __PRETTY_FUNCTION__ @@ -22,20 +30,39 @@ // ================================================================ -class Logger +class Logger : public QObject { + Q_OBJECT + public: enum LogLevel { UNSET=0,DEBUG=1, INFO=2,WARNING=3,ERROR=4,OFF=5 }; + typedef struct + { + QString appName; + QString loggerName; + QString function; + unsigned int line; + QString fileName; + time_t utime; + QString message; + LogLevel level; + QString levelString; + } T_LOG_MESSAGE; + static Logger* getInstance(std::string name="", LogLevel minLevel=Logger::INFO); static void deleteInstance(std::string name=""); static void setLogLevel(LogLevel level,std::string name=""); static LogLevel getLogLevel(std::string name=""); + static QVector* getGlobalLogMessageBuffer() { return GlobalLogMessageBuffer; }; 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; }; +signals: + void newLogMessage(Logger::T_LOG_MESSAGE); + protected: Logger( std::string name="", LogLevel minLevel=INFO); ~Logger(); @@ -43,6 +70,8 @@ protected: private: static std::map *LoggerMap; static LogLevel GLOBAL_MIN_LOG_LEVEL; + static QVector *GlobalLogMessageBuffer; + static QVector *LogCallacks; std::string _name; std::string _appname; @@ -51,3 +80,21 @@ private: unsigned int _loggerId; }; +class LoggerNotifier : public QObject +{ + Q_OBJECT + +public: + static LoggerNotifier* getInstance(); + +protected: + LoggerNotifier(); + ~LoggerNotifier(); + + static LoggerNotifier* instance; +public slots: + void handleNewLogMessage(Logger::T_LOG_MESSAGE); + +signals: + void newLogMessage(Logger::T_LOG_MESSAGE); +}; diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index 85f42bd1..c854efaf 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -47,9 +47,11 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket) , _hyperion(Hyperion::getInstance()) , _receiveBuffer() , _webSocketHandshakeDone(false) - , _log(Logger::getInstance("JSONCLIENTCONNECTION")) + //, _log(Logger::getInstance("JSONCLIENTCONNECTION")) , _forwarder_enabled(true) + , _streaming_logging_activated(false) { + _log = Logger::getInstance("JSONCLIENTCONNECTION"); // connect internal signals and slots connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); connect(_socket, SIGNAL(readyRead()), this, SLOT(readData())); @@ -57,6 +59,9 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket) _timer_ledcolors.setSingleShot(false); connect(&_timer_ledcolors, SIGNAL(timeout()), this, SLOT(streamLedcolorsUpdate())); + + //qRegisterMetaType("Logger::T_LOG_MESSAGE"); + connect(LoggerNotifier::getInstance(),SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), this, SLOT(incommingLogMessage(Logger::T_LOG_MESSAGE))); } @@ -306,6 +311,8 @@ void JsonClientConnection::handleMessage(const QString& messageString) handleComponentStateCommand(message, command, tan); else if (command == "ledcolors") handleLedColorsCommand(message, command, tan); + else if (command == "logging") + handleLoggingCommand(message, command, tan); else handleNotImplemented(); } @@ -1204,6 +1211,55 @@ void JsonClientConnection::handleLedColorsCommand(const QJsonObject& message, co sendSuccessReply(command+"-"+subcommand,tan); } +void JsonClientConnection::handleLoggingCommand(const QJsonObject& message, const QString &command, const int tan) +{ + // create result + QString subcommand = message["subcommand"].toString(""); + _streaming_logging_reply["success"] = true; + _streaming_logging_reply["command"] = command; + _streaming_logging_reply["tan"] = tan; + + if (subcommand == "start") + { + if (!_streaming_logging_activated) + { + _streaming_logging_reply["command"] = command+"-update"; + connect(_log,SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), this, SLOT(incommingLogMessage(Logger::T_LOG_MESSAGE))); + } + } + else if (subcommand == "stop") + { + if (_streaming_logging_activated) + { + disconnect(_log, SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), this, 0); + _streaming_logging_activated = false; + } + } + else + { + sendErrorReply("unknown subcommand",command,tan); + return; + } + + sendSuccessReply(command+"-"+subcommand,tan); +} + +void JsonClientConnection::incommingLogMessage(Logger::T_LOG_MESSAGE msg) +{ + if (!_streaming_logging_activated) + { + _streaming_logging_activated = true; + QVector* logBuffer = Logger::getGlobalLogMessageBuffer(); + for(int i=0; ilength(); i++) + { + std::cout << "------- " << logBuffer->at(i).message.toStdString() << std::endl; + } + } + + std::cout << "------- " << msg.message.toStdString() << std::endl; +} + + void JsonClientConnection::handleNotImplemented() { sendErrorReply("Command not implemented"); diff --git a/libsrc/jsonserver/JsonClientConnection.h b/libsrc/jsonserver/JsonClientConnection.h index 268c3f08..f0b08676 100644 --- a/libsrc/jsonserver/JsonClientConnection.h +++ b/libsrc/jsonserver/JsonClientConnection.h @@ -40,6 +40,7 @@ public: public slots: void componentStateChanged(const hyperion::Components component, bool enable); void streamLedcolorsUpdate(); + void incommingLogMessage(Logger::T_LOG_MESSAGE); signals: /// @@ -181,6 +182,12 @@ private: /// void handleLedColorsCommand(const QJsonObject & message, const QString &command, const int tan); + /// Handle an incoming JSON Logging message + /// + /// @param message the incoming message + /// + void handleLoggingCommand(const QJsonObject & message, const QString &command, const int tan); + /// /// Handle an incoming JSON message of unknown type /// @@ -255,9 +262,12 @@ private: /// Flag if forwarder is enabled bool _forwarder_enabled; - /// + /// timer for ledcolors streaming QTimer _timer_ledcolors; + // streaming buffers QJsonObject _streaming_leds_reply; + QJsonObject _streaming_logging_reply; + bool _streaming_logging_activated; }; diff --git a/libsrc/leddevice/ProviderRs232.cpp b/libsrc/leddevice/ProviderRs232.cpp index 8ffaff1f..e3e53906 100644 --- a/libsrc/leddevice/ProviderRs232.cpp +++ b/libsrc/leddevice/ProviderRs232.cpp @@ -166,7 +166,7 @@ int ProviderRs232::writeBytes(const qint64 size, const uint8_t * data) return tryOpen(5000) ? 0 : -1; } - if (_frameDropCounter > 0) + if (_frameDropCounter > 5) { Debug(_log, "%d frames dropped", _frameDropCounter); } diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index 4d821dc6..311a3ae2 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -1,54 +1,64 @@ # Define the current source locations + SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils) SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/utils) +SET(Utils_QT_HEADERS + ${CURRENT_HEADER_DIR}/Logger.h +) + +SET(Utils_HEADERS + ${CURRENT_HEADER_DIR}/ColorBgr.h + ${CURRENT_HEADER_DIR}/ColorRgb.h + ${CURRENT_HEADER_DIR}/ColorRgba.h + ${CURRENT_HEADER_DIR}/ColorRgbw.h + ${CURRENT_HEADER_DIR}/Image.h + ${CURRENT_HEADER_DIR}/Sleep.h + ${CURRENT_HEADER_DIR}/FileUtils.h + ${CURRENT_HEADER_DIR}/Process.h + ${CURRENT_HEADER_DIR}/PixelFormat.h + ${CURRENT_HEADER_DIR}/VideoMode.h + ${CURRENT_HEADER_DIR}/ImageResampler.h + ${CURRENT_HEADER_DIR}/HsvTransform.h + ${CURRENT_HEADER_DIR}/HslTransform.h + ${CURRENT_HEADER_DIR}/RgbChannelTransform.h + ${CURRENT_HEADER_DIR}/RgbChannelAdjustment.h + ${CURRENT_HEADER_DIR}/RgbToRgbw.h + ${CURRENT_HEADER_DIR}/jsonschema/QJsonFactory.h + ${CURRENT_HEADER_DIR}/jsonschema/QJsonSchemaChecker.h +) + +SET(Utils_SOURCES + ${CURRENT_SOURCE_DIR}/ColorArgb.cpp + ${CURRENT_SOURCE_DIR}/ColorBgr.cpp + ${CURRENT_SOURCE_DIR}/ColorRgb.cpp + ${CURRENT_SOURCE_DIR}/ColorRgba.cpp + ${CURRENT_SOURCE_DIR}/ColorRgbw.cpp + ${CURRENT_SOURCE_DIR}/FileUtils.cpp + ${CURRENT_SOURCE_DIR}/Process.cpp + ${CURRENT_SOURCE_DIR}/Logger.cpp + ${CURRENT_SOURCE_DIR}/ImageResampler.cpp + ${CURRENT_SOURCE_DIR}/HsvTransform.cpp + ${CURRENT_SOURCE_DIR}/HslTransform.cpp + ${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp + ${CURRENT_SOURCE_DIR}/RgbChannelAdjustment.cpp + ${CURRENT_SOURCE_DIR}/RgbToRgbw.cpp + ${CURRENT_SOURCE_DIR}/jsonschema/QJsonSchemaChecker.cpp +) + if ( ENABLE_PROFILER ) SET ( PROFILER_SOURCE ${CURRENT_HEADER_DIR}/Profiler.h ${CURRENT_SOURCE_DIR}/Profiler.cpp ) endif() +qt5_wrap_cpp(Utils_HEADERS_MOC ${Utils_QT_HEADERS}) + + add_library(hyperion-utils - ${CURRENT_HEADER_DIR}/ColorArgb.h - ${CURRENT_SOURCE_DIR}/ColorArgb.cpp - ${CURRENT_HEADER_DIR}/ColorBgr.h - ${CURRENT_SOURCE_DIR}/ColorBgr.cpp - ${CURRENT_HEADER_DIR}/ColorRgb.h - ${CURRENT_SOURCE_DIR}/ColorRgb.cpp - ${CURRENT_HEADER_DIR}/ColorRgba.h - ${CURRENT_SOURCE_DIR}/ColorRgba.cpp - ${CURRENT_HEADER_DIR}/ColorRgbw.h - ${CURRENT_SOURCE_DIR}/ColorRgbw.cpp - ${CURRENT_HEADER_DIR}/Image.h - ${CURRENT_HEADER_DIR}/Sleep.h - ${CURRENT_HEADER_DIR}/FileUtils.h - ${CURRENT_SOURCE_DIR}/FileUtils.cpp - ${CURRENT_HEADER_DIR}/Process.h - ${CURRENT_SOURCE_DIR}/Process.cpp - - ${CURRENT_HEADER_DIR}/Logger.h - ${CURRENT_SOURCE_DIR}/Logger.cpp + ${Utils_QT_HEADERS} + ${Utils_HEADERS_MOC} + ${Utils_HEADERS} + ${Utils_SOURCES} ${PROFILER_SOURCE} - - ${CURRENT_HEADER_DIR}/PixelFormat.h - ${CURRENT_HEADER_DIR}/VideoMode.h - - ${CURRENT_HEADER_DIR}/ImageResampler.h - ${CURRENT_SOURCE_DIR}/ImageResampler.cpp - - ${CURRENT_HEADER_DIR}/HsvTransform.h - ${CURRENT_SOURCE_DIR}/HsvTransform.cpp - ${CURRENT_HEADER_DIR}/HslTransform.h - ${CURRENT_SOURCE_DIR}/HslTransform.cpp - ${CURRENT_HEADER_DIR}/RgbChannelTransform.h - ${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp - ${CURRENT_HEADER_DIR}/RgbChannelAdjustment.h - ${CURRENT_SOURCE_DIR}/RgbChannelAdjustment.cpp - - ${CURRENT_HEADER_DIR}/RgbToRgbw.h - ${CURRENT_SOURCE_DIR}/RgbToRgbw.cpp - - ${CURRENT_HEADER_DIR}/jsonschema/QJsonFactory.h - ${CURRENT_HEADER_DIR}/jsonschema/QJsonSchemaChecker.h - ${CURRENT_SOURCE_DIR}/jsonschema/QJsonSchemaChecker.cpp ) qt5_use_modules(hyperion-utils Core) diff --git a/libsrc/utils/Logger.cpp b/libsrc/utils/Logger.cpp index d4f05823..271bfbd3 100644 --- a/libsrc/utils/Logger.cpp +++ b/libsrc/utils/Logger.cpp @@ -4,22 +4,25 @@ #include #include #include -#include #include -#include +#include - -static const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" }; -static const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR }; -static unsigned int loggerCount = 0; -static unsigned int loggerId = 0; +static const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" }; +static const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR }; +static unsigned int loggerCount = 0; +static unsigned int loggerId = 0; +static const int loggerMaxMsgBufferSize = 50; std::map *Logger::LoggerMap = nullptr; Logger::LogLevel Logger::GLOBAL_MIN_LOG_LEVEL = Logger::UNSET; +QVector *Logger::GlobalLogMessageBuffer = nullptr; + +LoggerNotifier* LoggerNotifier::instance = nullptr; Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel) { + Logger* log = nullptr; if (LoggerMap == nullptr) { LoggerMap = new std::map; @@ -27,13 +30,22 @@ Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel) if ( LoggerMap->find(name) == LoggerMap->end() ) { - Logger* log = new Logger(name,minLevel); + 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 - return log; - } - - return LoggerMap->at(name); + connect(log, SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), LoggerNotifier::getInstance(), SLOT(handleNewLogMessage(Logger::T_LOG_MESSAGE))); + } + else + { + log = LoggerMap->at(name); + } + + if (GlobalLogMessageBuffer == nullptr) + { + GlobalLogMessageBuffer = new QVector; + } + + return log; } void Logger::deleteInstance(std::string name) @@ -82,11 +94,12 @@ Logger::LogLevel Logger::getLogLevel(std::string name) return log->getMinLevel(); } -Logger::Logger ( std::string name, LogLevel minLevel ): - _name(name), - _minLevel(minLevel), - _syslogEnabled(true), - _loggerId(loggerId++) +Logger::Logger ( std::string name, LogLevel minLevel ) + : QObject() + , _name(name) + , _minLevel(minLevel) + , _syslogEnabled(true) + , _loggerId(loggerId++) { #ifdef __GLIBC__ const char* _appname_char = program_invocation_short_name; @@ -126,13 +139,32 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u vsnprintf (msg, max_msg_length, fmt, args); va_end (args); + Logger::T_LOG_MESSAGE logMsg; + + logMsg.appName = QString::fromStdString(_appname); + logMsg.loggerName = QString::fromStdString(_name); + logMsg.function = QString(func); + logMsg.line = line; + logMsg.fileName = FileUtils::getBaseName(sourceFile); + time(&(logMsg.utime)); + logMsg.message = QString(msg); + logMsg.level = level; + logMsg.levelString = QString::fromStdString(LogLevelStrings[level]); + + emit newLogMessage(logMsg); + QString location; - QString function(func); if ( level == Logger::DEBUG ) { - location = "<" + FileUtils::getBaseName(sourceFile) + ":" + QString::number(line)+":"+ function + "()> "; + location = "<" + logMsg.fileName + ":" + QString::number(line)+":"+ logMsg.function + "()> "; } + GlobalLogMessageBuffer->append(logMsg); + if (GlobalLogMessageBuffer->length() > loggerMaxMsgBufferSize) + { + GlobalLogMessageBuffer->erase(GlobalLogMessageBuffer->begin()); + } + std::cout << "[" << _appname << " " << _name << "] <" << LogLevelStrings[level] << "> " << location.toStdString() << msg @@ -143,3 +175,25 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u } +LoggerNotifier::LoggerNotifier() + : QObject() +{ +} + +LoggerNotifier::~LoggerNotifier() +{ +} + + +void LoggerNotifier::handleNewLogMessage(Logger::T_LOG_MESSAGE msg) +{ + //std::cout << "<" << msg.loggerName.toStdString() << "> " << msg.message.toStdString() << std::endl; + emit newLogMessage(msg); +} + +LoggerNotifier* LoggerNotifier::getInstance() +{ + if ( instance == nullptr ) + instance = new LoggerNotifier(); + return instance; +} diff --git a/libsrc/utils/Profiler.cpp b/libsrc/utils/Profiler.cpp index e3393082..70c207fe 100644 --- a/libsrc/utils/Profiler.cpp +++ b/libsrc/utils/Profiler.cpp @@ -21,12 +21,12 @@ double getClockDelta(clock_t start) return ((double)(clock() - start) / CLOCKS_PER_SEC) ; } -Profiler::Profiler(const char* sourceFile, const char* func, unsigned int line) : - _file(sourceFile), - _func(func), - _line(line), - _blockId(blockCounter++), - _startTime(clock()) +Profiler::Profiler(const char* sourceFile, const char* func, unsigned int line) + : _file(sourceFile) + , _func(func) + , _line(line) + , _blockId(blockCounter++) + , _startTime(clock()) { Profiler::initLogger(); _logger->Message(Logger::DEBUG,_file,_func,_line,">>> enter block %d", _blockId);