global logbuffer (#297)

* - implement a global logbuffer
- providerrs232 reduce log spam

* logger add signal and start json push

* implement logger notifier ... need some cleanup
This commit is contained in:
redPanther 2016-11-26 22:34:46 +01:00 committed by GitHub
parent 9360183f2e
commit 73406c982b
7 changed files with 247 additions and 70 deletions

View File

@ -1,9 +1,17 @@
#pragma once #pragma once
// QT includes
#include <QObject>
#include <QString>
// stl includes
#include <string> #include <string>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <map> #include <map>
#include <QVector>
// standard log messages // standard log messages
//#define _FUNCNAME_ __PRETTY_FUNCTION__ //#define _FUNCNAME_ __PRETTY_FUNCTION__
@ -22,20 +30,39 @@
// ================================================================ // ================================================================
class Logger class Logger : public QObject
{ {
Q_OBJECT
public: public:
enum LogLevel { UNSET=0,DEBUG=1, INFO=2,WARNING=3,ERROR=4,OFF=5 }; 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 Logger* getInstance(std::string name="", LogLevel minLevel=Logger::INFO);
static void deleteInstance(std::string name=""); static void deleteInstance(std::string name="");
static void setLogLevel(LogLevel level,std::string name=""); static void setLogLevel(LogLevel level,std::string name="");
static LogLevel getLogLevel(std::string name=""); static LogLevel getLogLevel(std::string name="");
static QVector<Logger::T_LOG_MESSAGE>* getGlobalLogMessageBuffer() { return GlobalLogMessageBuffer; };
void Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...); void Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...);
void setMinLevel(LogLevel level) { _minLevel = level; }; void setMinLevel(LogLevel level) { _minLevel = level; };
LogLevel getMinLevel() { return _minLevel; }; LogLevel getMinLevel() { return _minLevel; };
signals:
void newLogMessage(Logger::T_LOG_MESSAGE);
protected: protected:
Logger( std::string name="", LogLevel minLevel=INFO); Logger( std::string name="", LogLevel minLevel=INFO);
~Logger(); ~Logger();
@ -43,6 +70,8 @@ protected:
private: private:
static std::map<std::string,Logger*> *LoggerMap; static std::map<std::string,Logger*> *LoggerMap;
static LogLevel GLOBAL_MIN_LOG_LEVEL; static LogLevel GLOBAL_MIN_LOG_LEVEL;
static QVector<T_LOG_MESSAGE> *GlobalLogMessageBuffer;
static QVector<T_LOG_MESSAGE> *LogCallacks;
std::string _name; std::string _name;
std::string _appname; std::string _appname;
@ -51,3 +80,21 @@ private:
unsigned int _loggerId; 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);
};

View File

