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.