Improve debug report and report download mechanism
This commit is contained in:
parent
6aa624c261
commit
79cdf8316e
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
* Copyright (C) 2018-2019 Simon Stürz <simon.stuerz@nymea.io> *
|
||||||
* *
|
* *
|
||||||
* This file is part of nymea. *
|
* This file is part of nymea. *
|
||||||
* *
|
* *
|
||||||
@ -44,7 +44,7 @@ function selectSection(event, section) {
|
|||||||
|
|
||||||
|
|
||||||
/* ========================================================================*/
|
/* ========================================================================*/
|
||||||
/* Websocket connection
|
/* Websocket connection for log live view
|
||||||
/* ========================================================================*/
|
/* ========================================================================*/
|
||||||
|
|
||||||
var webSocket = null;
|
var webSocket = null;
|
||||||
@ -126,39 +126,45 @@ function downloadFile(filePath, fileName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================================*/
|
||||||
|
/* Generate report
|
||||||
|
/* ========================================================================*/
|
||||||
|
|
||||||
var generateReportTimer = null;
|
var generateReportTimer = null;
|
||||||
|
|
||||||
function generateReport() {
|
function pollReportResult() {
|
||||||
console.log("Requesting to generate report file " + "/debug/report");
|
|
||||||
|
|
||||||
var textArea = document.getElementById("generateReportTextArea");
|
|
||||||
var button = document.getElementById("generateReportButton");
|
|
||||||
|
|
||||||
// Request report file generation
|
// Request report file generation
|
||||||
var reportGenerateRequest = new XMLHttpRequest();
|
var reportGenerateRequest = new XMLHttpRequest();
|
||||||
reportGenerateRequest.open("GET", "/debug/report", true);
|
reportGenerateRequest.open("GET", "/debug/report", true);
|
||||||
reportGenerateRequest.send(null);
|
reportGenerateRequest.send(null);
|
||||||
|
|
||||||
button.disabled = true;
|
|
||||||
textArea.value = ".";
|
|
||||||
|
|
||||||
// Start the timer
|
|
||||||
generateReportTimer = setTimeout(generateReportTimerTimeout, 1000);
|
|
||||||
|
|
||||||
reportGenerateRequest.onreadystatechange = function() {
|
reportGenerateRequest.onreadystatechange = function() {
|
||||||
if (reportGenerateRequest.readyState == 4) {
|
if (reportGenerateRequest.readyState == 4) {
|
||||||
console.log("Report generation finished with " + reportGenerateRequest.status);
|
console.log("Report generation finished with " + reportGenerateRequest.status);
|
||||||
|
|
||||||
|
/* 204: the report is not ready yet. */
|
||||||
|
if (reportGenerateRequest.status == 204) {
|
||||||
|
// Restart poll timer
|
||||||
|
generateReportTimer = setTimeout(generateReportTimerTimeout, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the generation went fine */
|
||||||
if (reportGenerateRequest.status != 200) {
|
if (reportGenerateRequest.status != 200) {
|
||||||
console.log("Report generation finished with error.");
|
console.log("Report generation finished with error.");
|
||||||
clearTimeout(generateReportTimer);
|
clearTimeout(generateReportTimer);
|
||||||
textArea.value = "Something went wrong :(";
|
textArea.value = "Something went wrong :(" + reportGenerateRequest.status;
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the timer
|
/* The report is finished! Show information and start downloading it. */
|
||||||
|
|
||||||
|
/* Stop the timer */
|
||||||
clearTimeout(generateReportTimer);
|
clearTimeout(generateReportTimer);
|
||||||
|
var textArea = document.getElementById("generateReportTextArea");
|
||||||
|
var button = document.getElementById("generateReportButton");
|
||||||
|
|
||||||
|
|
||||||
console.log(reportGenerateRequest.responseText);
|
console.log(reportGenerateRequest.responseText);
|
||||||
var responseMap = JSON.parse(reportGenerateRequest.responseText);
|
var responseMap = JSON.parse(reportGenerateRequest.responseText);
|
||||||
@ -190,10 +196,24 @@ function generateReport() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateReport() {
|
||||||
|
console.log("Requesting to generate report file " + "/debug/report");
|
||||||
|
|
||||||
|
var textArea = document.getElementById("generateReportTextArea");
|
||||||
|
var button = document.getElementById("generateReportButton");
|
||||||
|
|
||||||
|
button.disabled = true;
|
||||||
|
textArea.value = ".";
|
||||||
|
|
||||||
|
pollReportResult();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function generateReportTimerTimeout() {
|
function generateReportTimerTimeout() {
|
||||||
var textArea = document.getElementById("generateReportTextArea");
|
var textArea = document.getElementById("generateReportTextArea");
|
||||||
textArea.value += ".";
|
textArea.value += ".";
|
||||||
generateReportTimer = setTimeout(generateReportTimerTimeout, 1000);
|
|
||||||
|
pollReportResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================================================*/
|
/* ========================================================================*/
|
||||||
|
|||||||
@ -28,7 +28,9 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QSysInfo>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
|
|
||||||
@ -41,6 +43,7 @@ DebugReportGenerator::DebugReportGenerator(QObject *parent) : QObject(parent)
|
|||||||
|
|
||||||
DebugReportGenerator::~DebugReportGenerator()
|
DebugReportGenerator::~DebugReportGenerator()
|
||||||
{
|
{
|
||||||
|
// Clean up any leftover files
|
||||||
cleanupReport();
|
cleanupReport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +62,16 @@ QString DebugReportGenerator::md5Sum() const
|
|||||||
return m_md5Sum;
|
return m_md5Sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DebugReportGenerator::isReady() const
|
||||||
|
{
|
||||||
|
return m_isReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DebugReportGenerator::isValid() const
|
||||||
|
{
|
||||||
|
return m_isValid;
|
||||||
|
}
|
||||||
|
|
||||||
void DebugReportGenerator::generateReport()
|
void DebugReportGenerator::generateReport()
|
||||||
{
|
{
|
||||||
qCDebug(dcDebugServer()) << "Start generating debug report";
|
qCDebug(dcDebugServer()) << "Start generating debug report";
|
||||||
@ -83,6 +96,7 @@ void DebugReportGenerator::generateReport()
|
|||||||
saveConfigs();
|
saveConfigs();
|
||||||
saveLogFiles();
|
saveLogFiles();
|
||||||
saveEnv();
|
saveEnv();
|
||||||
|
saveSystemInformation();
|
||||||
|
|
||||||
QProcess *pingProcess = new QProcess(this);
|
QProcess *pingProcess = new QProcess(this);
|
||||||
pingProcess->setProcessChannelMode(QProcess::MergedChannels);
|
pingProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||||
@ -131,6 +145,37 @@ void DebugReportGenerator::verifyRunningProcessesFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugReportGenerator::saveSystemInformation()
|
||||||
|
{
|
||||||
|
QFile outputFile(m_reportDirectory.path() + "/sysinfo.txt");
|
||||||
|
if (!outputFile.open(QIODevice::ReadWrite)) {
|
||||||
|
qCWarning(dcDebugServer()) << "Could not open sysinfo file" << outputFile.fileName();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcDebugServer()) << "Write system information file" << outputFile.fileName();
|
||||||
|
QTextStream stream(&outputFile);
|
||||||
|
stream << "Server name: " << NymeaCore::instance()->configuration()->serverName() << endl;
|
||||||
|
stream << "Server version: " << NYMEA_VERSION_STRING << endl;
|
||||||
|
stream << "JSON-RPC version: " << JSON_PROTOCOL_VERSION << endl;
|
||||||
|
stream << "Language: " << NymeaCore::instance()->configuration()->locale().name() << " (" << NymeaCore::instance()->configuration()->locale().nativeCountryName() << " - " << NymeaCore::instance()->configuration()->locale().nativeLanguageName() << ")" << endl;
|
||||||
|
stream << "Timezone: " << QString::fromUtf8(NymeaCore::instance()->configuration()->timeZone()) << endl;
|
||||||
|
stream << "Server UUID: " << NymeaCore::instance()->configuration()->serverUuid().toString() << endl;
|
||||||
|
stream << "Settings path: " << NymeaSettings::settingsPath() << endl;
|
||||||
|
stream << "Translations path: " << NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath() << endl;
|
||||||
|
stream << "User: " << qgetenv("USER") << endl;
|
||||||
|
stream << "Command: " << QCoreApplication::arguments().join(' ') << endl;
|
||||||
|
stream << "Qt runtime version: " << qVersion() << endl;
|
||||||
|
stream << "" << endl;
|
||||||
|
stream << "Hostname: " << QSysInfo::machineHostName() << endl;
|
||||||
|
stream << "Architecture: " << QSysInfo::currentCpuArchitecture() << endl;
|
||||||
|
stream << "Kernel type: " << QSysInfo::kernelType() << endl;
|
||||||
|
stream << "Kernel version: " << QSysInfo::kernelVersion() << endl;
|
||||||
|
stream << "Product type: " << QSysInfo::productType() << endl;
|
||||||
|
stream << "Product version: " << QSysInfo::productVersion() << endl;
|
||||||
|
outputFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
void DebugReportGenerator::saveLogFiles()
|
void DebugReportGenerator::saveLogFiles()
|
||||||
{
|
{
|
||||||
QDir logDir("/var/log/");
|
QDir logDir("/var/log/");
|
||||||
@ -269,18 +314,22 @@ void DebugReportGenerator::onCompressProcessFinished(int exitCode, QProcess::Exi
|
|||||||
QFile reportFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + m_reportFileName);
|
QFile reportFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + m_reportFileName);
|
||||||
if (!reportFile.open(QIODevice::ReadOnly)) {
|
if (!reportFile.open(QIODevice::ReadOnly)) {
|
||||||
qCWarning(dcDebugServer()) << "Could not open report file name for reading" << reportFile.fileName();
|
qCWarning(dcDebugServer()) << "Could not open report file name for reading" << reportFile.fileName();
|
||||||
|
m_isReady = true;
|
||||||
|
m_isValid = false;
|
||||||
emit finished(false);
|
emit finished(false);
|
||||||
} else {
|
} else {
|
||||||
m_reportFileData = reportFile.readAll();
|
m_reportFileData = reportFile.readAll();
|
||||||
m_md5Sum = QString::fromUtf8(QCryptographicHash::hash(m_reportFileData, QCryptographicHash::Md5).toHex());
|
m_md5Sum = QString::fromUtf8(QCryptographicHash::hash(m_reportFileData, QCryptographicHash::Md5).toHex());
|
||||||
qCDebug(dcDebugServer()) << "File generated successfully" << reportFile.fileName() << m_reportFileData.size() << "B" << m_md5Sum;
|
qCDebug(dcDebugServer()) << "File generated successfully" << reportFile.fileName() << m_reportFileData.size() << "B" << m_md5Sum;
|
||||||
|
m_isReady = true;
|
||||||
|
m_isValid = true;
|
||||||
emit finished(true);
|
emit finished(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
reportFile.close();
|
reportFile.close();
|
||||||
|
|
||||||
// Todo: start expire timer
|
// When this timer expires, the debug report is not valid any more and will be deleted
|
||||||
QTimer::singleShot(30000, this, &DebugReportGenerator::timeout);
|
QTimer::singleShot(120000, this, &DebugReportGenerator::timeout);
|
||||||
|
|
||||||
process->deleteLater();
|
process->deleteLater();
|
||||||
process = nullptr;
|
process = nullptr;
|
||||||
|
|||||||
@ -34,15 +34,21 @@ public:
|
|||||||
explicit DebugReportGenerator(QObject *parent = nullptr);
|
explicit DebugReportGenerator(QObject *parent = nullptr);
|
||||||
~DebugReportGenerator();
|
~DebugReportGenerator();
|
||||||
|
|
||||||
|
|
||||||
QByteArray reportFileData() const;
|
QByteArray reportFileData() const;
|
||||||
QString reportFileName();
|
QString reportFileName();
|
||||||
QString md5Sum() const;
|
QString md5Sum() const;
|
||||||
|
|
||||||
|
bool isReady() const;
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
void generateReport();
|
void generateReport();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDir m_reportDirectory;
|
QDir m_reportDirectory;
|
||||||
QString m_reportFileName;
|
QString m_reportFileName;
|
||||||
|
bool m_isReady = false;
|
||||||
|
bool m_isValid = false;
|
||||||
|
|
||||||
QProcess *m_compressProcess = nullptr;
|
QProcess *m_compressProcess = nullptr;
|
||||||
QList<QProcess *> m_runningProcesses;
|
QList<QProcess *> m_runningProcesses;
|
||||||
@ -53,6 +59,7 @@ private:
|
|||||||
void copyFileToReportDirectory(const QString &fileName, const QString &subDirectory = QString());
|
void copyFileToReportDirectory(const QString &fileName, const QString &subDirectory = QString());
|
||||||
void verifyRunningProcessesFinished();
|
void verifyRunningProcessesFinished();
|
||||||
|
|
||||||
|
void saveSystemInformation();
|
||||||
void saveLogFiles();
|
void saveLogFiles();
|
||||||
void saveConfigs();
|
void saveConfigs();
|
||||||
void saveEnv();
|
void saveEnv();
|
||||||
|
|||||||
@ -378,35 +378,70 @@ HttpReply *DebugServerHandler::processDebugRequest(const QString &requestPath, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requestPath.startsWith("/debug/report")) {
|
if (requestPath.startsWith("/debug/report")) {
|
||||||
|
|
||||||
|
// The client can poll this url in order to get information about the current report generating process.
|
||||||
|
// If there is currently no report generated, start generating it and inform client that there is a report on the way (204)
|
||||||
|
// If there is already a report generation in progress, inform the client that it's not ready yet (204)
|
||||||
|
// If the report is ready, return information of the file and the client will start downloading it (202 and file informations).
|
||||||
|
|
||||||
// Check if download request or generate request
|
// Check if download request or generate request
|
||||||
if (requestQuery.hasQueryItem("filename")) {
|
if (requestQuery.hasQueryItem("filename")) {
|
||||||
QString fileName = requestQuery.queryItemValue("filename");
|
QString fileName = requestQuery.queryItemValue("filename");
|
||||||
qCDebug(dcDebugServer()) << "Report download request for" << fileName;
|
qCDebug(dcDebugServer()) << "Report download request for" << fileName;
|
||||||
|
|
||||||
if (m_finishedReportGenerators.contains(fileName)) {
|
if (!m_debugReportGenerator) {
|
||||||
HttpReply *downloadReportReply = RestResource::createSuccessReply();
|
qCWarning(dcDebugServer()) << "There is currently no debug report generator. The requested file does not exist.";
|
||||||
DebugReportGenerator *generator = m_finishedReportGenerators.take(fileName);
|
return RestResource::createErrorReply(HttpReply::NotFound);
|
||||||
downloadReportReply->setPayload(generator->reportFileData());
|
|
||||||
downloadReportReply->setHeader(HttpReply::ContentTypeHeader, "application/tar+gzip;");
|
|
||||||
generator->deleteLater();
|
|
||||||
|
|
||||||
return downloadReportReply;
|
|
||||||
} else {
|
|
||||||
qCWarning(dcDebugServer()) << "The requested file does not exist any more" << fileName;
|
|
||||||
HttpReply *downloadReportReply = RestResource::createErrorReply(HttpReply::NotFound);
|
|
||||||
return downloadReportReply;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_debugReportGenerator->reportFileName() != fileName) {
|
||||||
|
qCWarning(dcDebugServer()) << "The requested file is not the file from the current debug report generator" << m_debugReportGenerator->reportFileName() << "!=" << fileName;
|
||||||
|
return RestResource::createErrorReply(HttpReply::NotFound);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything looks good, send the requested debug report
|
||||||
|
HttpReply *downloadReportReply = RestResource::createSuccessReply();
|
||||||
|
downloadReportReply->setPayload(m_debugReportGenerator->reportFileData());
|
||||||
|
downloadReportReply->setHeader(HttpReply::ContentTypeHeader, "application/tar+gzip;");
|
||||||
|
return downloadReportReply;
|
||||||
} else {
|
} else {
|
||||||
DebugReportGenerator *debugReportGenerator = new DebugReportGenerator(this);
|
// Generate or poll request
|
||||||
connect(debugReportGenerator, &DebugReportGenerator::finished, this, &DebugServerHandler::onDebugReportGeneratorFinished);
|
if (!m_debugReportGenerator) {
|
||||||
connect(debugReportGenerator, &DebugReportGenerator::timeout, this, &DebugServerHandler::onDebugReportGeneratorTimeout);
|
qCDebug(dcDebugServer()) << "Create new debug report generator and start generating report...";
|
||||||
debugReportGenerator->generateReport();
|
m_debugReportGenerator = new DebugReportGenerator(this);
|
||||||
|
connect(m_debugReportGenerator, &DebugReportGenerator::finished, this, &DebugServerHandler::onDebugReportGeneratorFinished);
|
||||||
|
connect(m_debugReportGenerator, &DebugReportGenerator::timeout, this, &DebugServerHandler::onDebugReportGeneratorTimeout);
|
||||||
|
m_debugReportGenerator->generateReport();
|
||||||
|
// Note: no content will bring the client to poll this report
|
||||||
|
return RestResource::createErrorReply(HttpReply::NoContent);
|
||||||
|
} else {
|
||||||
|
// There is a running generator, check if the report is ready
|
||||||
|
if (!m_debugReportGenerator->isReady()) {
|
||||||
|
qCDebug(dcDebugServer()) << "Report is not ready yet";
|
||||||
|
// Note: no content tells the client the report is not ready yet
|
||||||
|
return RestResource::createErrorReply(HttpReply::NoContent);
|
||||||
|
} else {
|
||||||
|
if (m_debugReportGenerator->isValid()) {
|
||||||
|
// Success, the debug report is ready and valid
|
||||||
|
QVariantMap reportInformation;
|
||||||
|
reportInformation.insert("fileName", m_debugReportGenerator->reportFileName());
|
||||||
|
reportInformation.insert("fileSize", m_debugReportGenerator->reportFileData().size());
|
||||||
|
reportInformation.insert("md5sum", m_debugReportGenerator->md5Sum());
|
||||||
|
|
||||||
HttpReply *debugReportReply = RestResource::createAsyncReply();
|
HttpReply * httpReply = RestResource::createSuccessReply();
|
||||||
m_runningReportGenerators.insert(debugReportGenerator, debugReportReply);
|
httpReply->setHttpStatusCode(HttpReply::Ok);
|
||||||
|
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||||
return debugReportReply;
|
httpReply->setPayload(QJsonDocument::fromVariant(reportInformation).toJson(QJsonDocument::Indented));
|
||||||
|
return httpReply;
|
||||||
|
} else {
|
||||||
|
qCWarning(dcDebugServer()) << "The debug report generator finished with error.";
|
||||||
|
m_debugReportGenerator->deleteLater();
|
||||||
|
m_debugReportGenerator = nullptr;
|
||||||
|
return RestResource::createErrorReply(HttpReply::InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,7 +531,6 @@ HttpReply *DebugServerHandler::processDebugFileRequest(const QString &requestPat
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DebugServerHandler::onDebugServerEnabledChanged(bool enabled)
|
void DebugServerHandler::onDebugServerEnabledChanged(bool enabled)
|
||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@ -605,32 +639,14 @@ void DebugServerHandler::onDebugReportGeneratorFinished(bool success)
|
|||||||
{
|
{
|
||||||
DebugReportGenerator *debugReportGenerator = static_cast<DebugReportGenerator *>(sender());
|
DebugReportGenerator *debugReportGenerator = static_cast<DebugReportGenerator *>(sender());
|
||||||
qCDebug(dcDebugServer()) << "Report generation finished" << (success ? "successfully" : "with error") << debugReportGenerator->reportFileName();
|
qCDebug(dcDebugServer()) << "Report generation finished" << (success ? "successfully" : "with error") << debugReportGenerator->reportFileName();
|
||||||
HttpReply *httpReply = m_runningReportGenerators.take(debugReportGenerator);
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
QVariantMap reportInformation;
|
|
||||||
reportInformation.insert("fileName", debugReportGenerator->reportFileName());
|
|
||||||
reportInformation.insert("fileSize", debugReportGenerator->reportFileData().size());
|
|
||||||
reportInformation.insert("md5sum", debugReportGenerator->md5Sum());
|
|
||||||
httpReply->setHttpStatusCode(HttpReply::Ok);
|
|
||||||
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
|
||||||
httpReply->setPayload(QJsonDocument::fromVariant(reportInformation).toJson(QJsonDocument::Indented));
|
|
||||||
|
|
||||||
m_finishedReportGenerators.insert(debugReportGenerator->reportFileName(), debugReportGenerator);
|
|
||||||
} else {
|
|
||||||
httpReply->setHttpStatusCode(HttpReply::InternalServerError);
|
|
||||||
}
|
|
||||||
|
|
||||||
httpReply->finished();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugServerHandler::onDebugReportGeneratorTimeout()
|
void DebugServerHandler::onDebugReportGeneratorTimeout()
|
||||||
{
|
{
|
||||||
DebugReportGenerator *debugReportGenerator = static_cast<DebugReportGenerator *>(sender());
|
qCWarning(dcDebugServer()) << "Debug report expired.";
|
||||||
qCWarning(dcDebugServer()) << "Report generation timeouted. Cleaning up" << debugReportGenerator->reportFileName();
|
if (m_debugReportGenerator) {
|
||||||
if (m_finishedReportGenerators.values().contains(debugReportGenerator)) {
|
m_debugReportGenerator->deleteLater();
|
||||||
m_finishedReportGenerators.remove(debugReportGenerator->reportFileName());
|
m_debugReportGenerator = nullptr;
|
||||||
debugReportGenerator->deleteLater();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -857,7 +873,7 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
|||||||
writer.writeEndElement(); // div warning
|
writer.writeEndElement(); // div warning
|
||||||
|
|
||||||
|
|
||||||
// System information section
|
// Server information section
|
||||||
writer.writeEmptyElement("hr");
|
writer.writeEmptyElement("hr");
|
||||||
//: The server information section of the debug interface
|
//: The server information section of the debug interface
|
||||||
writer.writeTextElement("h2", tr("Server information"));
|
writer.writeTextElement("h2", tr("Server information"));
|
||||||
@ -865,71 +881,6 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
|||||||
|
|
||||||
writer.writeStartElement("table");
|
writer.writeStartElement("table");
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The user name in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("User"));
|
|
||||||
writer.writeTextElement("td", qgetenv("USER"));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The Qt build version description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Compiled with Qt version"));
|
|
||||||
writer.writeTextElement("td", QT_VERSION_STR);
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The Qt runtime version description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Qt runtime version"));
|
|
||||||
writer.writeTextElement("td", qVersion());
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The command description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Command"));
|
|
||||||
writer.writeTextElement("td", QCoreApplication::arguments().join(' '));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
if (!qgetenv("SNAP").isEmpty()) {
|
|
||||||
// Note: http://snapcraft.io/docs/reference/env
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The snap name description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Snap name"));
|
|
||||||
writer.writeTextElement("td", qgetenv("SNAP_NAME"));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The snap version description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Snap version"));
|
|
||||||
writer.writeTextElement("td", qgetenv("SNAP_VERSION"));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The snap directory description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Snap directory"));
|
|
||||||
writer.writeTextElement("td", qgetenv("SNAP"));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The snap application data description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Snap application data"));
|
|
||||||
writer.writeTextElement("td", qgetenv("SNAP_DATA"));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The snap user data description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Snap user data"));
|
|
||||||
writer.writeTextElement("td", qgetenv("SNAP_USER_DATA"));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
|
||||||
//: The snap common data description in the server infromation section of the debug interface
|
|
||||||
writer.writeTextElement("th", tr("Snap common data"));
|
|
||||||
writer.writeTextElement("td", qgetenv("SNAP_COMMON"));
|
|
||||||
writer.writeEndElement(); // tr
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
writer.writeStartElement("tr");
|
writer.writeStartElement("tr");
|
||||||
//: The server name description in the server infromation section of the debug interface
|
//: The server name description in the server infromation section of the debug interface
|
||||||
writer.writeTextElement("th", tr("Server name"));
|
writer.writeTextElement("th", tr("Server name"));
|
||||||
@ -978,6 +929,117 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
|||||||
writer.writeTextElement("td", NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath());
|
writer.writeTextElement("td", NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath());
|
||||||
writer.writeEndElement(); // tr
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The user name in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("User"));
|
||||||
|
writer.writeTextElement("td", qgetenv("USER"));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The command description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Command"));
|
||||||
|
writer.writeTextElement("td", QCoreApplication::arguments().join(' '));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The Qt build version description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Compiled with Qt version"));
|
||||||
|
writer.writeTextElement("td", QT_VERSION_STR);
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The Qt runtime version description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Qt runtime version"));
|
||||||
|
writer.writeTextElement("td", qVersion());
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
if (!qgetenv("SNAP").isEmpty()) {
|
||||||
|
// Note: http://snapcraft.io/docs/reference/env
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The snap name description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Snap name"));
|
||||||
|
writer.writeTextElement("td", qgetenv("SNAP_NAME"));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The snap version description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Snap version"));
|
||||||
|
writer.writeTextElement("td", qgetenv("SNAP_VERSION"));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The snap directory description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Snap directory"));
|
||||||
|
writer.writeTextElement("td", qgetenv("SNAP"));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The snap application data description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Snap application data"));
|
||||||
|
writer.writeTextElement("td", qgetenv("SNAP_DATA"));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The snap user data description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Snap user data"));
|
||||||
|
writer.writeTextElement("td", qgetenv("SNAP_USER_DATA"));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The snap common data description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Snap common data"));
|
||||||
|
writer.writeTextElement("td", qgetenv("SNAP_COMMON"));
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeEndElement(); // table
|
||||||
|
|
||||||
|
|
||||||
|
// System information section
|
||||||
|
writer.writeEmptyElement("hr");
|
||||||
|
//: The system information section of the debug interface
|
||||||
|
writer.writeTextElement("h2", tr("System information"));
|
||||||
|
writer.writeEmptyElement("hr");
|
||||||
|
|
||||||
|
writer.writeStartElement("table");
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The command description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Hostname"));
|
||||||
|
writer.writeTextElement("td", QSysInfo::machineHostName());
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The command description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Architecture"));
|
||||||
|
writer.writeTextElement("td", QSysInfo::currentCpuArchitecture());
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The command description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Kernel type"));
|
||||||
|
writer.writeTextElement("td", QSysInfo::kernelType());
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The command description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Kernel version"));
|
||||||
|
writer.writeTextElement("td", QSysInfo::kernelVersion());
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The command description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Product type"));
|
||||||
|
writer.writeTextElement("td", QSysInfo::productType());
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
|
writer.writeStartElement("tr");
|
||||||
|
//: The command description in the server infromation section of the debug interface
|
||||||
|
writer.writeTextElement("th", tr("Product version"));
|
||||||
|
writer.writeTextElement("td", QSysInfo::productVersion());
|
||||||
|
writer.writeEndElement(); // tr
|
||||||
|
|
||||||
writer.writeEndElement(); // table
|
writer.writeEndElement(); // table
|
||||||
|
|
||||||
// Generate report
|
// Generate report
|
||||||
@ -1627,7 +1689,7 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
|||||||
// Footer
|
// Footer
|
||||||
writer.writeStartElement("div");
|
writer.writeStartElement("div");
|
||||||
writer.writeAttribute("class", "footer");
|
writer.writeAttribute("class", "footer");
|
||||||
writer.writeTextElement("p", QString("Copyright %1 2018 guh GmbH.").arg(QChar(0xA9)));
|
writer.writeTextElement("p", QString("Copyright %1 %2 guh GmbH.").arg(QChar(0xA9)).arg(COPYRIGHT_YEAR_STRING));
|
||||||
//: The footer license note of the debug interface
|
//: The footer license note of the debug interface
|
||||||
writer.writeTextElement("p", tr("Released under the GNU GENERAL PUBLIC LICENSE Version 2."));
|
writer.writeTextElement("p", tr("Released under the GNU GENERAL PUBLIC LICENSE Version 2."));
|
||||||
writer.writeEndElement(); // div footer
|
writer.writeEndElement(); // div footer
|
||||||
|
|||||||
@ -56,8 +56,7 @@ private:
|
|||||||
QProcess *m_tracePathProcess = nullptr;
|
QProcess *m_tracePathProcess = nullptr;
|
||||||
HttpReply *m_tracePathReply = nullptr;
|
HttpReply *m_tracePathReply = nullptr;
|
||||||
|
|
||||||
QHash<DebugReportGenerator *, HttpReply *> m_runningReportGenerators;
|
DebugReportGenerator *m_debugReportGenerator = nullptr;
|
||||||
QHash<QString, DebugReportGenerator *> m_finishedReportGenerators;
|
|
||||||
|
|
||||||
QByteArray loadResourceData(const QString &resourceFileName);
|
QByteArray loadResourceData(const QString &resourceFileName);
|
||||||
QString getResourceFileName(const QString &requestPath);
|
QString getResourceFileName(const QString &requestPath);
|
||||||
|
|||||||
Reference in New Issue
Block a user