Logbuffer (#298)

* - implement a global logbuffer
- providerrs232 reduce log spam

* logger add signal and start json push

* implement logger notifier ... need some cleanup

* imlement logview in webui - the layout stuff is basic atm and needs some tuning
This commit is contained in:
redPanther 2016-11-26 22:46:16 +01:00 committed by GitHub
parent 73406c982b
commit 1b62d9d717
13 changed files with 265 additions and 159 deletions

View File

@ -1,4 +1,5 @@
<div class="container-fluid">
<div class="container-fluid" id="content_dashboard">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<h2 class="page-header"><i class="fa fa-dashboard fa-fw"></i><span lang="en" data-lang-token="main_menu_dashboard_token">Dashboard</span></h2> <h2 class="page-header"><i class="fa fa-dashboard fa-fw"></i><span lang="en" data-lang-token="main_menu_dashboard_token">Dashboard</span></h2>

View File

@ -0,0 +1,19 @@
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<h2 class="page-header"><i class="fa fa-play-circle-o fa-fw"></i><span lang="en" data-lang-token="conf_kodi_label_title">Log Messages</span></h2>
<div class="introd">
<h4 lang="en" data-lang-token="conf_logging_label_intro">log messages.</h4>
</div>
<hr />
<div class="col-lg-12">
<div id="logmessages" style="white-space:pre">
</div>
</div>
</div>
</div>
</div>
<script src="/js/content_logging.js"></script>

View File

@ -220,6 +220,7 @@
<li> <li>
<a class="inactive"><i class="fa fa-industry fa-fw"></i><span lang="en" data-lang-token="main_menu_system_token">System</span><span class="fa arrow"></span></a> <a class="inactive"><i class="fa fa-industry fa-fw"></i><span lang="en" data-lang-token="main_menu_system_token">System</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li> <a class="inactive" id="load_logging"><i class="fa fa-download fa-fw"></i><span lang="en" data-lang-token="main_menu_logging_token">Events</span></a> </li>
<li> <a class="inactive" id="load_update"><i class="fa fa-download fa-fw"></i><span lang="en" data-lang-token="main_menu_update_token">Update</span></a> </li> <li> <a class="inactive" id="load_update"><i class="fa fa-download fa-fw"></i><span lang="en" data-lang-token="main_menu_update_token">Update</span></a> </li>
</ul> </ul>
</li> </li>

View File

@ -15,6 +15,7 @@ $(document).ready( function() {
bindNavToContent("#load_confColors","colors",false); bindNavToContent("#load_confColors","colors",false);
bindNavToContent("#load_confNetwork","network",false); bindNavToContent("#load_confNetwork","network",false);
bindNavToContent("#load_effectsconfig","effects_configurator",false); bindNavToContent("#load_effectsconfig","effects_configurator",false);
bindNavToContent("#load_logging","logging",false);
//Change all Checkboxes to Switches //Change all Checkboxes to Switches
@ -32,16 +33,25 @@ $(document).ready( function() {
// get active led device // get active led device
var leddevice = parsedServerInfoJSON.info.ledDevices.active; var leddevice = parsedServerInfoJSON.info.ledDevices.active;
if ($("#content_dashboard").length > 0)
{
$('#dash_leddevice').html(leddevice); $('#dash_leddevice').html(leddevice);
}
// get host // get host
var hostname = parsedServerInfoJSON.info.hostname; var hostname = parsedServerInfoJSON.info.hostname;
if ($("#content_dashboard").length > 0)
{
$('#dash_systeminfo').html(hostname+':'+hyperionport); $('#dash_systeminfo').html(hostname+':'+hyperionport);
}
if ($("#content_dashboard").length > 0)
{
var components = parsedServerInfoJSON.info.components; var components = parsedServerInfoJSON.info.components;
components_html = ""; components_html = "";
for ( idx=0; idx<components.length;idx++) for ( idx=0; idx<components.length;idx++)
{ {
console.log()
components_html += '<tr><td lang="en" data-lang-token="general_comp_'+components[idx].name+'">'+(components[idx].title)+'</td><td><i class="fa fa-circle component-'+(components[idx].enabled?"on":"off")+'"></i></td></tr>'; components_html += '<tr><td lang="en" data-lang-token="general_comp_'+components[idx].name+'">'+(components[idx].title)+'</td><td><i class="fa fa-circle component-'+(components[idx].enabled?"on":"off")+'"></i></td></tr>';
} }
$("#tab_components").html(components_html); $("#tab_components").html(components_html);
@ -63,6 +73,14 @@ $(document).ready( function() {
$('#versioninforesult').html('<div lang="en" data-lang-token="dashboard_infobox_message_updatesuccess" style="margin:0px;" class="alert alert-success">You run the latest version of Hyperion.</div>'); $('#versioninforesult').html('<div lang="en" data-lang-token="dashboard_infobox_message_updatesuccess" style="margin:0px;" class="alert alert-success">You run the latest version of Hyperion.</div>');
} }
}); });
}
if ($("#logmessages").length == 0)
{
requestLoggingStop();
}
$("#loading_overlay").removeClass("overlay"); $("#loading_overlay").removeClass("overlay");
$("#main-nav").show('slide', {direction: 'left'}, 1000); $("#main-nav").show('slide', {direction: 'left'}, 1000);

View File

@ -0,0 +1,24 @@
$(document).ready(function() {
requestLoggingStart();
if (!loggingHandlerInstalled)
{
loggingHandlerInstalled = true;
$(hyperion).on("cmd-logging-update",function(event){
if ($("#logmessages").length == 0)
{
requestLoggingStop();
}
else
{
messages = (event.response.result.messages);
for(var idx=0; idx<messages.length; idx++)
{
msg = messages[idx];
$("#logmessages").html($("#logmessages").html()+"\n"+msg);
}
}
});
}
});

View File

@ -36,6 +36,8 @@ var hyperion = {};
var wsTan = 1; var wsTan = 1;
var cronId = 0; var cronId = 0;
var ledStreamActive=false; var ledStreamActive=false;
var loggingStreamActive=false;
var loggingHandlerInstalled = false;
var watchdog = 0; var watchdog = 0;
// //
@ -215,5 +217,16 @@ function requestTestEffect(effectName,effectPy,effectArgs) {
} }
function requestDeleteEffect(effectName) { function requestDeleteEffect(effectName) {
websocket.send('{"command":"delete-effect","name":"'+effectName+'"}'); websocket.send('{"command":"delete-effect", "tan":'+wsTan+',"name":"'+effectName+'"}');
} }
function requestLoggingStart() {
loggingStreamActive=true;
websocket.send('{"command":"logging", "tan":'+wsTan+',"subcommand":"start"}');
}
function requestLoggingStop() {
loggingStreamActive=false;
websocket.send('{"command":"logging", "tan":'+wsTan+',"subcommand":"stop"}');
}

