From ed80e8a43643c8a55080414ff9d11ed846517dbf Mon Sep 17 00:00:00 2001 From: BenDr0id Date: Fri, 27 Jul 2018 17:18:57 +0200 Subject: [PATCH] WIP --- index.html | 37 +++++++++++----- src/App.cpp | 3 +- src/Options.cpp | 10 +++++ src/Options.h | 2 + src/cc/ClientStatus.cpp | 5 +++ src/cc/ClientStatus.h | 3 +- src/cc/Service.cpp | 93 +++++++++++++++++++++++++++-------------- src/cc/Service.h | 6 ++- src/config_cc.json | 1 + src/log/Log.cpp | 1 - src/log/RemoteLog.cpp | 4 +- src/log/RemoteLog.h | 2 +- 12 files changed, 117 insertions(+), 50 deletions(-) diff --git a/index.html b/index.html index 2c6d5613..934a6d3f 100644 --- a/index.html +++ b/index.html @@ -411,15 +411,24 @@ var data = table.row( $(this).parents('tr') ).data(); var clientId = data['client_status']['client_id']; var clientIp = data['client_status']['external_ip']; - var log = data['client_status']['log']; - var htmlContent = "
" + - ""+ - "" + - "
"; + $.ajax({ + type: "GET", + url: "/admin/getClientLog?clientId=" + clientId, + dataType:"json", + success: function(jsonClientLog) { + var htmlContent = "
" + + ""+ + "" + + "
"; - $('#minerLog').find('.modal-body').html(htmlContent); - $('#minerLog').modal('show'); + $('#minerLog').find('.modal-body').html(htmlContent); + $('#minerLog').modal('show'); + }, + error: function (data) { + setError('Unable to fetch ' + clientId + ' log. - Please make sure it is enabled on the miner!'); + } + }); }); $('#minerLogRefresh').click(function(event) { @@ -429,9 +438,17 @@ var row = table.row(index); var data = row.data(); - if (clientId === data.client_status.client_id) { - $('#log').val(data.client_status.log); - } + $.ajax({ + type: "GET", + url: "/admin/getClientLog?clientId=" + clientId, + dataType:"json", + success: function(jsonClientLog) { + $('#log').val(JSON.stringify(jsonClientLog,undefined, 2)); + }, + error: function (data) { + setError('Unable to fetch ' + clientId + ' log. - Please make sure it is enabled on the miner!'); + } + }); }); }); diff --git a/src/App.cpp b/src/App.cpp index 04ad9dde..0b549eda 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -90,7 +90,8 @@ App::App(int argc, char **argv) : } if (m_options->ccUseRemoteLogging()) { - Log::add(new RemoteLog()); + // 20 lines per second should be enough + Log::add(new RemoteLog(static_cast(m_options->ccUpdateInterval() * 20))); } # ifdef HAVE_SYSLOG_H diff --git a/src/Options.cpp b/src/Options.cpp index 0fa73004..7392eb13 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -110,6 +110,7 @@ Options:\n" --cc-use-tls enable tls encryption for CC communication\n\ --cc-cert-file=FILE when tls is turned on, use this to point to the right cert file (default: server.pem) \n\ --cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key) \n\ + --client-log-lines-history=N maximum lines of log history kept per miner \n\ --cc-client-config-folder=FOLDER Folder contains the client config files\n\ --cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'\n" # endif @@ -182,6 +183,7 @@ static struct option const options[] = { { "cc-key-file", 1, nullptr, 4015 }, { "cc-use-tls", 0, nullptr, 4016 }, { "cc-use-remote-logging", 0, nullptr, 4017 }, + { "cc-client-log-lines-history", 1, nullptr, 4018 }, { "daemonized", 0, nullptr, 4011 }, { "doublehash-thread-mask", 1, nullptr, 4013 }, { "multihash-thread-mask", 1, nullptr, 4013 }, @@ -257,6 +259,7 @@ static struct option const cc_server_options[] = { { "cert-file", 1, nullptr, 4014 }, { "key-file", 1, nullptr, 4015 }, { "use-tls", 0, nullptr, 4016 }, + { "client-log-lines-history", 1, nullptr, 4018 }, { nullptr, 0, nullptr, 0 } }; @@ -346,6 +349,7 @@ Options::Options(int argc, char **argv) : m_threads(0), m_ccUpdateInterval(10), m_ccPort(0), + m_ccClientLogLinesHistory(100), m_affinity(-1L), m_multiHashThreadMask(-1L) { @@ -558,6 +562,8 @@ bool Options::parseArg(int key, const char *arg) case 4006: /* --cc-port */ case 4012: /* --cc-update-interval-c */ return parseArg(key, strtol(arg, nullptr, 10)); + case 4018: /* --cc-client-log-lines-history */ + return parseArg(key, strtol(arg, nullptr, 25)); case 'B': /* --background */ case 'k': /* --keepalive */ @@ -756,6 +762,10 @@ bool Options::parseArg(int key, uint64_t arg) } break; + case 4018: /* --cc-client-log-lines-history */ + m_ccClientLogLinesHistory = (int) arg; + break; + default: break; } diff --git a/src/Options.h b/src/Options.h index 911b508a..cc89e887 100644 --- a/src/Options.h +++ b/src/Options.h @@ -101,6 +101,7 @@ public: inline size_t threads() const { return m_threads; } inline int ccUpdateInterval() const { return m_ccUpdateInterval; } inline int ccPort() const { return m_ccPort; } + inline size_t ccClientLogLinesHistory() const { return m_ccClientLogLinesHistory; } inline int64_t affinity() const { return m_affinity; } inline int64_t multiHashThreadMask() const { return m_multiHashThreadMask; } inline void setColors(bool colors) { m_colors = colors; } @@ -175,6 +176,7 @@ private: size_t m_threads; int m_ccUpdateInterval; int m_ccPort; + size_t m_ccClientLogLinesHistory; int64_t m_affinity; int64_t m_multiHashThreadMask; std::vector m_pools; diff --git a/src/cc/ClientStatus.cpp b/src/cc/ClientStatus.cpp index 1a040907..cddb8c89 100644 --- a/src/cc/ClientStatus.cpp +++ b/src/cc/ClientStatus.cpp @@ -150,6 +150,11 @@ void ClientStatus::setLog(const std::string& log) m_log = log; } +void ClientStatus::clearLog() +{ + m_log.clear(); +} + bool ClientStatus::hasHugepages() const { return m_hasHugepages; diff --git a/src/cc/ClientStatus.h b/src/cc/ClientStatus.h index 66a9b6f2..e8204126 100644 --- a/src/cc/ClientStatus.h +++ b/src/cc/ClientStatus.h @@ -82,7 +82,8 @@ public: void setVersion(const std::string& version); std::string getLog() const; - void setLog(const std::string& version); + void setLog(const std::string& log); + void clearLog(); bool hasHugepages() const; void setHugepages(bool hasHugepages); diff --git a/src/cc/Service.cpp b/src/cc/Service.cpp index 72719e13..6c9e317b 100644 --- a/src/cc/Service.cpp +++ b/src/cc/Service.cpp @@ -40,7 +40,7 @@ uv_mutex_t Service::m_mutex; std::map Service::m_clientCommand; std::map Service::m_clientStatus; -std::map> Service::m_remoteLog; +std::map> Service::m_clientLog; int Service::m_currentServerTime = 0; @@ -57,7 +57,7 @@ void Service::release() m_clientCommand.clear(); m_clientStatus.clear(); - m_remoteLog.clear(); + m_clientLog.clear(); uv_mutex_unlock(&m_mutex); } @@ -81,7 +81,7 @@ unsigned Service::handleGET(const Options* options, const std::string& url, cons } else if (url.rfind("/admin/getClientCommand", 0) == 0) { resultCode = getClientCommand(clientId, resp); } else if (url.rfind("/admin/getClientLog", 0) == 0) { - //resultCode = getClientCommand(clientId, resp); + resultCode = getClientLog(clientId, resp); } } else { @@ -105,7 +105,7 @@ unsigned Service::handlePOST(const Options* options, const std::string& url, con url.c_str(), clientIp.c_str(), clientId.c_str(), data.length()); if (url.rfind("/client/setClientStatus", 0) == 0) { - resultCode = setClientStatus(clientIp, clientId, data, resp); + resultCode = setClientStatus(options, clientIp, clientId, data, resp); } else if (url.rfind("/admin/setClientConfig", 0) == 0 || url.rfind("/client/setClientConfig", 0) == 0) { resultCode = setClientConfig(options, clientId, data, resp); } else if (url.rfind("/admin/setClientCommand", 0) == 0) { @@ -221,7 +221,7 @@ unsigned Service::getClientStatusList(std::string& resp) return MHD_HTTP_OK; } -unsigned Service::setClientStatus(const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp) +unsigned Service::setClientStatus(const Options* options, const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp) { int resultCode = MHD_HTTP_BAD_REQUEST; @@ -233,6 +233,10 @@ unsigned Service::setClientStatus(const std::string& clientIp, const std::string clientStatus.parseFromJson(document); clientStatus.setExternalIp(clientIp); + setClientLog(options->ccClientLogLinesHistory(), clientId, clientStatus.getLog()); + + clientStatus.clearLog(); + m_clientStatus[clientId] = clientStatus; resultCode = getClientCommand(clientId, resp); @@ -271,40 +275,22 @@ unsigned Service::getClientCommand(const std::string& clientId, std::string& res return MHD_HTTP_OK; } -unsigned Service::setClientCommand(const std::string& clientId, const std::string& data, std::string& resp) -{ - ControlCommand controlCommand; - - rapidjson::Document document; - if (!document.Parse(data.c_str()).HasParseError()) { - controlCommand.parseFromJson(document); - - m_clientCommand[clientId] = controlCommand; - - return MHD_HTTP_OK; - } else { - return MHD_HTTP_BAD_REQUEST; - } -} - -unsigned Service::resetClientStatusList(const std::string& data, std::string& resp) -{ - m_clientStatus.clear(); - - return MHD_HTTP_OK; -} - unsigned Service::getClientLog(const std::string& clientId, std::string& resp) { - if (m_remoteLog.find(clientId) != m_remoteLog.end()) { - + if (m_clientLog.find(clientId) != m_clientLog.end()) { rapidjson::Document respDocument; respDocument.SetObject(); auto& allocator = respDocument.GetAllocator(); - rapidjson::Value controlCommand = m_clientCommand[clientId].toJson(allocator); - respDocument.AddMember("client_log", controlCommand, allocator); + std::stringstream data; + for (auto& m_row : m_clientLog[clientId]) { + data << m_row.c_str() << std::endl; + } + + LOG_INFO("LOG: %s", data.str().c_str()); + + respDocument.AddMember("client_log", rapidjson::StringRef(data.str().c_str()), allocator); rapidjson::StringBuffer buffer(0, 4096); rapidjson::Writer writer(buffer); @@ -351,6 +337,49 @@ unsigned Service::getAdminPage(const Options* options, std::string& resp) return MHD_HTTP_OK; } +unsigned Service::setClientCommand(const std::string& clientId, const std::string& data, std::string& resp) +{ + ControlCommand controlCommand; + + rapidjson::Document document; + if (!document.Parse(data.c_str()).HasParseError()) { + controlCommand.parseFromJson(document); + + m_clientCommand[clientId] = controlCommand; + + return MHD_HTTP_OK; + } else { + return MHD_HTTP_BAD_REQUEST; + } +} + +void Service::setClientLog(size_t maxRows, const std::string& clientId, const std::string& log) +{ + if (m_clientLog.find(clientId) == m_clientLog.end()) { + m_clientLog[clientId] = std::list(); + } + + auto* clientLog = &m_clientLog[clientId]; + std::istringstream logStream(log); + + std::string logLine; + while (std::getline(logStream, logLine)) + { + if (clientLog->size() == maxRows) { + clientLog->pop_front(); + } + + clientLog->push_back(logLine); + } +} + +unsigned Service::resetClientStatusList(const std::string& data, std::string& resp) +{ + m_clientStatus.clear(); + + return MHD_HTTP_OK; +} + std::string Service::getClientConfigFileName(const Options* options, const std::string& clientId) { std::string clientConfigFileName; diff --git a/src/cc/Service.h b/src/cc/Service.h index 98d0ee03..e909debd 100644 --- a/src/cc/Service.h +++ b/src/cc/Service.h @@ -52,11 +52,13 @@ private: static unsigned getClientStatusList(std::string& resp); static unsigned getAdminPage(const Options* options, std::string& resp); - static unsigned setClientStatus(const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp); + static unsigned setClientStatus(const Options* options, const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp); static unsigned setClientCommand(const std::string& clientId, const std::string& data, std::string& resp); static unsigned setClientConfig(const Options* options, const std::string &clientId, const std::string &data, std::string &resp); static unsigned resetClientStatusList(const std::string& data, std::string& resp); + static void setClientLog(size_t maxRows, const std::string& clientId, const std::string& log); + static std::string getClientConfigFileName(const Options *options, const std::string &clientId); private: @@ -64,7 +66,7 @@ private: static std::map m_clientStatus; static std::map m_clientCommand; - static std::map> m_remoteLog; + static std::map> m_clientLog; static uv_mutex_t m_mutex; diff --git a/src/config_cc.json b/src/config_cc.json index 2b716a0d..ea4e492a 100644 --- a/src/config_cc.json +++ b/src/config_cc.json @@ -12,6 +12,7 @@ "user": "admin", // admin user for access CC Dashboard "pass": "pass", // admin pass for access CC Dashboard "client-config-folder" : null, // folder which contains the client-config files (null=current) + "client-log-lines-history" : 100, // maximum lines of log history kept per miner "custom-dashboard" : "index.html" // dashboard html file } } diff --git a/src/log/Log.cpp b/src/log/Log.cpp index f37d4424..906ddf17 100644 --- a/src/log/Log.cpp +++ b/src/log/Log.cpp @@ -35,7 +35,6 @@ Log *Log::m_self = nullptr; - Log::Log() { uv_mutex_init(&m_mutex); diff --git a/src/log/RemoteLog.cpp b/src/log/RemoteLog.cpp index d0d93caa..f5552d09 100644 --- a/src/log/RemoteLog.cpp +++ b/src/log/RemoteLog.cpp @@ -22,8 +22,8 @@ RemoteLog* RemoteLog::m_self = nullptr; -RemoteLog::RemoteLog() - : m_maxRows(100) +RemoteLog::RemoteLog(size_t maxRows) + : m_maxRows(maxRows) { uv_mutex_init(&m_mutex); diff --git a/src/log/RemoteLog.h b/src/log/RemoteLog.h index 07e8a768..973cc8f5 100644 --- a/src/log/RemoteLog.h +++ b/src/log/RemoteLog.h @@ -29,7 +29,7 @@ class RemoteLog : public ILogBackend { public: - RemoteLog(); + RemoteLog(size_t maxRows); ~RemoteLog(); void message(int level, const char* fmt, va_list args) override;