From 055544957803c5c1a49ef436f9d4ff5a995adb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 3 Oct 2019 17:24:47 +0200 Subject: [PATCH 1/9] Add remove and copy buttons for log view --- data/debug-interface/debug-interface.qrc | 2 + data/debug-interface/delete.svg | 177 ++++++++++++++++++++ data/debug-interface/edit-copy.svg | 204 +++++++++++++++++++++++ data/debug-interface/script.js | 22 +++ data/debug-interface/styles.css | 41 ++++- libnymea-core/debugserverhandler.cpp | 28 ++++ 6 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 data/debug-interface/delete.svg create mode 100644 data/debug-interface/edit-copy.svg diff --git a/data/debug-interface/debug-interface.qrc b/data/debug-interface/debug-interface.qrc index 733a0ac7..2c14f6e5 100644 --- a/data/debug-interface/debug-interface.qrc +++ b/data/debug-interface/debug-interface.qrc @@ -24,5 +24,7 @@ favicons/apple-touch-icon-76x76.png favicons/apple-touch-icon-114x114.png favicons/apple-touch-icon-120x120.png + edit-copy.svg + delete.svg diff --git a/data/debug-interface/delete.svg b/data/debug-interface/delete.svg new file mode 100644 index 00000000..c4f9686c --- /dev/null +++ b/data/debug-interface/delete.svg @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/data/debug-interface/edit-copy.svg b/data/debug-interface/edit-copy.svg new file mode 100644 index 00000000..299f9e01 --- /dev/null +++ b/data/debug-interface/edit-copy.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/data/debug-interface/script.js b/data/debug-interface/script.js index 65dc28a8..8ae22c1b 100644 --- a/data/debug-interface/script.js +++ b/data/debug-interface/script.js @@ -104,6 +104,28 @@ function disconnectWebsocket() { } +function clearLogsContent() { + console.log("Clear live log content"); + var logTextArea = document.getElementById("logsTextArea") + logTextArea.value = ""; +} + + + +function copyLogsContent() { + console.log("Copy live log content"); + var logTextArea = document.getElementById("logsTextArea") + + logTextArea.select(); + logTextArea.setSelectionRange(0, 99999); /*For mobile devices*/ + document.execCommand("copy"); + + console.log("Copied text:"); + console.log(logTextArea.value); +} + + + /* ========================================================================*/ /* File download / show functions /* ========================================================================*/ diff --git a/data/debug-interface/styles.css b/data/debug-interface/styles.css index 86b041c8..60b1be55 100644 --- a/data/debug-interface/styles.css +++ b/data/debug-interface/styles.css @@ -214,6 +214,8 @@ textarea { transition: 0.3s; } +button::-moz-focus-inner { border: 0; } + .button:hover { opacity: 1 } @@ -224,8 +226,45 @@ textarea { color: #676767; } +.log-buttons { + width: 100%; + float: left; +} + +.log-buttons button { + float: left; +} + +#toggleLogsButton { + width: 80%; + margin-right: 10px; +} + +#copyLogsButton { + width: 20px; + margin-left: 10px; + margin-right: 10px; +} + +.tool-image { + width: 25px; + height: 25px; +} + +#clearLogsButton { + width: 20px; + margin-left: 10px; +} + +/* Clear floats (clearfix hack) */ +.log-buttons:after { + content: ""; + clear: both; + display: table; +} + .container { - min-height:100%; + min-height: 100%; position:relative; } diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index 8e883018..06f15816 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -1670,6 +1670,9 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeTextElement("p", tr("This section allows you to see the live logs of the nymea server.")); + writer.writeStartElement("div"); + writer.writeAttribute("class", "log-buttons"); + // Toggle log button writer.writeStartElement("button"); writer.writeAttribute("class", "button"); @@ -1680,6 +1683,31 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeCharacters(tr("Start logs")); writer.writeEndElement(); // button + // Copy log content button + writer.writeStartElement("button"); + writer.writeAttribute("class", "button"); + writer.writeAttribute("type", "button"); + writer.writeAttribute("id", "copyLogsButton"); + writer.writeAttribute("onClick", "copyLogsContent()"); + writer.writeEmptyElement("img"); + writer.writeAttribute("class", "tool-image"); + writer.writeAttribute("src", "/debug/edit-copy.svg"); + writer.writeEndElement(); // button + + // Copy log content button + writer.writeStartElement("button"); + writer.writeAttribute("class", "button"); + writer.writeAttribute("type", "button"); + writer.writeAttribute("id", "clearLogsButton"); + writer.writeAttribute("onClick", "clearLogsContent()"); + writer.writeEmptyElement("img"); + writer.writeAttribute("class", "tool-image"); + writer.writeAttribute("src", "/debug/delete.svg"); + writer.writeEndElement(); // button + + writer.writeEndElement(); // div log-buttons + + // Logs output writer.writeStartElement("textarea"); writer.writeAttribute("class", "console-textarea"); From 7d98bb37c8d72c9a4b44b19c7b521b0dc00fbec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 4 Oct 2019 09:45:41 +0200 Subject: [PATCH 2/9] Adjust live logs buttons with flexbox --- data/debug-interface/styles.css | 34 +++++++++++++++++----------- libnymea-core/debugserverhandler.cpp | 3 +++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/data/debug-interface/styles.css b/data/debug-interface/styles.css index 60b1be55..fadcfbb3 100644 --- a/data/debug-interface/styles.css +++ b/data/debug-interface/styles.css @@ -227,41 +227,49 @@ button::-moz-focus-inner { border: 0; } } .log-buttons { - width: 100%; - float: left; + display: -webkit-flex; /* Safari */ + display: flex; + flex-flow: row nowrap; } .log-buttons button { - float: left; + display: -webkit-flex; /* Safari */ + display: flex; + margin: 10px; + width: auto; +} + +.tool-image { + width: 30px; + height: 30px; } #toggleLogsButton { - width: 80%; - margin-right: 10px; + flex-grow: 1; + justify-content: center; + align-items: center; } #copyLogsButton { width: 20px; - margin-left: 10px; - margin-right: 10px; -} - -.tool-image { - width: 25px; - height: 25px; + justify-content: center; + align-items: center; } #clearLogsButton { width: 20px; - margin-left: 10px; + justify-content: center; + align-items: center; } /* Clear floats (clearfix hack) */ +/* .log-buttons:after { content: ""; clear: both; display: table; } +*/ .container { min-height: 100%; diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index 06f15816..476dfc22 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -565,6 +565,9 @@ void DebugServerHandler::onWebsocketClientConnected() s_oldLogMessageHandler = qInstallMessageHandler(&logMessageHandler); } + // Enable the log categories depending on the current debug configuration + + s_websocketClients.append(client); qCDebug(dcDebugServer()) << "New websocket client connected:" << client->peerAddress().toString(); From dc6c4b88dfeb1213ea70bfaed272be4461e92197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 4 Oct 2019 15:28:45 +0200 Subject: [PATCH 3/9] Prepare debug categories for the live log viewer in the debug interface --- data/debug-interface/script.js | 6 +- data/debug-interface/styles.css | 118 +++++++++++++++++++++++---- libnymea-core/debugserverhandler.cpp | 39 +++++++++ 3 files changed, 146 insertions(+), 17 deletions(-) diff --git a/data/debug-interface/script.js b/data/debug-interface/script.js index 8ae22c1b..28af074b 100644 --- a/data/debug-interface/script.js +++ b/data/debug-interface/script.js @@ -111,17 +111,19 @@ function clearLogsContent() { } - function copyLogsContent() { console.log("Copy live log content"); var logTextArea = document.getElementById("logsTextArea") logTextArea.select(); - logTextArea.setSelectionRange(0, 99999); /*For mobile devices*/ + //logTextArea.setSelectionRange(0, 99999); /*For mobile devices*/ document.execCommand("copy"); console.log("Copied text:"); console.log(logTextArea.value); + + /* Clear selection */ + document.select(); } diff --git a/data/debug-interface/styles.css b/data/debug-interface/styles.css index fadcfbb3..5e4f2f22 100644 --- a/data/debug-interface/styles.css +++ b/data/debug-interface/styles.css @@ -212,6 +212,8 @@ textarea { border-radius: 10px; opacity: 0.8; transition: 0.3s; + cursor: pointer; + outline: none; } button::-moz-focus-inner { border: 0; } @@ -235,41 +237,127 @@ button::-moz-focus-inner { border: 0; } .log-buttons button { display: -webkit-flex; /* Safari */ display: flex; + justify-content: center; + align-items: center; margin: 10px; width: auto; } .tool-image { - width: 30px; - height: 30px; + width: 25px; + height: 25px; } #toggleLogsButton { flex-grow: 1; - justify-content: center; - align-items: center; } #copyLogsButton { width: 20px; - justify-content: center; - align-items: center; } #clearLogsButton { width: 20px; - justify-content: center; - align-items: center; } -/* Clear floats (clearfix hack) */ -/* -.log-buttons:after { - content: ""; - clear: both; - display: table; +.categories-area { + display: -webkit-flex; + display: flex; + flex-flow: row nowrap; } -*/ + +.debug-category { + display: -webkit-flex; + display: flex; + flex-flow: row nowrap; + justify-content: center; + align-items: center; + margin: 10px; + width: 25%; +} + +.debug-category p { + margin: 10px; + text-align: left; + flex-grow: 1; +} + +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked + .slider { + background-color: #2196F3; +} + +input:focus + .slider { + box-shadow: 0 0 1px #2196F3; +} + +input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 34px; +} + +.slider.round:before { + border-radius: 50%; +} + + .container { min-height: 100%; diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index 476dfc22..44709bd1 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -1720,6 +1720,45 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeCharacters(""); writer.writeEndElement(); // textarea + writer.writeStartElement("div"); + writer.writeAttribute("class", "categories-area"); + + // Application debug category + writer.writeStartElement("div"); + writer.writeAttribute("class", "debug-category"); + writer.writeTextElement("p", "Application"); + writer.writeStartElement("label"); + writer.writeAttribute("class", "switch"); + writer.writeStartElement("input"); + writer.writeAttribute("type", "checkbox"); + writer.writeEndElement(); // input + writer.writeStartElement("span"); + writer.writeAttribute("class", "slider round"); + writer.writeCharacters(""); + writer.writeEndElement(); // span + writer.writeEndElement(); // label + writer.writeEndElement(); // div debug-category + + writer.writeStartElement("div"); + writer.writeAttribute("class", "debug-category"); + writer.writeTextElement("p", "DeviceManager"); + writer.writeStartElement("label"); + writer.writeAttribute("class", "switch"); + writer.writeStartElement("input"); + writer.writeAttribute("type", "checkbox"); + writer.writeEndElement(); // input + writer.writeStartElement("span"); + writer.writeAttribute("class", "slider round"); + writer.writeCharacters(""); + writer.writeEndElement(); // span + writer.writeEndElement(); // label + writer.writeEndElement(); // div debug-category + + + // Provide options for debug categories + + writer.writeEndElement(); // div categories-area + writer.writeEndElement(); // logs-section writer.writeEndElement(); // div body From b4f32c073ae159e45aba7e88350cebe656bb67d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 7 Oct 2019 12:04:52 +0200 Subject: [PATCH 4/9] Add dynamic logging filter elements for core and plugins in the livelog view --- data/debug-interface/styles.css | 6 +-- libnymea-core/debugserverhandler.cpp | 80 +++++++++++++++++----------- libnymea-core/nymeacore.cpp | 59 ++++++++++++++++++++ libnymea-core/nymeacore.h | 2 + server/main.cpp | 52 ++---------------- 5 files changed, 117 insertions(+), 82 deletions(-) diff --git a/data/debug-interface/styles.css b/data/debug-interface/styles.css index 5e4f2f22..946d4cc0 100644 --- a/data/debug-interface/styles.css +++ b/data/debug-interface/styles.css @@ -263,7 +263,7 @@ button::-moz-focus-inner { border: 0; } .categories-area { display: -webkit-flex; display: flex; - flex-flow: row nowrap; + flex-flow: row wrap; } .debug-category { @@ -335,11 +335,11 @@ button::-moz-focus-inner { border: 0; } } input:checked + .slider { - background-color: #2196F3; + background-color: #57baae; } input:focus + .slider { - box-shadow: 0 0 1px #2196F3; + box-shadow: 0 0 1px #57baae; } input:checked + .slider:before { diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index 44709bd1..c6929011 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -1720,42 +1720,62 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeCharacters(""); writer.writeEndElement(); // textarea + writer.writeEmptyElement("hr"); + //: The network section of the debug interface + writer.writeTextElement("h2", tr("Logging filters")); + writer.writeEmptyElement("hr"); + writer.writeStartElement("div"); writer.writeAttribute("class", "categories-area"); - // Application debug category - writer.writeStartElement("div"); - writer.writeAttribute("class", "debug-category"); - writer.writeTextElement("p", "Application"); - writer.writeStartElement("label"); - writer.writeAttribute("class", "switch"); - writer.writeStartElement("input"); - writer.writeAttribute("type", "checkbox"); - writer.writeEndElement(); // input - writer.writeStartElement("span"); - writer.writeAttribute("class", "slider round"); - writer.writeCharacters(""); - writer.writeEndElement(); // span - writer.writeEndElement(); // label - writer.writeEndElement(); // div debug-category + QStringList loggingCategories = NymeaCore::loggingFilters(); + loggingCategories.sort(); + + foreach (const QString &loggingCategory, loggingCategories) { + writer.writeStartElement("div"); + writer.writeAttribute("class", "debug-category"); + writer.writeTextElement("p", loggingCategory); + writer.writeStartElement("label"); + writer.writeAttribute("class", "switch"); + writer.writeStartElement("input"); + writer.writeAttribute("type", "checkbox"); + writer.writeEndElement(); // input + writer.writeStartElement("span"); + writer.writeAttribute("class", "slider round"); + writer.writeCharacters(""); + writer.writeEndElement(); // span + writer.writeEndElement(); // label + writer.writeEndElement(); // div debug-category + } + + writer.writeEndElement(); // div categories-area + + writer.writeEmptyElement("hr"); + //: The network section of the debug interface + writer.writeTextElement("h2", tr("Logging filters plugins")); + writer.writeEmptyElement("hr"); writer.writeStartElement("div"); - writer.writeAttribute("class", "debug-category"); - writer.writeTextElement("p", "DeviceManager"); - writer.writeStartElement("label"); - writer.writeAttribute("class", "switch"); - writer.writeStartElement("input"); - writer.writeAttribute("type", "checkbox"); - writer.writeEndElement(); // input - writer.writeStartElement("span"); - writer.writeAttribute("class", "slider round"); - writer.writeCharacters(""); - writer.writeEndElement(); // span - writer.writeEndElement(); // label - writer.writeEndElement(); // div debug-category + writer.writeAttribute("class", "categories-area"); - - // Provide options for debug categories + QStringList loggingCategoriesPlugins = NymeaCore::loggingFiltersPlugins(); + loggingCategoriesPlugins.sort(); + foreach (const QString &loggingCategory, loggingCategoriesPlugins) { + writer.writeStartElement("div"); + writer.writeAttribute("class", "debug-category"); + writer.writeTextElement("p", loggingCategory); + writer.writeStartElement("label"); + writer.writeAttribute("class", "switch"); + writer.writeStartElement("input"); + writer.writeAttribute("type", "checkbox"); + writer.writeEndElement(); // input + writer.writeStartElement("span"); + writer.writeAttribute("class", "slider round"); + writer.writeCharacters(""); + writer.writeEndElement(); // span + writer.writeEndElement(); // label + writer.writeEndElement(); // div debug-category + } writer.writeEndElement(); // div categories-area diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index b5686a1b..5252e40a 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -690,6 +690,65 @@ QStringList NymeaCore::getAvailableLanguages() return availableLanguages; } +/*! Returns the list of logging categories from the core and the libnymea. */ +QStringList NymeaCore::loggingFilters() +{ + QStringList loggingFilters = { + "Warnings", + "Application", + "System", + "Platform", + "PlatformUpdate", + "PlatformZeroConf", + "Device", + "DeviceManager", + "RuleEngine", + "RuleEngineDebug", + "Hardware", + "Bluetooth", + "LogEngine", + "ServerManager", + "TcpServer", + "TcpServerTraffic", + "WebServer", + "WebServerTraffic", + "DebugServer", + "WebSocketServer", + "WebSocketServerTraffic", + "JsonRpc", + "JsonRpcTraffic", + "Rest", + "OAuth2", + "TimeManager", + "Coap", + "Avahi", + "AvahiDebug", + "UPnP", + "Cloud", + "CloudTraffic", + "NetworkManager", + "UserManager", + "AWS", + "AWSTraffic", + "BluetoothServer", + "BluetoothServerTraffic", + "Mqtt", + "Translations" + }; + + return loggingFilters; +} + +QStringList NymeaCore::loggingFiltersPlugins() +{ + QStringList loggingFiltersPlugins; + foreach (const QJsonObject &pluginMetadata, DeviceManagerImplementation::pluginsMetadata()) { + QString pluginName = pluginMetadata.value("name").toString(); + loggingFiltersPlugins << pluginName.left(1).toUpper() + pluginName.mid(1); + } + return loggingFiltersPlugins; +} + /*! Returns a pointer to the \l{BluetoothServer} instance owned by NymeaCore. */ BluetoothServer *NymeaCore::bluetoothServer() const { diff --git a/libnymea-core/nymeacore.h b/libnymea-core/nymeacore.h index 8b10dee2..4b6a1b78 100644 --- a/libnymea-core/nymeacore.h +++ b/libnymea-core/nymeacore.h @@ -96,6 +96,8 @@ public: Platform *platform() const; static QStringList getAvailableLanguages(); + static QStringList loggingFilters(); + static QStringList loggingFiltersPlugins(); signals: void initialized(); diff --git a/server/main.cpp b/server/main.cpp index b8a6d054..4d4037b5 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -97,55 +97,9 @@ int main(int argc, char *argv[]) application.setApplicationName("nymead"); application.setApplicationVersion(NYMEA_VERSION_STRING); - // logging filers for core and libnymea - QStringList loggingFilters = { - "Warnings", - "Application", - "System", - "Platform", - "PlatformUpdate", - "PlatformZeroConf", - "Device", - "DeviceManager", - "RuleEngine", - "RuleEngineDebug", - "Hardware", - "Bluetooth", - "LogEngine", - "ServerManager", - "TcpServer", - "TcpServerTraffic", - "WebServer", - "WebServerTraffic", - "DebugServer", - "WebSocketServer", - "WebSocketServerTraffic", - "JsonRpc", - "JsonRpcTraffic", - "Rest", - "OAuth2", - "TimeManager", - "Coap", - "Avahi", - "AvahiDebug", - "UPnP", - "Cloud", - "CloudTraffic", - "NetworkManager", - "UserManager", - "AWS", - "AWSTraffic", - "BluetoothServer", - "BluetoothServerTraffic", - "Mqtt", - "Translations" - }; - - QStringList loggingFiltersPlugins; - foreach (const QJsonObject &pluginMetadata, DeviceManagerImplementation::pluginsMetadata()) { - QString pluginName = pluginMetadata.value("name").toString(); - loggingFiltersPlugins << pluginName.left(1).toUpper() + pluginName.mid(1); - } + // Logging filers for core + libnymea and plugins + QStringList loggingFilters = NymeaCore::loggingFilters(); + QStringList loggingFiltersPlugins = NymeaCore::loggingFiltersPlugins(); // Translator for the server application QTranslator translator; From 191936e2357b4e96d6e368c78fa660654101bb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 7 Oct 2019 18:22:25 +0200 Subject: [PATCH 5/9] Load debug categories from settings and allow configuration using debug interface --- data/debug-interface/script.js | 63 +++++++++++++++++++++++++++- data/debug-interface/styles.css | 7 ++-- data/systemd/nymead.service | 3 +- debian/nymead.install.in | 1 - libnymea-core/debugserverhandler.cpp | 63 ++++++++++++++++++++++++++-- server/main.cpp | 51 +++++++++++++++------- 6 files changed, 161 insertions(+), 27 deletions(-) diff --git a/data/debug-interface/script.js b/data/debug-interface/script.js index 28af074b..c73bf09a 100644 --- a/data/debug-interface/script.js +++ b/data/debug-interface/script.js @@ -92,7 +92,6 @@ function connectWebsocket() { } catch (exception) { console.error(exception); } - } @@ -127,6 +126,65 @@ function copyLogsContent() { } +function loadLoggingCategorySettings() { + // Request report file generation + var request = new XMLHttpRequest(); + request.open("GET", "/debug/logging-categories", true); + request.send(null); + + request.onreadystatechange = function() { + if (request.readyState == 4) { + console.log("Load logging category settings finished", request.status); + + /* Check if the generation went fine */ + if (request.status != 200) { + console.warn("Could not load logging category settings", request.status); + return; + } + + console.log(request.responseText); + var responseMap = JSON.parse(request.responseText); + + for (var loggingCategory in responseMap['loggingCategories']) { + console.warn(loggingCategory, responseMap['loggingCategories'][loggingCategory]) + var loggingCategoryElement = document.getElementById("debug-category-" + loggingCategory) + loggingCategoryElement.checked = responseMap['loggingCategories'][loggingCategory] + } + + for (var loggingCategory in responseMap['loggingCategoriesPlugins']) { + console.warn(loggingCategory, responseMap['loggingCategoriesPlugins'][loggingCategory]) + var loggingCategoryElement = document.getElementById("debug-category-" + loggingCategory) + loggingCategoryElement.checked = responseMap['loggingCategoriesPlugins'][loggingCategory] + } + } + } +} + + +function toggleLoggingCategory(categoryName) { + var switchElement = document.getElementById("debug-category-" + categoryName) + console.log("Toggle logging category", categoryName, switchElement.checked) + + var fileRequestUrl = "/debug/logging-categories?" + categoryName + "=" + (switchElement.checked ? "true" : "false"); + + // Request report file generation + var request = new XMLHttpRequest(); + request.open("GET", fileRequestUrl, true); + request.send(null); + + request.onreadystatechange = function() { + if (request.readyState == 4) { + console.log("Set logging category settings finished", request.status); + + /* Check if the generation went fine */ + if (request.status != 200) { + console.warn("Could not set logging category settings", request.status); + return; + } + } + } +} + /* ========================================================================*/ /* File download / show functions @@ -175,7 +233,7 @@ function pollReportResult() { /* Check if the generation went fine */ if (reportGenerateRequest.status != 200) { - console.log("Report generation finished with error."); + console.warn("Report generation finished with error."); clearTimeout(generateReportTimer); textArea.value = "Something went wrong :(" + reportGenerateRequest.status; button.disabled = false; @@ -366,5 +424,6 @@ function tracePathTimerTimeout() { window.onload = function() { console.log("Window loading finished."); document.getElementById("informationTabButton").click(); + loadLoggingCategorySettings(); }; diff --git a/data/debug-interface/styles.css b/data/debug-interface/styles.css index 946d4cc0..6aaf5cd5 100644 --- a/data/debug-interface/styles.css +++ b/data/debug-interface/styles.css @@ -71,6 +71,7 @@ textarea { min-height: 100px; text-align: left; border-radius: 10px; + outline: none; } .tab { @@ -273,12 +274,12 @@ button::-moz-focus-inner { border: 0; } justify-content: center; align-items: center; margin: 10px; - width: 25%; + width: 30%; } .debug-category p { margin: 10px; - text-align: left; + text-align: right; flex-grow: 1; } @@ -357,8 +358,6 @@ input:checked + .slider:before { border-radius: 50%; } - - .container { min-height: 100%; position:relative; diff --git a/data/systemd/nymead.service b/data/systemd/nymead.service index d1606420..ed25508b 100644 --- a/data/systemd/nymead.service +++ b/data/systemd/nymead.service @@ -5,8 +5,7 @@ After=network.target Wants=network-online.target [Service] -Environment=QT_LOGGING_CONF=/etc/nymea/logging.conf -ExecStart=/usr/bin/nymead -n --print-all +ExecStart=/usr/bin/nymead -n StandardOutput=journal StandardError=journal Restart=on-failure diff --git a/debian/nymead.install.in b/debian/nymead.install.in index e8d5fca0..672a4bd3 100644 --- a/debian/nymead.install.in +++ b/debian/nymead.install.in @@ -5,4 +5,3 @@ usr/lib/@DEB_HOST_MULTIARCH@/libnymea-core.so.1.0.0 data/systemd/nymead.service /lib/systemd/system/ data/logrotate/nymead /etc/logrotate.d/ data/dbus-1/io.guh.nymead.conf /etc/dbus-1/system.d/ -data/config/logging.conf /etc/nymea/ diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index c6929011..cecbabc8 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -379,6 +379,61 @@ HttpReply *DebugServerHandler::processDebugRequest(const QString &requestPath, c return m_tracePathReply; } + if (requestPath.startsWith("/debug/logging-categories")) { + + if (requestQuery.isEmpty()) { + // Return the list of debug category settings + NymeaSettings settings(NymeaSettings::SettingsRoleGlobal); + settings.beginGroup("LoggingRules"); + + qCDebug(dcDebugServer()) << "Request logging categories list"; + QVariantMap dataMap; + QVariantMap loggingCategories; + foreach (const QString &loggingCategory, NymeaCore::loggingFilters()) { + loggingCategories.insert(loggingCategory, settings.value(QString("%1.debug").arg(loggingCategory), false).toBool()); + } + dataMap.insert("loggingCategories", loggingCategories); + QVariantMap loggingCategoriesPlugins; + foreach (const QString &loggingCategory, NymeaCore::loggingFiltersPlugins()) { + loggingCategoriesPlugins.insert(loggingCategory, settings.value(QString("%1.debug").arg(loggingCategory), false).toBool()); + } + dataMap.insert("loggingCategoriesPlugins", loggingCategoriesPlugins); + + settings.endGroup(); + + HttpReply *reply = RestResource::createSuccessReply(); + reply->setPayload(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented)); + return reply; + } else { + NymeaSettings settings(NymeaSettings::SettingsRoleGlobal); + settings.beginGroup("LoggingRules"); + for (int i = 0; i < requestQuery.queryItems().count(); i++) { + QString category = requestQuery.queryItems().at(i).first; + if (!NymeaCore::loggingFilters().contains(category) && !NymeaCore::loggingFiltersPlugins().contains(category)) { + qCWarning(dcDebugServer()) << "Invalid logging category in request query" << requestQuery.toString() << category; + continue; + } + + bool enabled = QVariant(requestQuery.queryItems().at(i).second).toBool(); + qCDebug(dcDebugServer()) << "Category" << category << enabled; + settings.setValue(QString("%1.debug").arg(category), (enabled ? "true" : "false")); + } + + // Update logging filter rules according to the nw settings + QStringList loggingRules; + loggingRules << "*.debug=false"; + // Load the rules from nymead.conf file and append them to the rules + foreach (const QString &category, settings.childKeys()) { + loggingRules << QString("%1=%2").arg(category).arg(settings.value(category, "false").toString()); + } + settings.endGroup(); + QLoggingCategory::setFilterRules(loggingRules.join('\n')); + + return RestResource::createSuccessReply(); + } + } + + if (requestPath.startsWith("/debug/report")) { // The client can poll this url in order to get information about the current report generating process. @@ -562,12 +617,10 @@ void DebugServerHandler::onWebsocketClientConnected() if (s_websocketClients.isEmpty()) { qCDebug(dcDebugServer()) << "Install debug message handler for live logs."; + //QLoggingCategory::setFilterRules("*.debug=true"); s_oldLogMessageHandler = qInstallMessageHandler(&logMessageHandler); } - // Enable the log categories depending on the current debug configuration - - s_websocketClients.append(client); qCDebug(dcDebugServer()) << "New websocket client connected:" << client->peerAddress().toString(); @@ -1738,7 +1791,9 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeStartElement("label"); writer.writeAttribute("class", "switch"); writer.writeStartElement("input"); + writer.writeAttribute("id", QString("debug-category-%1").arg(loggingCategory)); writer.writeAttribute("type", "checkbox"); + writer.writeAttribute("onclick", QString("toggleLoggingCategory('%1')").arg(loggingCategory)); writer.writeEndElement(); // input writer.writeStartElement("span"); writer.writeAttribute("class", "slider round"); @@ -1767,7 +1822,9 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeStartElement("label"); writer.writeAttribute("class", "switch"); writer.writeStartElement("input"); + writer.writeAttribute("id", QString("debug-category-%1").arg(loggingCategory)); writer.writeAttribute("type", "checkbox"); + writer.writeAttribute("onclick", QString("toggleLoggingCategory('%1')").arg(loggingCategory)); writer.writeEndElement(); // input writer.writeStartElement("span"); writer.writeAttribute("class", "slider round"); diff --git a/server/main.cpp b/server/main.cpp index 4d4037b5..ae121979 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -171,29 +171,50 @@ int main(int argc, char *argv[]) } } - QStringList filterRules; + + /* The logging rules will be evaluated sequentially + * 1. All debug categories off + * 2. The stored categories from the nymead.conf will be appended + * 3. The Command line parameters will be added (-p and -d) + * 4. QT_LOGGING_CONF + * 5. QT_LOGGING_RULES + * + * The final filter rules will be set. + */ + + QStringList loggingRules; + loggingRules << "*.debug=false"; + // Load the rules from nymead.conf file and append them to the rules + NymeaSettings nymeaSettings(NymeaSettings::SettingsRoleGlobal); + nymeaSettings.beginGroup("LoggingRules"); + foreach (const QString &category, nymeaSettings.childKeys()) { + loggingRules << QString("%1=%2").arg(category).arg(nymeaSettings.value(category, "false").toString()); + } + nymeaSettings.endGroup(); + + // Append the rules depending on the application parameter if (parser.isSet(allOption)) { - filterRules << "*.debug=true"; - filterRules << "*Traffic.debug=false"; - filterRules << "*Debug.debug=false"; - } else { - filterRules << "*.debug=false"; + loggingRules << "*.debug=true"; + loggingRules << "*Traffic.debug=false"; + loggingRules << "*Debug.debug=false"; } - // And allow overriding individual values + // And allow overriding individual values with application parameter foreach (QString debugArea, parser.values(debugOption)) { bool enable = !debugArea.startsWith("No"); bool isWarning = debugArea.endsWith("Warnings"); debugArea.remove(QRegExp("^No")); debugArea.remove(QRegExp("Warnings$")); if (loggingFilters.contains(debugArea) || loggingFiltersPlugins.contains(debugArea)) { - filterRules.append(QString("%1.%2=%3").arg(debugArea).arg(isWarning ? "warning" : "debug").arg(enable ? "true": "false")); + loggingRules.append(QString("%1.%2=%3").arg(debugArea).arg(isWarning ? "warning" : "debug").arg(enable ? "true": "false")); } else { qCWarning(dcApplication) << QCoreApplication::translate("nymea", "No such debug category:") << debugArea; } } - QLoggingCategory::setFilterRules(filterRules.join('\n')); + QLoggingCategory::setFilterRules(loggingRules.join('\n')); + + // Parse DBus option if (parser.isSet(dbusOption)) { NymeaDBusService::setBusType(QDBusConnection::SessionBus); } @@ -208,13 +229,13 @@ int main(int argc, char *argv[]) fprintf(stdout, "Could not create nymea settings directory %s", qPrintable(NymeaSettings::settingsPath())); exit(EXIT_FAILURE); } - qCInfo(dcApplication) << "====================================="; - qCInfo(dcApplication) << "nymead" << NYMEA_VERSION_STRING << "started with user ID" << userId; - qCInfo(dcApplication) << "====================================="; + qCInfo(dcApplication()) << "====================================="; + qCInfo(dcApplication()) << "nymead" << NYMEA_VERSION_STRING << "started with user ID" << userId; + qCInfo(dcApplication()) << "====================================="; } else { - qCInfo(dcApplication) << "====================================="; - qCInfo(dcApplication) << "nymead" << NYMEA_VERSION_STRING << "started as root."; - qCInfo(dcApplication) << "====================================="; + qCInfo(dcApplication()) << "====================================="; + qCInfo(dcApplication()) << "nymead" << NYMEA_VERSION_STRING << "started as root."; + qCInfo(dcApplication()) << "====================================="; } // If running in a snappy environment, print out some details about it. From cc858b4d0aebbbe9adb171263f06a38589dbc671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 8 Oct 2019 09:40:47 +0200 Subject: [PATCH 6/9] Fix hostname reading for Qt < 5.6 --- data/debug-interface/script.js | 8 ++---- data/debug-interface/styles.css | 43 ++++++++++++++-------------- libnymea-core/debugserverhandler.cpp | 6 ++-- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/data/debug-interface/script.js b/data/debug-interface/script.js index c73bf09a..e3f04559 100644 --- a/data/debug-interface/script.js +++ b/data/debug-interface/script.js @@ -67,13 +67,13 @@ function connectWebsocket() { webSocket = new WebSocket(urlString); webSocket.onopen = function(openEvent) { - console.log("WebSocket connected: " + JSON.stringify(openEvent, null, 4)); + console.log("WebSocket connected"); webSocketConnected = true; document.getElementById("toggleLogsButton").innerHTML = "Stop logs"; }; webSocket.onclose = function(closeEvent) { - console.log("WebSocket disconnected: " + JSON.stringify(closeEvent, null, 4)); + console.log("WebSocket disconnected"); webSocketConnected = false; document.getElementById("toggleLogsButton").innerHTML = "Start logs"; }; @@ -84,7 +84,6 @@ function connectWebsocket() { webSocket.onmessage = function (messageEvent) { var message = messageEvent.data; - console.log("WebSocket data received: " + message); document.getElementById("logsTextArea").value += message; document.getElementById("logsTextArea").scrollTop = document.getElementById("logsTextArea").scrollHeight; }; @@ -142,17 +141,14 @@ function loadLoggingCategorySettings() { return; } - console.log(request.responseText); var responseMap = JSON.parse(request.responseText); for (var loggingCategory in responseMap['loggingCategories']) { - console.warn(loggingCategory, responseMap['loggingCategories'][loggingCategory]) var loggingCategoryElement = document.getElementById("debug-category-" + loggingCategory) loggingCategoryElement.checked = responseMap['loggingCategories'][loggingCategory] } for (var loggingCategory in responseMap['loggingCategoriesPlugins']) { - console.warn(loggingCategory, responseMap['loggingCategoriesPlugins'][loggingCategory]) var loggingCategoryElement = document.getElementById("debug-category-" + loggingCategory) loggingCategoryElement.checked = responseMap['loggingCategoriesPlugins'][loggingCategory] } diff --git a/data/debug-interface/styles.css b/data/debug-interface/styles.css index 6aaf5cd5..1d7f4caa 100644 --- a/data/debug-interface/styles.css +++ b/data/debug-interface/styles.css @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2018 Simon Stürz * + * Copyright (C) 2018-2019 Simon Stürz * * * * This file is part of nymea. * * * @@ -39,6 +39,14 @@ h1, h2, h3, h4, h5, h6 { text-align: center; } +table { + display: table; + border-collapse: colapse; + border-color: #efefef; + min-height: 100px; + width: 100%; +} + th, td { padding: 3px; padding-left: 10px; @@ -52,28 +60,10 @@ hr { color: #efefef; } -table { - display: table; - border-collapse: colapse; - border-color: #efefef; - min-height: 100px; - width: 100%; -} - button { width: 100%; } -textarea { - background-color: #3a4055; - width: 100%; - padding: 15px; - min-height: 100px; - text-align: left; - border-radius: 10px; - outline: none; -} - .tab { overflow: hidden; background-color: #efefef; @@ -107,8 +97,18 @@ textarea { } @keyframes fadeEffect { - from {opacity: 0;} - to {opacity: 1;} + from { opacity: 0; } + to { opacity: 1; } +} + +textarea { + background-color: #3a4055; + width: 100%; + padding: 15px; + min-height: 100px; + text-align: left; + border-radius: 10px; + outline: none; } .console-textarea { @@ -349,7 +349,6 @@ input:checked + .slider:before { transform: translateX(26px); } -/* Rounded sliders */ .slider.round { border-radius: 34px; } diff --git a/libnymea-core/debugserverhandler.cpp b/libnymea-core/debugserverhandler.cpp index cecbabc8..f92e8aac 100644 --- a/libnymea-core/debugserverhandler.cpp +++ b/libnymea-core/debugserverhandler.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2018 Simon Stürz * + * Copyright (C) 2018-2019 Simon Stürz * * * * This file is part of nymea. * * * @@ -415,7 +415,7 @@ HttpReply *DebugServerHandler::processDebugRequest(const QString &requestPath, c } bool enabled = QVariant(requestQuery.queryItems().at(i).second).toBool(); - qCDebug(dcDebugServer()) << "Category" << category << enabled; + qCDebug(dcDebugServer()) << "Logging category" << category << (enabled ? "enabled" : "disabled"); settings.setValue(QString("%1.debug").arg(category), (enabled ? "true" : "false")); } @@ -433,7 +433,6 @@ HttpReply *DebugServerHandler::processDebugRequest(const QString &requestPath, c } } - if (requestPath.startsWith("/debug/report")) { // The client can poll this url in order to get information about the current report generating process. @@ -902,7 +901,6 @@ QByteArray DebugServerHandler::createDebugXmlDocument() writer.writeStartElement("div"); writer.writeAttribute("class", "body"); - // --------------------------------------------------------------------------- writer.writeStartElement("div"); writer.writeAttribute("class", "tabcontent"); From fba096ff0c6a034832659ece961f1775dc427649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 8 Oct 2019 09:44:12 +0200 Subject: [PATCH 7/9] Fix debug category layout --- data/debug-interface/styles.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/debug-interface/styles.css b/data/debug-interface/styles.css index 1d7f4caa..7dfa353b 100644 --- a/data/debug-interface/styles.css +++ b/data/debug-interface/styles.css @@ -273,8 +273,8 @@ button::-moz-focus-inner { border: 0; } flex-flow: row nowrap; justify-content: center; align-items: center; - margin: 10px; - width: 30%; + margin-top: 10px; + width: 33%; } .debug-category p { From b1da5b432783fd5f472cf7778817f938e7b05ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 10 Oct 2019 16:08:23 +0200 Subject: [PATCH 8/9] Fix inline comments and make small logging category logic adjustments --- data/config/logging.conf | 2 -- data/debug-interface/script.js | 2 +- server/main.cpp | 26 +++++++++++++++----------- 3 files changed, 16 insertions(+), 14 deletions(-) delete mode 100644 data/config/logging.conf diff --git a/data/config/logging.conf b/data/config/logging.conf deleted file mode 100644 index be2bf225..00000000 --- a/data/config/logging.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Rules] -*.debug=false diff --git a/data/debug-interface/script.js b/data/debug-interface/script.js index e3f04559..68417699 100644 --- a/data/debug-interface/script.js +++ b/data/debug-interface/script.js @@ -114,7 +114,7 @@ function copyLogsContent() { var logTextArea = document.getElementById("logsTextArea") logTextArea.select(); - //logTextArea.setSelectionRange(0, 99999); /*For mobile devices*/ + logTextArea.setSelectionRange(0, 99999); /*For mobile devices*/ document.execCommand("copy"); console.log("Copied text:"); diff --git a/server/main.cpp b/server/main.cpp index ae121979..c3a70856 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -174,17 +174,27 @@ int main(int argc, char *argv[]) /* The logging rules will be evaluated sequentially * 1. All debug categories off - * 2. The stored categories from the nymead.conf will be appended - * 3. The Command line parameters will be added (-p and -d) + * 2. Enable all debug categories if requested from command line (-p) + * 3. The stored categories from the nymead.conf will be appended + * 4. Add the individual command line params will be added (-d) * 4. QT_LOGGING_CONF * 5. QT_LOGGING_RULES * * The final filter rules will be set. */ + // 1. All debug categories off QStringList loggingRules; loggingRules << "*.debug=false"; - // Load the rules from nymead.conf file and append them to the rules + + // 2. Enable all debug categories making sense if requested from command line (-p) + if (parser.isSet(allOption)) { + loggingRules << "*.debug=true"; + loggingRules << "*Traffic.debug=false"; + loggingRules << "*Debug.debug=false"; + } + + // 3. The stored categories from the nymead.conf will be appended NymeaSettings nymeaSettings(NymeaSettings::SettingsRoleGlobal); nymeaSettings.beginGroup("LoggingRules"); foreach (const QString &category, nymeaSettings.childKeys()) { @@ -192,14 +202,7 @@ int main(int argc, char *argv[]) } nymeaSettings.endGroup(); - // Append the rules depending on the application parameter - if (parser.isSet(allOption)) { - loggingRules << "*.debug=true"; - loggingRules << "*Traffic.debug=false"; - loggingRules << "*Debug.debug=false"; - } - - // And allow overriding individual values with application parameter + // Add the individual command line params will be added (-d) foreach (QString debugArea, parser.values(debugOption)) { bool enable = !debugArea.startsWith("No"); bool isWarning = debugArea.endsWith("Warnings"); @@ -212,6 +215,7 @@ int main(int argc, char *argv[]) } } + // Finally set the rules for the logging QLoggingCategory::setFilterRules(loggingRules.join('\n')); // Parse DBus option From 95e71b47b8e7fcbaa87aaa436b8df0e9e4755193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 10 Oct 2019 16:10:40 +0200 Subject: [PATCH 9/9] Fix comments --- server/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/main.cpp b/server/main.cpp index c3a70856..ce69a08d 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -177,8 +177,8 @@ int main(int argc, char *argv[]) * 2. Enable all debug categories if requested from command line (-p) * 3. The stored categories from the nymead.conf will be appended * 4. Add the individual command line params will be added (-d) - * 4. QT_LOGGING_CONF - * 5. QT_LOGGING_RULES + * 5. QT_LOGGING_CONF + * 6. QT_LOGGING_RULES * * The final filter rules will be set. */ @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) } nymeaSettings.endGroup(); - // Add the individual command line params will be added (-d) + // 4. Add the individual command line params will be added (-d) foreach (QString debugArea, parser.values(debugOption)) { bool enable = !debugArea.startsWith("No"); bool isWarning = debugArea.endsWith("Warnings");