View File

@ -54,7 +54,6 @@ public:
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; };
@ -70,8 +69,6 @@ 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;
@ -80,21 +77,25 @@ private:
unsigned int _loggerId; unsigned int _loggerId;
}; };
class LoggerNotifier : public QObject
class LoggerManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static LoggerNotifier* getInstance(); static LoggerManager* getInstance();
QVector<Logger::T_LOG_MESSAGE>* getLogMessageBuffer() { return &_logMessageBuffer; };
protected:
LoggerNotifier();
~LoggerNotifier();
static LoggerNotifier* instance;
public slots: public slots:
void handleNewLogMessage(Logger::T_LOG_MESSAGE); void handleNewLogMessage(Logger::T_LOG_MESSAGE);
signals: signals:
void newLogMessage(Logger::T_LOG_MESSAGE); void newLogMessage(Logger::T_LOG_MESSAGE);
protected:
LoggerManager();
static LoggerManager* _instance;
QVector<Logger::T_LOG_MESSAGE> _logMessageBuffer;
const int _loggerMaxMsgBufferSize;
}; };

View File

@ -47,11 +47,10 @@ 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) , _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()));
@ -59,9 +58,6 @@ 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)));
} }
@ -1224,15 +1220,18 @@ void JsonClientConnection::handleLoggingCommand(const QJsonObject& message, cons
if (!_streaming_logging_activated) if (!_streaming_logging_activated)
{ {
_streaming_logging_reply["command"] = command+"-update"; _streaming_logging_reply["command"] = command+"-update";
connect(_log,SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), this, SLOT(incommingLogMessage(Logger::T_LOG_MESSAGE))); connect(LoggerManager::getInstance(),SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), this, SLOT(incommingLogMessage(Logger::T_LOG_MESSAGE)));
Debug(_log, "log streaming activated"); // needed to trigger log sending
} }
} }
else if (subcommand == "stop") else if (subcommand == "stop")
{ {
if (_streaming_logging_activated) if (_streaming_logging_activated)
{ {
disconnect(_log, SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), this, 0); disconnect(LoggerManager::getInstance(), SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), this, 0);
_streaming_logging_activated = false; _streaming_logging_activated = false;
Debug(_log, "log streaming deactivated");
} }
} }
else else
@ -1246,17 +1245,30 @@ void JsonClientConnection::handleLoggingCommand(const QJsonObject& message, cons
void JsonClientConnection::incommingLogMessage(Logger::T_LOG_MESSAGE msg) void JsonClientConnection::incommingLogMessage(Logger::T_LOG_MESSAGE msg)
{ {
QJsonObject result;
QJsonArray messages;
if (!_streaming_logging_activated) if (!_streaming_logging_activated)
{ {
_streaming_logging_activated = true; _streaming_logging_activated = true;
QVector<Logger::T_LOG_MESSAGE>* logBuffer = Logger::getGlobalLogMessageBuffer(); QVector<Logger::T_LOG_MESSAGE>* logBuffer = LoggerManager::getInstance()->getLogMessageBuffer();
for(int i=0; i<logBuffer->length(); i++) for(int i=0; i<logBuffer->length(); i++)
{ {
std::cout << "------- " << logBuffer->at(i).message.toStdString() << std::endl; //std::cout << "------- " << logBuffer->at(i).message.toStdString() << std::endl;
messages.append(logBuffer->at(i).message);
} }
} }
else
{
//std::cout << "------- " << msg.message.toStdString() << std::endl;
messages.append(msg.message);
}
std::cout << "------- " << msg.message.toStdString() << std::endl; result["messages"] = messages;
_streaming_logging_reply["result"] = result;
// send the result
sendMessage(_streaming_logging_reply);
} }

View File

@ -17,5 +17,6 @@
<file alias="schema-config">schema/schema-config.json</file> <file alias="schema-config">schema/schema-config.json</file>
<file alias="schema-componentstate">schema/schema-componentstate.json</file> <file alias="schema-componentstate">schema/schema-componentstate.json</file>
<file alias="schema-ledcolors">schema/schema-ledcolors.json</file> <file alias="schema-ledcolors">schema/schema-ledcolors.json</file>
<file alias="schema-logging">schema/schema-logging.json</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -0,0 +1,28 @@
{
"type":"object",
"required":true,
"properties":{
"command": {
"type" : "string",
"required" : true,
"enum" : ["logging"]
},
"tan" : {
"type" : "integer"
},
"subcommand": {
"type" : "string",
"required" : true,
"enum" : ["stop","start","update"]
},
"oneshot": {
"type" : "bool"
},
"interval": {
"type" : "integer"
}
},
"additionalProperties": false
}

View File

@ -5,7 +5,7 @@
"command": { "command": {
"type" : "string", "type" : "string",
"required" : true, "required" : true,
"enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "transform", "correction", "temperature", "adjustment", "sourceselect", "config", "componentstate", "ledcolors"] "enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "transform", "correction", "temperature", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging"]
} }
} }
} }

