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 "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
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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