Merge PR #152: Add a log viewer for the app log in developer options

This commit is contained in:
Jenkins 2019-02-12 16:47:59 +01:00
commit f531f0e3e8
5 changed files with 208 additions and 0 deletions

View File

@ -0,0 +1,110 @@
#include "applogcontroller.h"
#include <QStandardPaths>
#include <QDebug>
#include <QSettings>
QtMessageHandler AppLogController::s_oldLogMessageHandler = nullptr;
QObject *AppLogController::appLogControllerProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return instance();
}
AppLogController *AppLogController::instance()
{
static AppLogController* thiz = nullptr;
if (!thiz) {
thiz = new AppLogController();
}
return thiz;
}
AppLogController::AppLogController(QObject *parent) : QObject(parent)
{
QString fileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/nymea-app.log";
m_logFile.setFileName(fileName);
qDebug() << "App log file:" << fileName;
if (!m_logFile.open(QFile::ReadWrite)) {
qDebug() << "Cannot open logfile for writing";
return;
}
qDebug() << "Logging is" << (enabled() ? "enabled" : "disabled");
if (enabled()) {
activate();
}
}
bool AppLogController::canWriteLogs() const
{
return m_logFile.isOpen();
}
bool AppLogController::enabled() const
{
QSettings settings;
return settings.value("AppLoggingEnabled", false).toBool();
}
void AppLogController::setEnabled(bool enabled)
{
if (enabled == this->enabled()) {
return;
}
if (enabled) {
if (!canWriteLogs()) {
qWarning() << "Cannot write log file. Not enabling logging.";
return;
}
activate();
} else {
deactivate();
}
QSettings settings;
settings.setValue("AppLoggingEnabled", enabled);
emit enabledChanged();
}
QByteArray AppLogController::content()
{
return m_buffer;
}
void AppLogController::logMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
s_oldLogMessageHandler(type, context, message);
QString finalMessage = message + "\n";
instance()->m_logFile.write(finalMessage.toUtf8());
instance()->m_logFile.flush();
instance()->m_buffer.append(finalMessage);
int maxBuffer = 1024 * 1024;
if (instance()->m_buffer.size() > maxBuffer) {
instance()->m_buffer.remove(0, instance()->m_buffer.size() - maxBuffer);
}
emit instance()->contentChanged();
emit instance()->contentAdded(finalMessage.toUtf8());
}
void AppLogController::activate()
{
qDebug() << "Activating log file writing";
s_oldLogMessageHandler = qInstallMessageHandler(&logMessageHandler);
}
void AppLogController::deactivate()
{
qInstallMessageHandler(s_oldLogMessageHandler);
s_oldLogMessageHandler = nullptr;
}

View File

@ -0,0 +1,43 @@
#ifndef APPLOGCONTROLLER_H
#define APPLOGCONTROLLER_H
#include <QObject>
#include <QFile>
#include <QQmlEngine>
class AppLogController : public QObject
{
Q_OBJECT
Q_PROPERTY(bool canWriteLogs READ canWriteLogs CONSTANT)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(QByteArray content READ content NOTIFY contentChanged)
public:
static QObject* appLogControllerProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
static AppLogController* instance();
bool canWriteLogs() const;
bool enabled() const;
void setEnabled(bool enabled);
QByteArray content();
signals:
void enabledChanged();
void contentChanged();
void contentAdded(const QByteArray &newContent);
private:
explicit AppLogController(QObject *parent = nullptr);
static QtMessageHandler s_oldLogMessageHandler;
static void logMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);
void activate();
void deactivate();
QFile m_logFile;
QByteArray m_buffer;
};
#endif // APPLOGCONTROLLER_H

View File

@ -38,6 +38,7 @@
#include "stylecontroller.h"
#include "pushnotifications.h"
#include "applogcontroller.h"
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
@ -68,6 +69,9 @@ int main(int argc, char *argv[])
application.setApplicationName("nymea-app");
application.setOrganizationName("nymea");
// Initialize app log controller as early as possible, but after setting app name etc
AppLogController::instance();
foreach (const QFileInfo &fi, QDir(":/ui/fonts/").entryInfoList()) {
QFontDatabase::addApplicationFont(fi.absoluteFilePath());
}
@ -106,6 +110,8 @@ int main(int argc, char *argv[])
PushNotifications::instance()->connectClient();
qmlRegisterSingletonType<PushNotifications>("Nymea", 1, 0, "PushNotifications", PushNotifications::pushNotificationsProvider);
qmlRegisterSingletonType<AppLogController>("Nymea", 1, 0, "AppLogController", AppLogController::appLogControllerProvider);
#ifdef BRANDING
engine->rootContext()->setContextProperty("appBranding", BRANDING);
#else

View File

@ -21,12 +21,14 @@ HEADERS += \
pushnotifications.h \
platformhelper.h \
platformintegration/generic/platformhelpergeneric.h \
applogcontroller.h
SOURCES += main.cpp \
stylecontroller.cpp \
pushnotifications.cpp \
platformhelper.cpp \
platformintegration/generic/platformhelpergeneric.cpp \
applogcontroller.cpp
RESOURCES += resources.qrc \
ruletemplates.qrc \

View File

@ -31,5 +31,52 @@ Page {
}
}
}
CheckDelegate {
text: qsTr("Enable app logging")
enabled: AppLogController.canWriteLogs
checked: AppLogController.enabled
onCheckedChanged: AppLogController.enabled = checked;
Layout.fillWidth: true
}
MeaListItemDelegate {
Layout.fillWidth: true
text: qsTr("View log")
onClicked: pageStack.push(appLogComponent)
enabled: AppLogController.enabled
}
}
Component {
id: appLogComponent
Page {
header: GuhHeader {
text: qsTr("App log")
backButtonVisible: true
onBackPressed: pageStack.pop()
}
ScrollView {
anchors.fill: parent
TextArea {
id: logArea
wrapMode: Text.WordWrap
readOnly: true
font.pixelSize: app.smallFont
Component.onCompleted: {
text = AppLogController.content
}
Connections {
target: AppLogController
onContentAdded: {
logArea.append(newContent)
}
}
}
}
}
}
}