View File

@ -15,9 +15,7 @@ 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; LoggerManager* LoggerManager::_instance = nullptr;
LoggerNotifier* LoggerNotifier::instance = nullptr;
Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel) Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel)
@ -33,18 +31,13 @@ Logger* Logger::getInstance(std::string name, Logger::LogLevel minLevel)
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
connect(log, SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), LoggerNotifier::getInstance(), SLOT(handleNewLogMessage(Logger::T_LOG_MESSAGE))); connect(log, SIGNAL(newLogMessage(Logger::T_LOG_MESSAGE)), LoggerManager::getInstance(), SLOT(handleNewLogMessage(Logger::T_LOG_MESSAGE)));
} }
else else
{ {
log = LoggerMap->at(name); log = LoggerMap->at(name);
} }
if (GlobalLogMessageBuffer == nullptr)
{
GlobalLogMessageBuffer = new QVector<Logger::T_LOG_MESSAGE>;
}
return log; return log;
} }
@ -159,12 +152,6 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u
location = "<" + logMsg.fileName + ":" + QString::number(line)+":"+ logMsg.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
@ -175,25 +162,26 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u
} }
LoggerNotifier::LoggerNotifier() LoggerManager::LoggerManager()
: QObject() : QObject()
, _loggerMaxMsgBufferSize(200)
{ {
} }
LoggerNotifier::~LoggerNotifier() void LoggerManager::handleNewLogMessage(Logger::T_LOG_MESSAGE msg)
{ {
_logMessageBuffer.append(msg);
if (_logMessageBuffer.length() > _loggerMaxMsgBufferSize)
{
_logMessageBuffer.erase(_logMessageBuffer.begin());
} }
void LoggerNotifier::handleNewLogMessage(Logger::T_LOG_MESSAGE msg)
{
//std::cout << "<" << msg.loggerName.toStdString() << "> " << msg.message.toStdString() << std::endl;
emit newLogMessage(msg); emit newLogMessage(msg);
} }
LoggerNotifier* LoggerNotifier::getInstance() LoggerManager* LoggerManager::getInstance()
{ {
if ( instance == nullptr ) if ( _instance == nullptr )
instance = new LoggerNotifier(); _instance = new LoggerManager();
return instance; return _instance;
} }