From b0a38816fc507c8f06f38c2bc2ecae8c153b8b87 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 5 Oct 2020 17:48:30 +0200 Subject: [PATCH 1/7] Change the defaults for logging Turn on the logging by default for everyone. Let's use a log dir within the config directory of the application and have debug logs expiring after a day. This obviously means we'll generate quite some logs but with the automated compression it shouldn't be too horrible. Obviously that scales with the amount of files and syncs occurring. In our tests with a large setup we're around 100 MB for a day worth of logs, this shouldn't be too much of an issue on today's average desktop/laptop. Signed-off-by: Kevin Ottens --- src/libsync/configfile.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libsync/configfile.cpp b/src/libsync/configfile.cpp index c4e81110cd..da4aca58e1 100644 --- a/src/libsync/configfile.cpp +++ b/src/libsync/configfile.cpp @@ -901,8 +901,9 @@ void ConfigFile::setAutomaticLogDir(bool enabled) QString ConfigFile::logDir() const { + const auto defaultLogDir = QString(configPath() + QStringLiteral("/logs")); QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(QLatin1String(logDirC), QString()).toString(); + return settings.value(QLatin1String(logDirC), defaultLogDir).toString(); } void ConfigFile::setLogDir(const QString &dir) @@ -914,7 +915,7 @@ void ConfigFile::setLogDir(const QString &dir) bool ConfigFile::logDebug() const { QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(QLatin1String(logDebugC), false).toBool(); + return settings.value(QLatin1String(logDebugC), true).toBool(); } void ConfigFile::setLogDebug(bool enabled) @@ -926,7 +927,7 @@ void ConfigFile::setLogDebug(bool enabled) int ConfigFile::logExpire() const { QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(QLatin1String(logExpireC), 0).toBool(); + return settings.value(QLatin1String(logExpireC), 24).toBool(); } void ConfigFile::setLogExpire(int hours) From 167800320ff0fbeda001f3a355e6d0896fabb5ca Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 5 Oct 2020 19:34:46 +0200 Subject: [PATCH 2/7] Make sure --logfile has precedence on config Since we changed the default in the config file and since log dir had precedence on log file, the --logfile command line option wasn't doing anything anymore. We make sure it has an effect again overriding --logdir or the logDir config entry. Signed-off-by: Kevin Ottens --- src/gui/application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/application.cpp b/src/gui/application.cpp index 9ac569cbc8..a408b392bf 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -408,7 +408,9 @@ void Application::setupLogging() // might be called from second instance auto logger = Logger::instance(); logger->setLogFile(_logFile); - logger->setLogDir(!_logDir.isEmpty() ? _logDir : ConfigFile().logDir()); + if (_logFile.isEmpty()) { + logger->setLogDir(_logDir.isEmpty() ? ConfigFile().logDir() : _logDir); + } logger->setLogExpire(_logExpire > 0 ? _logExpire : ConfigFile().logExpire()); logger->setLogFlush(_logFlush || ConfigFile().logFlush()); logger->setLogDebug(_logDebug || ConfigFile().logDebug()); From 607347289ea3eb03b59bb72c75b9552a34d7b787 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 5 Oct 2020 19:36:25 +0200 Subject: [PATCH 3/7] Expose more of the logger state It is better to rely on the Logger state to know exactly where we're logging. Indeed due to the the various ways to impact its state the config alone might not now where we're logging. Signed-off-by: Kevin Ottens --- src/libsync/logger.cpp | 10 ++++++++++ src/libsync/logger.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/src/libsync/logger.cpp b/src/libsync/logger.cpp index 6827308e1a..d5d2048314 100644 --- a/src/libsync/logger.cpp +++ b/src/libsync/logger.cpp @@ -167,6 +167,11 @@ void Logger::setLogWindowActivated(bool activated) _logWindowActivated = activated; } +QString Logger::logFile() const +{ + return _logFile.fileName(); +} + void Logger::setLogFile(const QString &name) { QMutexLocker locker(&_mutex); @@ -204,6 +209,11 @@ void Logger::setLogExpire(int expire) _logExpire = expire; } +QString Logger::logDir() const +{ + return _logDirectory; +} + void Logger::setLogDir(const QString &dir) { _logDirectory = dir; diff --git a/src/libsync/logger.h b/src/libsync/logger.h index 5f32a8a0d8..12973c71c1 100644 --- a/src/libsync/logger.h +++ b/src/libsync/logger.h @@ -60,9 +60,15 @@ public: void postGuiMessage(const QString &title, const QString &message); void setLogWindowActivated(bool activated); + + QString logFile() const; void setLogFile(const QString &name); + void setLogExpire(int expire); + + QString logDir() const; void setLogDir(const QString &dir); + void setLogFlush(bool flush); bool logDebug() const { return _logDebug; } From 15d294e7fb4fb7948b9837ff686118cf66be7ad1 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 5 Oct 2020 19:20:26 +0200 Subject: [PATCH 4/7] Add dependency on QtGuiPrivate I'm not a huge fan of using private APIs but QZip is really the API with the least hassles for our debug archive need. No external dependency and we know it is generally available and stable despite the lack of stability promise. Signed-off-by: Kevin Ottens --- src/gui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 2f1e99e2ba..97a3c19af4 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -314,7 +314,7 @@ set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE};${CMAKE_INSTALL_RPATH}" ) -target_link_libraries( ${APPLICATION_EXECUTABLE} Qt5::Widgets Qt5::Svg Qt5::Network Qt5::Xml Qt5::Qml Qt5::Quick Qt5::QuickControls2 Qt5::WebEngineWidgets) +target_link_libraries( ${APPLICATION_EXECUTABLE} Qt5::Widgets Qt5::GuiPrivate Qt5::Svg Qt5::Network Qt5::Xml Qt5::Qml Qt5::Quick Qt5::QuickControls2 Qt5::WebEngineWidgets) target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} ) IF(BUILD_UPDATER) target_link_libraries( ${APPLICATION_EXECUTABLE} updater ) From 8fb673457b42e9bf37562568410a7382ed50448d Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 5 Oct 2020 19:45:40 +0200 Subject: [PATCH 5/7] Add a button to create a debug archive This will harvest everything we might need for debugging purposes: * config file * sync journal dbs * log files Signed-off-by: Kevin Ottens --- src/gui/generalsettings.cpp | 93 +++++++++++++++++++++++++++++++++++++ src/gui/generalsettings.h | 1 + src/gui/generalsettings.ui | 11 ++++- 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/gui/generalsettings.cpp b/src/gui/generalsettings.cpp index fff5c9076b..f910601ac6 100644 --- a/src/gui/generalsettings.cpp +++ b/src/gui/generalsettings.cpp @@ -30,21 +30,102 @@ #include "ignorelisteditor.h" #include "common/utility.h" +#include "logger.h" #include "config.h" #include "legalnotice.h" +#include +#include #include #include #include +#include + #define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0)) #if !(QTLEGACY) #include #endif +namespace { +struct ZipEntry { + QString localFilename; + QString zipFilename; +}; + +ZipEntry fileInfoToZipEntry(const QFileInfo &info) +{ + return { + info.absoluteFilePath(), + info.fileName() + }; +} + +ZipEntry fileInfoToLogZipEntry(const QFileInfo &info) +{ + auto entry = fileInfoToZipEntry(info); + entry.zipFilename.prepend(QStringLiteral("logs/")); + return entry; +} + +ZipEntry syncFolderToZipEntry(OCC::Folder *f) +{ + const auto journalPath = f->journalDb()->databaseFilePath(); + const auto journalInfo = QFileInfo(journalPath); + return fileInfoToZipEntry(journalInfo); +} + +QVector createFileList() +{ + auto list = QVector(); + OCC::ConfigFile cfg; + + list.append(fileInfoToZipEntry(QFileInfo(cfg.configFile()))); + + const auto logger = OCC::Logger::instance(); + + if (!logger->logDir().isEmpty()) { + list.append({QString(), QStringLiteral("logs")}); + + QDir dir(logger->logDir()); + const auto infoList = dir.entryInfoList(QDir::Files); + std::transform(std::cbegin(infoList), std::cend(infoList), + std::back_inserter(list), + fileInfoToLogZipEntry); + } else if (!logger->logFile().isEmpty()) { + list.append(fileInfoToZipEntry(QFileInfo(logger->logFile()))); + } + + const auto folders = OCC::FolderMan::instance()->map().values(); + std::transform(std::cbegin(folders), std::cend(folders), + std::back_inserter(list), + syncFolderToZipEntry); + + return list; +} + +void createDebugArchive(const QString &filename) +{ + const auto entries = createFileList(); + + QZipWriter zip(filename); + for (const auto &entry : entries) { + if (entry.localFilename.isEmpty()) { + zip.addDirectory(entry.zipFilename); + } else { + QFile file(entry.localFilename); + if (!file.open(QFile::ReadOnly)) { + continue; + } + zip.addFile(entry.zipFilename, &file); + } + } +} +} + namespace OCC { GeneralSettings::GeneralSettings(QWidget *parent) @@ -122,6 +203,7 @@ GeneralSettings::GeneralSettings(QWidget *parent) _ui->monoIconsCheckBox->setVisible(Theme::instance()->monoIconsAvailable()); connect(_ui->ignoredFilesButton, &QAbstractButton::clicked, this, &GeneralSettings::slotIgnoreFilesEditor); + connect(_ui->debugArchiveButton, &QAbstractButton::clicked, this, &GeneralSettings::slotCreateDebugArchive); // accountAdded means the wizard was finished and the wizard might change some options. connect(AccountManager::instance(), &AccountManager::accountAdded, this, &GeneralSettings::loadMiscSettings); @@ -260,6 +342,17 @@ void GeneralSettings::slotIgnoreFilesEditor() } } +void GeneralSettings::slotCreateDebugArchive() +{ + const auto filename = QFileDialog::getSaveFileName(this, tr("Create Debug Archive"), QString(), tr("Zip Archives") + " (*.zip)"); + if (filename.isEmpty()) { + return; + } + + createDebugArchive(filename); + QMessageBox::information(this, tr("Debug Archive Created"), tr("Debug archive is created at %1").arg(filename)); +} + void GeneralSettings::slotShowLegalNotice() { auto notice = new LegalNotice(); diff --git a/src/gui/generalsettings.h b/src/gui/generalsettings.h index 4b5e6a538f..fa6fe11b9c 100644 --- a/src/gui/generalsettings.h +++ b/src/gui/generalsettings.h @@ -48,6 +48,7 @@ private slots: void slotToggleOptionalServerNotifications(bool); void slotShowInExplorerNavigationPane(bool); void slotIgnoreFilesEditor(); + void slotCreateDebugArchive(); void loadMiscSettings(); void slotShowLegalNotice(); #if defined(BUILD_UPDATER) diff --git a/src/gui/generalsettings.ui b/src/gui/generalsettings.ui index ebc69ebd66..67e9af6ee9 100644 --- a/src/gui/generalsettings.ui +++ b/src/gui/generalsettings.ui @@ -6,8 +6,8 @@ 0 0 - 516 - 523 + 553 + 558 @@ -219,6 +219,13 @@ + + + + Create Debug Archive... + + + From 8ce137cc5358be3ac56635360c38fd6c12aaba71 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 5 Oct 2020 19:45:47 +0200 Subject: [PATCH 6/7] Also add the command line arguments in the archive Signed-off-by: Kevin Ottens --- src/gui/generalsettings.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/generalsettings.cpp b/src/gui/generalsettings.cpp index f910601ac6..804a9974d4 100644 --- a/src/gui/generalsettings.cpp +++ b/src/gui/generalsettings.cpp @@ -123,6 +123,8 @@ void createDebugArchive(const QString &filename) zip.addFile(entry.zipFilename, &file); } } + + zip.addFile("__nextcloud_client_parameters.txt", QCoreApplication::arguments().join(' ').toUtf8()); } } From 3fca307fbb3a183504e0abb2b988bf26c892bea8 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 5 Oct 2020 21:56:42 +0200 Subject: [PATCH 7/7] Also add build infos in the archive Signed-off-by: Kevin Ottens --- src/gui/generalsettings.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/generalsettings.cpp b/src/gui/generalsettings.cpp index 804a9974d4..8e57eb8d1d 100644 --- a/src/gui/generalsettings.cpp +++ b/src/gui/generalsettings.cpp @@ -125,6 +125,9 @@ void createDebugArchive(const QString &filename) } zip.addFile("__nextcloud_client_parameters.txt", QCoreApplication::arguments().join(' ').toUtf8()); + + const auto buildInfo = QString(OCC::Theme::instance()->about() + "\n\n" + OCC::Theme::instance()->aboutDetails()); + zip.addFile("__nextcloud_client_buildinfo.txt", buildInfo.toUtf8()); } }