@ -47,9 +47,11 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket)
, _hyperion(Hyperion::getInstance()) , _hyperion(Hyperion::getInstance())
, _receiveBuffer() , _receiveBuffer()
, _webSocketHandshakeDone(false) , _webSocketHandshakeDone(false)
, _log(Logger::getInstance("JSONCLIENTCONNECTION")) //, _log(Logger::getInstance("JSONCLIENTCONNECTION"))
, _forwarder_enabled(true) , _forwarder_enabled(true)
, _streaming_logging_activated(false)
{ {
_log = Logger::getInstance("JSONCLIENTCONNECTION");
// connect internal signals and slots // connect internal signals and slots
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData())); connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
@ -57,6 +59,9 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket)
_timer_ledcolors.setSingleShot(false); _timer_ledcolors.setSingleShot(false);
connect(&_timer_ledcolors, SIGNAL(timeout()), this, SLOT(streamLedcolorsUpdate())); connect(&_timer_ledcolors, SIGNAL(timeout()), this, SLOT(streamLedcolorsUpdate()));
//qRegisterMetaType<Logger::T_LOG_MESSAGE>("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); handleComponentStateCommand(message, command, tan);
else if (command == "ledcolors") else if (command == "ledcolors")
handleLedColorsCommand(message, command, tan); handleLedColorsCommand(message, command, tan);
else if (command == "logging")
handleLoggingCommand(message, command, tan);
else else
handleNotImplemented(); handleNotImplemented();
} }
@ -1204,6 +1211,55 @@ void JsonClientConnection::handleLedColorsCommand(const QJsonObject& message, co
sendSuccessReply(command+"-"+subcommand,tan); 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<Logger::T_LOG_MESSAGE>* logBuffer = Logger::getGlobalLogMessageBuffer();
for(int i=0; i<logBuffer->length(); i++)
{
std::cout << "------- " << logBuffer->at(i).message.toStdString() << std::endl;
}
}
std::cout << "------- " << msg.message.toStdString() << std::endl;
}
void JsonClientConnection::handleNotImplemented() void JsonClientConnection::handleNotImplemented()
{ {
sendErrorReply("Command not implemented"); sendErrorReply("Command not implemented");

View File

@ -40,6 +40,7 @@ public:
public slots: public slots:
void componentStateChanged(const hyperion::Components component, bool enable); void componentStateChanged(const hyperion::Components component, bool enable);
void streamLedcolorsUpdate(); void streamLedcolorsUpdate();
void incommingLogMessage(Logger::T_LOG_MESSAGE);
signals: signals:
/// ///
@ -181,6 +182,12 @@ private:
/// ///
void handleLedColorsCommand(const QJsonObject & message, const QString &command, const int tan); 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 /// Handle an incoming JSON message of unknown type
/// ///
@ -255,9 +262,12 @@ private:
/// Flag if forwarder is enabled /// Flag if forwarder is enabled
bool _forwarder_enabled; bool _forwarder_enabled;
/// /// timer for ledcolors streaming
QTimer _timer_ledcolors; QTimer _timer_ledcolors;
// streaming buffers
QJsonObject _streaming_leds_reply; QJsonObject _streaming_leds_reply;
QJsonObject _streaming_logging_reply;
bool _streaming_logging_activated;
}; };

View File

@ -166,7 +166,7 @@ int ProviderRs232::writeBytes(const qint64 size, const uint8_t * data)
return tryOpen(5000) ? 0 : -1; return tryOpen(5000) ? 0 : -1;
} }
if (_frameDropCounter > 0) if (_frameDropCounter > 5)
{ {
Debug(_log, "%d frames dropped", _frameDropCounter); Debug(_log, "%d frames dropped", _frameDropCounter);
} }

View File

