Merge PR #152: Add a log viewer for the app log in developer options
This commit is contained in:
commit
f531f0e3e8
110
nymea-app/applogcontroller.cpp
Normal file
110
nymea-app/applogcontroller.cpp
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
43
nymea-app/applogcontroller.h
Normal file
43
nymea-app/applogcontroller.h
Normal 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
|
||||||
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "stylecontroller.h"
|
#include "stylecontroller.h"
|
||||||
#include "pushnotifications.h"
|
#include "pushnotifications.h"
|
||||||
|
#include "applogcontroller.h"
|
||||||
|
|
||||||
|
|
||||||
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
||||||
@ -68,6 +69,9 @@ int main(int argc, char *argv[])
|
|||||||
application.setApplicationName("nymea-app");
|
application.setApplicationName("nymea-app");
|
||||||
application.setOrganizationName("nymea");
|
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()) {
|
foreach (const QFileInfo &fi, QDir(":/ui/fonts/").entryInfoList()) {
|
||||||
QFontDatabase::addApplicationFont(fi.absoluteFilePath());
|
QFontDatabase::addApplicationFont(fi.absoluteFilePath());
|
||||||
}
|
}
|
||||||
@ -106,6 +110,8 @@ int main(int argc, char *argv[])
|
|||||||
PushNotifications::instance()->connectClient();
|
PushNotifications::instance()->connectClient();
|
||||||
qmlRegisterSingletonType<PushNotifications>("Nymea", 1, 0, "PushNotifications", PushNotifications::pushNotificationsProvider);
|
qmlRegisterSingletonType<PushNotifications>("Nymea", 1, 0, "PushNotifications", PushNotifications::pushNotificationsProvider);
|
||||||
|
|
||||||
|
qmlRegisterSingletonType<AppLogController>("Nymea", 1, 0, "AppLogController", AppLogController::appLogControllerProvider);
|
||||||
|
|
||||||
#ifdef BRANDING
|
#ifdef BRANDING
|
||||||
engine->rootContext()->setContextProperty("appBranding", BRANDING);
|
engine->rootContext()->setContextProperty("appBranding", BRANDING);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -21,12 +21,14 @@ HEADERS += \
|
|||||||
pushnotifications.h \
|
pushnotifications.h \
|
||||||
platformhelper.h \
|
platformhelper.h \
|
||||||
platformintegration/generic/platformhelpergeneric.h \
|
platformintegration/generic/platformhelpergeneric.h \
|
||||||
|
applogcontroller.h
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
stylecontroller.cpp \
|
stylecontroller.cpp \
|
||||||
pushnotifications.cpp \
|
pushnotifications.cpp \
|
||||||
platformhelper.cpp \
|
platformhelper.cpp \
|
||||||
platformintegration/generic/platformhelpergeneric.cpp \
|
platformintegration/generic/platformhelpergeneric.cpp \
|
||||||
|
applogcontroller.cpp
|
||||||
|
|
||||||
RESOURCES += resources.qrc \
|
RESOURCES += resources.qrc \
|
||||||
ruletemplates.qrc \
|
ruletemplates.qrc \
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user