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. *
|
||||
* *
|
||||
@ -44,7 +44,7 @@ function selectSection(event, section) {
|
||||
|
||||
|
||||
/* ========================================================================*/
|
||||
/* Websocket connection
|
||||
/* Websocket connection for log live view
|
||||
/* ========================================================================*/
|
||||
|
||||
var webSocket = null;
|
||||
@ -126,39 +126,45 @@ function downloadFile(filePath, fileName) {
|
||||
}
|
||||
|
||||
|
||||
/* ========================================================================*/
|
||||
/* Generate report
|
||||
/* ========================================================================*/
|
||||
|
||||
var generateReportTimer = null;
|
||||
|
||||
function generateReport() {
|
||||
console.log("Requesting to generate report file " + "/debug/report");
|
||||
|
||||
var textArea = document.getElementById("generateReportTextArea");
|
||||
var button = document.getElementById("generateReportButton");
|
||||
|
||||
function pollReportResult() {
|
||||
// Request report file generation
|
||||
var reportGenerateRequest = new XMLHttpRequest();
|
||||
reportGenerateRequest.open("GET", "/debug/report", true);
|
||||
reportGenerateRequest.send(null);
|
||||
|
||||
button.disabled = true;
|
||||
textArea.value = ".";
|
||||
|
||||
// Start the timer
|
||||
generateReportTimer = setTimeout(generateReportTimerTimeout, 1000);
|
||||
|
||||
reportGenerateRequest.onreadystatechange = function() {
|
||||
if (reportGenerateRequest.readyState == 4) {
|
||||
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) {
|
||||
console.log("Report generation finished with error.");
|
||||
clearTimeout(generateReportTimer);
|
||||
textArea.value = "Something went wrong :(";
|
||||
textArea.value = "Something went wrong :(" + reportGenerateRequest.status;
|
||||
button.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop the timer
|
||||
/* The report is finished! Show information and start downloading it. */
|
||||
|
||||
/* Stop the timer */
|
||||
clearTimeout(generateReportTimer);
|
||||
var textArea = document.getElementById("generateReportTextArea");
|
||||
var button = document.getElementById("generateReportButton");
|
||||
|
||||
|
||||
console.log(reportGenerateRequest.responseText);
|
||||
var responseMap = JSON.parse(reportGenerateRequest.responseText);
|
||||
@ -190,10 +196,24 @@ function generateReport() {
|
||||
};
|
||||
}
|
||||
|
||||
function generateReportTimerTimeout() {
|
||||
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() {
|
||||
var textArea = document.getElementById("generateReportTextArea");
|
||||
textArea.value += ".";
|
||||
generateReportTimer = setTimeout(generateReportTimerTimeout, 1000);
|
||||
|
||||
pollReportResult();
|
||||
}
|
||||
|
||||
/* ========================================================================*/
|
||||
|
||||
@ -28,7 +28,9 @@
|
||||
#include <QFile>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QSysInfo>
|
||||
#include <QStandardPaths>
|
||||
#include <QCoreApplication>
|
||||
#include <QCryptographicHash>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
@ -41,6 +43,7 @@ DebugReportGenerator::DebugReportGenerator(QObject *parent) : QObject(parent)
|
||||
|
||||
DebugReportGenerator::~DebugReportGenerator()
|
||||
{
|
||||
// Clean up any leftover files
|
||||
cleanupReport();
|
||||
}
|
||||
|
||||
@ -59,6 +62,16 @@ QString DebugReportGenerator::md5Sum() const
|
||||
return m_md5Sum;
|
||||
}
|
||||
|
||||
bool DebugReportGenerator::isReady() const
|
||||
{
|
||||
return m_isReady;
|
||||
}
|
||||
|
||||
bool DebugReportGenerator::isValid() const
|
||||
{
|
||||
return m_isValid;
|
||||
}
|
||||
|
||||
void DebugReportGenerator::generateReport()
|
||||
{
|
||||
qCDebug(dcDebugServer()) << "Start generating debug report";
|
||||
@ -83,6 +96,7 @@ void DebugReportGenerator::generateReport()
|
||||
saveConfigs();
|
||||
saveLogFiles();
|
||||
saveEnv();
|
||||
saveSystemInformation();
|
||||
|
||||
QProcess *pingProcess = new QProcess(this);
|
||||
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()
|
||||
{
|
||||
QDir logDir("/var/log/");
|
||||
@ -269,18 +314,22 @@ void DebugReportGenerator::onCompressProcessFinished(int exitCode, QProcess::Exi
|
||||
QFile reportFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + m_reportFileName);
|
||||
if (!reportFile.open(QIODevice::ReadOnly)) {
|
||||
qCWarning(dcDebugServer()) << "Could not open report file name for reading" << reportFile.fileName();
|
||||
m_isReady = true;
|
||||
m_isValid = false;
|
||||
emit finished(false);
|
||||
} else {
|
||||
m_reportFileData = reportFile.readAll();
|
||||
m_md5Sum = QString::fromUtf8(QCryptographicHash::hash(m_reportFileData, QCryptographicHash::Md5).toHex());
|
||||
qCDebug(dcDebugServer()) << "File generated successfully" << reportFile.fileName() << m_reportFileData.size() << "B" << m_md5Sum;
|
||||
m_isReady = true;
|
||||
m_isValid = true;
|
||||
emit finished(true);
|
||||
}
|
||||
|
||||
reportFile.close();
|
||||
|
||||
// Todo: start expire timer
|
||||
QTimer::singleShot(30000, this, &DebugReportGenerator::timeout);
|
||||
// When this timer expires, the debug report is not valid any more and will be deleted
|
||||
QTimer::singleShot(120000, this, &DebugReportGenerator::timeout);
|
||||
|
||||
process->deleteLater();
|
||||
process = nullptr;
|
||||
|
||||
@ -34,15 +34,21 @@ public:
|
||||
explicit DebugReportGenerator(QObject *parent = nullptr);
|
||||
~DebugReportGenerator();
|
||||
|
||||
|
||||
QByteArray reportFileData() const;
|
||||
QString reportFileName();
|
||||
QString md5Sum() const;
|
||||
|
||||
bool isReady() const;
|
||||
bool isValid() const;
|
||||
|
||||
void generateReport();
|
||||
|
||||
private:
|
||||
QDir m_reportDirectory;
|
||||
QString m_reportFileName;
|
||||
bool m_isReady = false;
|
||||
bool m_isValid = false;
|
||||
|
||||
QProcess *m_compressProcess = nullptr;
|
||||
QList<QProcess *> m_runningProcesses;
|
||||
@ -53,6 +59,7 @@ private:
|
||||
void copyFileToReportDirectory(const QString &fileName, const QString &subDirectory = QString());
|
||||
void verifyRunningProcessesFinished();
|
||||
|
||||
void saveSystemInformation();
|
||||
void saveLogFiles();
|
||||
void saveConfigs();
|
||||
void saveEnv();
|
||||
|
||||
@ -378,35 +378,70 @@ 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.
|
||||
// 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
|
||||
if (requestQuery.hasQueryItem("filename")) {
|
||||
QString fileName = requestQuery.queryItemValue("filename");
|
||||
qCDebug(dcDebugServer()) << "Report download request for" << fileName;
|
||||
|
||||
if (m_finishedReportGenerators.contains(fileName)) {
|
||||
HttpReply *downloadReportReply = RestResource::createSuccessReply();
|
||||
DebugReportGenerator *generator = m_finishedReportGenerators.take(fileName);
|
||||
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) {
|
||||
qCWarning(dcDebugServer()) << "There is currently no debug report generator. The requested file does not exist.";
|
||||
return RestResource::createErrorReply(HttpReply::NotFound);
|
||||
}
|
||||
|
||||
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 {
|
||||
DebugReportGenerator *debugReportGenerator = new DebugReportGenerator(this);
|
||||
connect(debugReportGenerator, &DebugReportGenerator::finished, this, &DebugServerHandler::onDebugReportGeneratorFinished);
|
||||
connect(debugReportGenerator, &DebugReportGenerator::timeout, this, &DebugServerHandler::onDebugReportGeneratorTimeout);
|
||||
debugReportGenerator->generateReport();
|
||||
// Generate or poll request
|
||||
if (!m_debugReportGenerator) {
|
||||
qCDebug(dcDebugServer()) << "Create new debug report generator and start generating report...";
|
||||
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();
|
||||
m_runningReportGenerators.insert(debugReportGenerator, debugReportReply);
|
||||
|
||||
return debugReportReply;
|
||||
HttpReply * httpReply = RestResource::createSuccessReply();
|
||||
httpReply->setHttpStatusCode(HttpReply::Ok);
|
||||
httpReply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void DebugServerHandler::onDebugServerEnabledChanged(bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
@ -605,32 +639,14 @@ void DebugServerHandler::onDebugReportGeneratorFinished(bool success)
|
||||
{
|
||||
DebugReportGenerator *debugReportGenerator = static_cast<DebugReportGenerator *>(sender());
|
||||
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()
|
||||
{
|
||||
DebugReportGenerator *debugReportGenerator = static_cast<DebugReportGenerator *>(sender());
|
||||
qCWarning(dcDebugServer()) << "Report generation timeouted. Cleaning up" << debugReportGenerator->reportFileName();
|
||||
if (m_finishedReportGenerators.values().contains(debugReportGenerator)) {
|
||||
m_finishedReportGenerators.remove(debugReportGenerator->reportFileName());
|
||||
debugReportGenerator->deleteLater();
|
||||
qCWarning(dcDebugServer()) << "Debug report expired.";
|
||||
if (m_debugReportGenerator) {
|
||||
m_debugReportGenerator->deleteLater();
|
||||
m_debugReportGenerator = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -857,7 +873,7 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
||||
writer.writeEndElement(); // div warning
|
||||
|
||||
|
||||
// System information section
|
||||
// Server information section
|
||||
writer.writeEmptyElement("hr");
|
||||
//: The server information section of the debug interface
|
||||
writer.writeTextElement("h2", tr("Server information"));
|
||||
@ -865,71 +881,6 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
||||
|
||||
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");
|
||||
//: The server name description in the server infromation section of the debug interface
|
||||
writer.writeTextElement("th", tr("Server name"));
|
||||
@ -978,6 +929,117 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
||||
writer.writeTextElement("td", NymeaSettings(NymeaSettings::SettingsRoleGlobal).translationsPath());
|
||||
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
|
||||
|
||||
// Generate report
|
||||
@ -1627,7 +1689,7 @@ QByteArray DebugServerHandler::createDebugXmlDocument()
|
||||
// Footer
|
||||
writer.writeStartElement("div");
|
||||
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
|
||||
writer.writeTextElement("p", tr("Released under the GNU GENERAL PUBLIC LICENSE Version 2."));
|
||||
writer.writeEndElement(); // div footer
|
||||
|
||||
@ -56,8 +56,7 @@ private:
|
||||
QProcess *m_tracePathProcess = nullptr;
|
||||
HttpReply *m_tracePathReply = nullptr;
|
||||
|
||||
QHash<DebugReportGenerator *, HttpReply *> m_runningReportGenerators;
|
||||
QHash<QString, DebugReportGenerator *> m_finishedReportGenerators;
|
||||
DebugReportGenerator *m_debugReportGenerator = nullptr;
|
||||
|
||||
QByteArray loadResourceData(const QString &resourceFileName);
|
||||
QString getResourceFileName(const QString &requestPath);
|
||||
|
||||
Reference in New Issue
Block a user