@ -1,54 +1,64 @@
# Define the current source locations # Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils) SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/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 ) if ( ENABLE_PROFILER )
SET ( PROFILER_SOURCE ${CURRENT_HEADER_DIR}/Profiler.h ${CURRENT_SOURCE_DIR}/Profiler.cpp ) SET ( PROFILER_SOURCE ${CURRENT_HEADER_DIR}/Profiler.h ${CURRENT_SOURCE_DIR}/Profiler.cpp )
endif() endif()
qt5_wrap_cpp(Utils_HEADERS_MOC ${Utils_QT_HEADERS})
add_library(hyperion-utils add_library(hyperion-utils
${CURRENT_HEADER_DIR}/ColorArgb.h ${Utils_QT_HEADERS}
${CURRENT_SOURCE_DIR}/ColorArgb.cpp ${Utils_HEADERS_MOC}
${CURRENT_HEADER_DIR}/ColorBgr.h ${Utils_HEADERS}
${CURRENT_SOURCE_DIR}/ColorBgr.cpp ${Utils_SOURCES}
${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
${PROFILER_SOURCE} ${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) qt5_use_modules(hyperion-utils Core)

View File

@ -4,22 +4,25 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <syslog.h> #include <syslog.h>
#include <map>
#include <QFileInfo> #include <QFileInfo>
#include <QString> #include <time.h>
static const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" };
static const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" }; static const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR };
static const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR }; static unsigned int loggerCount = 0;
static unsigned int loggerCount = 0; static unsigned int loggerId = 0;
static unsigned int loggerId = 0; static const int loggerMaxMsgBufferSize = 50;
std::map<std::string,Logger*> *Logger::LoggerMap = nullptr; std::map<std::string,Logger*> *Logger::LoggerMap = nullptr;
Logger::LogLevel Logger::GLOBAL_MIN_LOG_LEVEL = Logger::UNSET; Logger::LogLevel Logger::GLOBAL_MIN_LOG_LEVEL = Logger::UNSET;
QVector<Logger::T_LOG_MESSAGE> *Logger::GlobalLogMessageBuffer = nullptr;
LoggerNotifier* LoggerNotifier::instance = nullptr;
Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel) Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel)
{ {
Logger* log = nullptr;
if (LoggerMap == nullptr) if (LoggerMap == nullptr)
{ {
LoggerMap = new std::map<std::string,Logger*>; LoggerMap = new std::map<std::string,Logger*>;
@ -27,13 +30,22 @@ Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel)
if ( LoggerMap->find(name) == LoggerMap->end() ) if ( LoggerMap->find(name) == LoggerMap->end() )
{ {
Logger* log = new Logger(name,minLevel); log = new Logger(name,minLevel);
LoggerMap->insert(std::pair<std::string,Logger*>(name,log)); // compat version, replace it with following line if we have 100% c++11 LoggerMap->insert(std::pair<std::string,Logger*>(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 //LoggerMap->emplace(name,log); // not compat with older linux distro's e.g. wheezy
return log; connect(log, SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), LoggerNotifier::getInstance(), SLOT(handleNewLogMessage(Logger::T_LOG_MESSAGE)));
} }
else
return LoggerMap->at(name); {
log = LoggerMap->at(name);
}
if (GlobalLogMessageBuffer == nullptr)
{
GlobalLogMessageBuffer = new QVector<Logger::T_LOG_MESSAGE>;
}
return log;
} }
void Logger::deleteInstance(std::string name) void Logger::deleteInstance(std::string name)
@ -82,11 +94,12 @@ Logger::LogLevel Logger::getLogLevel(std::string name)
return log->getMinLevel(); return log->getMinLevel();
} }
Logger::Logger ( std::string name, LogLevel minLevel ): Logger::Logger ( std::string name, LogLevel minLevel )
_name(name), : QObject()
_minLevel(minLevel), , _name(name)
_syslogEnabled(true), , _minLevel(minLevel)
_loggerId(loggerId++) , _syslogEnabled(true)
, _loggerId(loggerId++)
{ {
#ifdef __GLIBC__ #ifdef __GLIBC__
const char* _appname_char = program_invocation_short_name; 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); vsnprintf (msg, max_msg_length, fmt, args);
va_end (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 location;
QString function(func);
if ( level == Logger::DEBUG ) 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 std::cout
<< "[" << _appname << " " << _name << "] <" << "[" << _appname << " " << _name << "] <"
<< LogLevelStrings[level] << "> " << location.toStdString() << msg << 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;
}

View File

@ -21,12 +21,12 @@ double getClockDelta(clock_t start)
return ((double)(clock() - start) / CLOCKS_PER_SEC) ; return ((double)(clock() - start) / CLOCKS_PER_SEC) ;
} }
Profiler::Profiler(const char* sourceFile, const char* func, unsigned int line) : Profiler::Profiler(const char* sourceFile, const char* func, unsigned int line)
_file(sourceFile), : _file(sourceFile)
_func(func), , _func(func)
_line(line), , _line(line)
_blockId(blockCounter++), , _blockId(blockCounter++)
_startTime(clock()) , _startTime(clock())
{ {
Profiler::initLogger(); Profiler::initLogger();
_logger->Message(Logger::DEBUG,_file,_func,_line,">>> enter block %d", _blockId); _logger->Message(Logger::DEBUG,_file,_func,_line,">>> enter block %d", _blockId);