[krita] /: Add usage logging to the buginfo dialog

Boudewijn Rempt null at kde.org
Tue Feb 5 11:06:27 GMT 2019


Git commit caebac3e0a04c0200e9502ee76c26fab86277d56 by Boudewijn Rempt.
Committed on 05/02/2019 at 11:01.
Pushed by rempt into branch 'master'.

Add usage logging to the buginfo dialog

We can now log important events to a krita.log file. It is completely
independent of qDebug, and only meant for those actions that we know
users often get wrong or have problems with. Right now, it logs
creating, loading, exporting and saving a file, and switching between
the smoothing options.

The krita.log file is NOT automatically uploaded or shared or anything
like that. The header that explains this is translated so users can
see that for themselves.

We rotate 10 sessions in the log file, so even if the user starts Krita
a few times after having a problem, we should still be able to review
the problematical session.

The logging api is pretty simple: a static KisUsageLogger::log method
that writes a timestamp, and a KisUsageLogger::write method that writes
an informational line without a timestamp.

Note that the logger is created and torn down in the main function:
this means that the location is GenericDataLocation, not AppDataLocation.

CCMAIL:kimageshop at kde.org

M  +24   -3    krita/main.cc
M  +2    -0    libs/global/CMakeLists.txt
A  +160  -0    libs/global/KisUsageLogger.cpp     [License: GPL (v2+)]
A  +61   -0    libs/global/KisUsageLogger.h     [License: GPL (v2+)]
M  +40   -3    libs/ui/KisDocument.cpp
M  +21   -3    libs/ui/KisImportExportManager.cpp
M  +3    -1    libs/ui/dialogs/kis_dlg_preferences.cc
M  +22   -5    libs/ui/forms/wdggeneralsettings.ui
M  +28   -17   libs/ui/input/wintab/kis_tablet_support_win.cpp
M  +10   -0    libs/ui/kis_statusbar.cc
M  +2    -0    libs/ui/kis_statusbar.h
M  +7    -2    libs/ui/opengl/kis_opengl.cpp
M  +48   -33   plugins/extensions/buginfo/dlg_buginfo.cpp
M  +8    -0    plugins/tools/basictools/kis_tool_brush.cc

https://commits.kde.org/krita/caebac3e0a04c0200e9502ee76c26fab86277d56

diff --git a/krita/main.cc b/krita/main.cc
index c7c03a657fb..6ddeaf3fc7b 100644
--- a/krita/main.cc
+++ b/krita/main.cc
@@ -32,6 +32,7 @@
 #include <QSettings>
 #include <QByteArray>
 #include <QMessageBox>
+#include <QThread>
 
 #if QT_VERSION >= 0x050900
 #include <QOperatingSystemVersion>
@@ -54,6 +55,8 @@
 #include "KisApplicationArguments.h"
 #include <opengl/kis_opengl.h>
 #include "input/KisQtWidgetsTweaker.h"
+#include <KisUsageLogger.h>
+#include <kis_image_config.h>
 
 #if defined Q_OS_WIN
 #include <windows.h>
@@ -152,21 +155,22 @@ extern "C" int main(int argc, char **argv)
 #endif
 
     const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
+    QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
 
     bool singleApplication = true;
     bool enableOpenGLDebug = false;
     bool openGLDebugSynchronous = false;
+    bool logUsage = true;
     {
-        QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
+
         singleApplication = kritarc.value("EnableSingleApplication", true).toBool();
-#if QT_VERSION >= 0x050600
         if (kritarc.value("EnableHiDPI", true).toBool()) {
             QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
         }
         if (!qgetenv("KRITA_HIDPI").isEmpty()) {
             QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
         }
-#endif
+
         if (!qgetenv("KRITA_OPENGL_DEBUG").isEmpty()) {
             enableOpenGLDebug = true;
         } else {
@@ -178,6 +182,8 @@ extern "C" int main(int argc, char **argv)
 
         KisOpenGL::setDefaultFormat(enableOpenGLDebug, openGLDebugSynchronous);
 
+        logUsage = kritarc.value("LogUsage", true).toBool();
+
 #ifdef Q_OS_WIN
         QString preferredOpenGLRenderer = kritarc.value("OpenGLRenderer", "auto").toString();
 
@@ -194,6 +200,10 @@ extern "C" int main(int argc, char **argv)
 #endif
     }
 
+    if (logUsage) {
+        KisUsageLogger::initialize();
+    }
+
 
     QString root;
     QString language;
@@ -456,6 +466,13 @@ extern "C" int main(int argc, char **argv)
     QObject::connect(&app, SIGNAL(fileOpenRequest(QString)),
                      &app, SLOT(fileOpenRequested(QString)));
 
+    // Hardware information
+    KisUsageLogger::write("\nHardware Information\n");
+    KisUsageLogger::write(QString("  GPU Acceleration: %1").arg(kritarc.value("OpenGLRenderer", "auto").toString()));
+    KisUsageLogger::write(QString("  Memory: %1 Mb").arg(KisImageConfig(true).totalRAM()));
+    KisUsageLogger::write(QString("  Number of Cores: %1").arg(QThread::idealThreadCount()));
+    KisUsageLogger::write(QString("  Swap Location: %1\n").arg(KisImageConfig(true).swapDir()));
+
     int state = app.exec();
 
     {
@@ -463,5 +480,9 @@ extern "C" int main(int argc, char **argv)
         kritarc.setValue("canvasState", "OPENGL_SUCCESS");
     }
 
+    if (logUsage) {
+        KisUsageLogger::close();
+    }
+
     return state;
 }
diff --git a/libs/global/CMakeLists.txt b/libs/global/CMakeLists.txt
index 74e53b84568..873eb80db64 100644
--- a/libs/global/CMakeLists.txt
+++ b/libs/global/CMakeLists.txt
@@ -30,6 +30,7 @@ set(kritaglobal_LIB_SRCS
     KisRollingMeanAccumulatorWrapper.cpp
     kis_config_notifier.cpp
     KisDeleteLaterWrapper.cpp
+    KisUsageLogger.cpp
 )
 
 add_library(kritaglobal SHARED ${kritaglobal_LIB_SRCS} )
@@ -37,6 +38,7 @@ generate_export_header(kritaglobal BASE_NAME kritaglobal)
 
 target_link_libraries(kritaglobal 
     PUBLIC
+        kritaversion
         Qt5::Concurrent 
         Qt5::Core 
         Qt5::Gui 
diff --git a/libs/global/KisUsageLogger.cpp b/libs/global/KisUsageLogger.cpp
new file mode 100644
index 00000000000..c1df8321610
--- /dev/null
+++ b/libs/global/KisUsageLogger.cpp
@@ -0,0 +1,160 @@
+/*
+ *  Copyright (c) 2019 Boudewijn Rempt <boud at valdyas.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "KisUsageLogger.h"
+
+#include <QGlobalStatic>
+#include <QDebug>
+#include <QDateTime>
+#include <QSysInfo>
+#include <QStandardPaths>
+#include <QFile>
+#include <QDesktopWidget>
+#include <QClipboard>
+#include <QThread>
+
+#include <klocalizedstring.h>
+#include <KritaVersionWrapper.h>
+
+
+Q_GLOBAL_STATIC(KisUsageLogger, s_instance)
+
+const QString KisUsageLogger::s_sectionHeader("================================================================================\n");
+
+struct KisUsageLogger::Private {
+    bool active {false};
+    QFile logFile;
+};
+
+KisUsageLogger::KisUsageLogger()
+    : d(new Private)
+{
+    d->logFile.setFileName(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/krita.log");
+
+    rotateLog();
+    d->logFile.open(QFile::Append);
+    writeHeader();
+}
+
+KisUsageLogger::~KisUsageLogger()
+{
+    if (d->active) {
+        close();
+    }
+}
+
+void KisUsageLogger::initialize()
+{
+    s_instance->d->active = true;
+}
+
+void KisUsageLogger::close()
+{
+    log("Closing.");
+    s_instance->d->active = false;
+    s_instance->d->logFile.flush();
+    s_instance->d->logFile.close();
+}
+
+void KisUsageLogger::log(const QString &message)
+{
+    if (!s_instance->d->active) return;
+    if (!s_instance->d->logFile.isOpen()) return;
+
+    s_instance->d->logFile.write(QDateTime::currentDateTime().toString(Qt::RFC2822Date).toUtf8());
+    s_instance->d->logFile.write(": ");
+    write(message);
+}
+
+void KisUsageLogger::write(const QString &message)
+{
+    if (!s_instance->d->active) return;
+    if (!s_instance->d->logFile.isOpen()) return;
+
+    s_instance->d->logFile.write(message.toUtf8());
+    s_instance->d->logFile.write("\n");
+
+    s_instance->d->logFile.flush();
+}
+
+void KisUsageLogger::writeHeader()
+{
+    Q_ASSERT(d->logFile.isOpen());
+
+    QString sessionHeader = QString("SESSION: %1\n\n").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date));
+    QString disclaimer = i18n("WARNING: This file contains information about your system and the\n"
+                              "images you have been working with.\n"
+                              "\n"
+                              "If you have problems with Krita, the Krita developers might ask\n"
+                              "you to share this file with them. The information in this file is\n"
+                              "not shared automatically with the Krita developers in any way. You\n"
+                              "can disable logging to this file in Krita's Configure Krita Dialog.\n"
+                              "\n"
+                              "Please review the contents of this file before sharing this file with\n"
+                              "anyone.\n\n");
+
+    QString systemInfo;
+
+    // NOTE: This is intentionally not translated!
+
+    // Krita version info
+    systemInfo.append("Krita\n");
+    systemInfo.append("\n  Version: ").append(KritaVersionWrapper::versionString(true));
+    systemInfo.append("\n\n");
+
+    systemInfo.append("Qt\n");
+    systemInfo.append("\n  Version (compiled): ").append(QT_VERSION_STR);
+    systemInfo.append("\n  Version (loaded): ").append(qVersion());
+    systemInfo.append("\n\n");
+
+    // OS information
+    systemInfo.append("OS Information\n");
+    systemInfo.append("\n  Build ABI: ").append(QSysInfo::buildAbi());
+    systemInfo.append("\n  Build CPU: ").append(QSysInfo::buildCpuArchitecture());
+    systemInfo.append("\n  CPU: ").append(QSysInfo::currentCpuArchitecture());
+    systemInfo.append("\n  Kernel Type: ").append(QSysInfo::kernelType());
+    systemInfo.append("\n  Kernel Version: ").append(QSysInfo::kernelVersion());
+    systemInfo.append("\n  Pretty Productname: ").append(QSysInfo::prettyProductName());
+    systemInfo.append("\n  Product Type: ").append(QSysInfo::productType());
+    systemInfo.append("\n  Product Version: ").append(QSysInfo::productVersion());
+    systemInfo.append("\n\n");
+
+    d->logFile.write(s_sectionHeader.toUtf8());
+    d->logFile.write(sessionHeader.toUtf8());
+    d->logFile.write(disclaimer.toUtf8());
+    d->logFile.write(systemInfo.toUtf8());
+
+
+}
+
+void KisUsageLogger::rotateLog()
+{
+    d->logFile.open(QFile::ReadOnly);
+    QString log = QString::fromUtf8(d->logFile.readAll());
+    int sectionCount = log.count(s_sectionHeader);
+    int nextSectionIndex = log.indexOf(s_sectionHeader, s_sectionHeader.length());
+    while(sectionCount >= s_maxLogs) {
+        log = log.remove(0, log.indexOf(s_sectionHeader, nextSectionIndex));
+        nextSectionIndex = log.indexOf(s_sectionHeader, s_sectionHeader.length());
+        sectionCount = log.count(s_sectionHeader);
+    }
+    d->logFile.close();
+    d->logFile.open(QFile::WriteOnly);
+    d->logFile.write(log.toUtf8());
+    d->logFile.close();
+}
+
diff --git a/libs/global/KisUsageLogger.h b/libs/global/KisUsageLogger.h
new file mode 100644
index 00000000000..5f128259f61
--- /dev/null
+++ b/libs/global/KisUsageLogger.h
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2019 Boudewijn Rempt <boud at valdyas.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KISUSAGELOGGER_H
+#define KISUSAGELOGGER_H
+
+#include <QString>
+#include <QScopedPointer>
+
+#include "kritaglobal_export.h"
+
+/**
+ * @brief The KisUsageLogger class logs messages to a logfile
+ */
+class KRITAGLOBAL_EXPORT KisUsageLogger
+{
+
+public:
+
+    KisUsageLogger();
+    ~KisUsageLogger();
+
+    static void initialize();
+    static void close();
+
+    /// Logs with date/time
+    static void log(const QString &message);
+
+    /// Writes without date/time
+    static void write(const QString &message);
+
+private:
+
+    void writeHeader();
+    void rotateLog();
+
+    Q_DISABLE_COPY(KisUsageLogger)
+
+    struct Private;
+    const QScopedPointer<Private> d;
+
+    static const QString s_sectionHeader;
+    static const int s_maxLogs {10};
+
+};
+
+#endif // KISUSAGELOGGER_H
diff --git a/libs/ui/KisDocument.cpp b/libs/ui/KisDocument.cpp
index ab95fd2a29e..d24933e79bc 100644
--- a/libs/ui/KisDocument.cpp
+++ b/libs/ui/KisDocument.cpp
@@ -47,6 +47,7 @@
 #include <KoStoreDevice.h>
 #include <KoDialog.h>
 
+#include <KisUsageLogger.h>
 #include <klocalizedstring.h>
 #include <kis_debug.h>
 #include <kis_generator_layer.h>
@@ -77,6 +78,7 @@
 #include <QFutureWatcher>
 
 // Krita Image
+#include <kis_image_animation_interface.h>
 #include <kis_config.h>
 #include <flake/kis_shape_layer.h>
 #include <kis_group_layer.h>
@@ -532,7 +534,7 @@ bool KisDocument::exportDocumentImpl(const KritaUtils::ExportFileJob &job, KisPr
 
     KisConfig cfg(true);
     if (cfg.backupFile() && filePathInfo.exists()) {
-        KBackup::backupFile(job.filePath);
+        KBackup::numberedBackupFile(job.filePath);
     }
 
     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!job.mimeType.isEmpty(), false);
@@ -563,6 +565,16 @@ bool KisDocument::exportDocument(const QUrl &url, const QByteArray &mimeType, bo
         flags |= SaveShowWarnings;
     }
 
+    KisUsageLogger::log(QString("Exporting Document: %1 as %2. %3 * %4 pixels, %5 layers, %6 frames, %7 framerate. Export configuration: %8")
+                        .arg(url.toLocalFile())
+                        .arg(QString::fromLatin1(mimeType))
+                        .arg(d->image->width())
+                        .arg(d->image->height())
+                        .arg(d->image->nlayers())
+                        .arg(d->image->animationInterface()->totalLength())
+                        .arg(d->image->animationInterface()->framerate())
+                        .arg(exportConfiguration ? exportConfiguration->toXML() : "No configuration"));
+
     return exportDocumentImpl(KritaUtils::ExportFileJob(url.toLocalFile(),
                                                         mimeType,
                                                         flags),
@@ -570,11 +582,23 @@ bool KisDocument::exportDocument(const QUrl &url, const QByteArray &mimeType, bo
 
 }
 
-bool KisDocument::saveAs(const QUrl &url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
+bool KisDocument::saveAs(const QUrl &_url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
 {
     using namespace KritaUtils;
 
-    return exportDocumentImpl(ExportFileJob(url.toLocalFile(),
+    KisUsageLogger::log(QString("Saving Document %9 as %1 (mime: %2). %3 * %4 pixels, %5 layers.  %6 frames, %7 framerate. Export configuration: %8")
+                        .arg(_url.toLocalFile())
+                        .arg(QString::fromLatin1(mimeType))
+                        .arg(d->image->width())
+                        .arg(d->image->height())
+                        .arg(d->image->nlayers())
+                        .arg(d->image->animationInterface()->totalLength())
+                        .arg(d->image->animationInterface()->framerate())
+                        .arg(exportConfiguration ? exportConfiguration->toXML() : "No configuration")
+                        .arg(url().toLocalFile()));
+
+
+    return exportDocumentImpl(ExportFileJob(_url.toLocalFile(),
                                             mimeType,
                                             showWarnings ? SaveShowWarnings : SaveNone),
                               exportConfiguration);
@@ -813,6 +837,11 @@ void KisDocument::slotChildCompletedSavingInBackground(KisImportExportFilter::Co
     const KritaUtils::ExportFileJob job = d->backgroundSaveJob;
     d->backgroundSaveJob = KritaUtils::ExportFileJob();
 
+    KisUsageLogger::log(QString("Completed saving %1 (mime: %2). Result: %3")
+                        .arg(job.filePath)
+                        .arg(QString::fromLatin1(job.mimeType))
+                        .arg(status != KisImportExportFilter::OK ? exportErrorToUserMessage(status, errorMessage) : "OK"));
+
     emit sigCompleteBackgroundSaving(job, status, errorMessage);
 }
 
@@ -1703,6 +1732,14 @@ bool KisDocument::newImage(const QString& name,
     cfg.setDefaultColorDepth(image->colorSpace()->colorDepthId().id());
     cfg.defColorProfile(image->colorSpace()->profile()->name());
 
+    KisUsageLogger::log(i18n("Created image \"%1\", %2 * %3 pixels, %4 dpi. Color model: %6 %5 (%7). Layers: %8"
+                             , name
+                             , width, height
+                             , imageResolution * 72.0
+                             , image->colorSpace()->colorModelId().name(), image->colorSpace()->colorDepthId().name()
+                             , image->colorSpace()->profile()->name()
+                             , numberOfLayers));
+
     QApplication::restoreOverrideCursor();
 
     return true;
diff --git a/libs/ui/KisImportExportManager.cpp b/libs/ui/KisImportExportManager.cpp
index 7e8f616ad4b..e5ac96de102 100644
--- a/libs/ui/KisImportExportManager.cpp
+++ b/libs/ui/KisImportExportManager.cpp
@@ -40,6 +40,7 @@
 #include <ksqueezedtextlabel.h>
 #include <kpluginfactory.h>
 
+#include <KisUsageLogger.h>
 #include <KoFileDialog.h>
 #include <kis_icon_utils.h>
 #include <KoDialog.h>
@@ -277,7 +278,6 @@ KisImportExportManager::ConversionResult KisImportExportManager::convert(KisImpo
     // export configuration is supported for export only
     KIS_SAFE_ASSERT_RECOVER_NOOP(direction == Export || !bool(exportConfiguration));
 
-
     QString typeName = mimeType;
     if (typeName.isEmpty()) {
         typeName = KisMimeDatabase::mimeTypeForFile(location, direction == KisImportExportManager::Export ? false : true);
@@ -338,10 +338,18 @@ KisImportExportManager::ConversionResult KisImportExportManager::convert(KisImpo
                 direction == Import || direction == Export,
                 KisImportExportFilter::BadConversionGraph);
 
-
-
     ConversionResult result = KisImportExportFilter::OK;
     if (direction == Import) {
+
+        KisUsageLogger::log(QString("Importing %1 to %2. Location: %3. Real location: %4. Batchmode: %5")
+                            .arg(QString::fromLatin1(from))
+                            .arg(QString::fromLatin1(to))
+                            .arg(location)
+                            .arg(realLocation)
+                            .arg(batchMode()));
+
+
+
         // async importing is not yet supported!
         KIS_SAFE_ASSERT_RECOVER_NOOP(!isAsync);
 
@@ -372,6 +380,16 @@ KisImportExportManager::ConversionResult KisImportExportManager::convert(KisImpo
             return KisImportExportFilter::UserCancelled;
         }
 
+        KisUsageLogger::log(QString("Converting from %1 to %2. Location: %3. Real location: %4. Batchmode: %5. Configuration: %6")
+                            .arg(QString::fromLatin1(from))
+                            .arg(QString::fromLatin1(to))
+                            .arg(location)
+                            .arg(realLocation)
+                            .arg(batchMode())
+                            .arg(exportConfiguration ? exportConfiguration->toXML() : "none"));
+
+
+
         if (isAsync) {
             result = QtConcurrent::run(std::bind(&KisImportExportManager::doExport, this, location, filter, exportConfiguration, alsoAsKra));
 
diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc
index ffadadb009a..88b66293956 100644
--- a/libs/ui/dialogs/kis_dlg_preferences.cc
+++ b/libs/ui/dialogs/kis_dlg_preferences.cc
@@ -145,7 +145,7 @@ GeneralTab::GeneralTab(QWidget *_parent, const char *_name)
     const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
     QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
     m_chkHiDPI->setChecked(kritarc.value("EnableHiDPI", true).toBool());
-
+    chkUsageLogging->setChecked(kritarc.value("LogUsage", true).toBool());
     m_chkSingleApplication->setChecked(kritarc.value("EnableSingleApplication", true).toBool());
 
     //
@@ -245,6 +245,7 @@ void GeneralTab::setDefault()
     m_chkSingleApplication->setChecked(true);
 
     m_chkHiDPI->setChecked(true);
+    chkUsageLogging->setChecked(true);
     m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker(true));
     cmbFlowMode->setCurrentIndex(0);
     m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled(true));
@@ -1352,6 +1353,7 @@ bool KisDlgPreferences::editPreferences()
         QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
         kritarc.setValue("EnableHiDPI", dialog->m_general->m_chkHiDPI->isChecked());
         kritarc.setValue("EnableSingleApplication", dialog->m_general->m_chkSingleApplication->isChecked());
+        kritarc.setValue("LogUsage", dialog->m_general->chkUsageLogging->isChecked());
 
         cfg.setToolOptionsInDocker(dialog->m_general->toolOptionsInDocker());
 
diff --git a/libs/ui/forms/wdggeneralsettings.ui b/libs/ui/forms/wdggeneralsettings.ui
index 129061ff290..00abf30b182 100644
--- a/libs/ui/forms/wdggeneralsettings.ui
+++ b/libs/ui/forms/wdggeneralsettings.ui
@@ -517,7 +517,14 @@
         </widget>
        </item>
        <item row="0" column="1">
-        <widget class="QComboBox" name="cmbStartupSession"/>
+        <widget class="QComboBox" name="cmbStartupSession">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
        </item>
        <item row="1" column="1">
         <widget class="QCheckBox" name="chkSaveSessionOnQuit">
@@ -675,7 +682,7 @@
          </property>
         </widget>
        </item>
-       <item row="14" column="1">
+       <item row="15" column="1">
         <widget class="QCheckBox" name="m_chkNativeFileDialog">
          <property name="toolTip">
           <string>Warning: if you enable this setting and the file dialogs do weird stuff, do not report a bug.</string>
@@ -685,14 +692,14 @@
          </property>
         </widget>
        </item>
-       <item row="16" column="0">
+       <item row="17" column="0">
         <widget class="QLabel" name="label_9">
          <property name="text">
           <string>Maximum brush size:</string>
          </property>
         </widget>
        </item>
-       <item row="16" column="1">
+       <item row="17" column="1">
         <layout class="QHBoxLayout" name="horizontalLayout_2">
          <item>
           <widget class="QSpinBox" name="intMaxBrushSize">
@@ -728,7 +735,7 @@
          </item>
         </layout>
        </item>
-       <item row="17" column="1">
+       <item row="18" column="1">
         <spacer name="verticalSpacer_4">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
@@ -773,6 +780,16 @@
          </property>
         </widget>
        </item>
+       <item row="14" column="1">
+        <widget class="QCheckBox" name="chkUsageLogging">
+         <property name="text">
+          <string>Enable Logging for bug reports</string>
+         </property>
+         <property name="checked">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
       </layout>
      </widget>
     </widget>
diff --git a/libs/ui/input/wintab/kis_tablet_support_win.cpp b/libs/ui/input/wintab/kis_tablet_support_win.cpp
index f977bdfa5e2..83bd63981c3 100644
--- a/libs/ui/input/wintab/kis_tablet_support_win.cpp
+++ b/libs/ui/input/wintab/kis_tablet_support_win.cpp
@@ -26,9 +26,11 @@
 #include "kis_tablet_support_win.h"
 
 #include <kis_debug.h>
+#include <KisUsageLogger.h>
 #include <QApplication>
 #include <QGuiApplication>
 #include <QDesktopWidget>
+#include <QBuffer>
 
 // #include <qpa/qwindowsysteminterface.h>
 // #include <qpa/qplatformscreen.h>
@@ -110,23 +112,32 @@ HWND createDummyWindow(const QString &className, const wchar_t *windowName, WNDP
 
 void printContext(const LOGCONTEXT &lc)
 {
-    dbgTablet << "# Getting current context data:";
-    dbgTablet << ppVar(lc.lcName);
-    dbgTablet << ppVar(lc.lcDevice);
-    dbgTablet << ppVar(lc.lcInOrgX);
-    dbgTablet << ppVar(lc.lcInOrgY);
-    dbgTablet << ppVar(lc.lcInExtX);
-    dbgTablet << ppVar(lc.lcInExtY);
-    dbgTablet << ppVar(lc.lcOutOrgX);
-    dbgTablet << ppVar(lc.lcOutOrgY);
-    dbgTablet << ppVar(lc.lcOutExtX);
-    dbgTablet << ppVar(lc.lcOutExtY);
-    dbgTablet << ppVar(lc.lcSysOrgX);
-    dbgTablet << ppVar(lc.lcSysOrgY);
-    dbgTablet << ppVar(lc.lcSysExtX);
-    dbgTablet << ppVar(lc.lcSysExtY);
-
-    dbgTablet << "Qt Desktop Geometry" << QApplication::desktop()->geometry();
+    QByteArray ba;
+    QBuffer buf(&ba);
+    buf.open(QBuffer::WriteOnly);
+
+    buf << "\nTablet context data:\n ";
+    buf << ppVar(lc.lcName) << "\n ";
+    buf << ppVar(lc.lcDevice) << "\n ";
+    buf << ppVar(lc.lcInOrgX) << "\n ";
+    buf << ppVar(lc.lcInOrgY) << "\n ";
+    buf << ppVar(lc.lcInExtX) << "\n ";
+    buf << ppVar(lc.lcInExtY) << "\n ";
+    buf << ppVar(lc.lcOutOrgX) << "\n ";
+    buf << ppVar(lc.lcOutOrgY) << "\n ";
+    buf << ppVar(lc.lcOutExtX) << "\n ";
+    buf << ppVar(lc.lcOutExtY) << "\n ";
+    buf << ppVar(lc.lcSysOrgX) << "\n ";
+    buf << ppVar(lc.lcSysOrgY) << "\n ";
+    buf << ppVar(lc.lcSysExtX) << "\n ";
+    buf << ppVar(lc.lcSysExtY) << "\n ";
+
+    buf << "Qt Desktop Geometry" << QApplication::desktop()->geometry()  << "\n ";
+
+    buf.close();
+
+    dbgTablet << buf;
+    KisUsageLogger::write(QString::fromUtf8(ba));
 }
 
 
diff --git a/libs/ui/kis_statusbar.cc b/libs/ui/kis_statusbar.cc
index c30348ba0f8..991beb82457 100644
--- a/libs/ui/kis_statusbar.cc
+++ b/libs/ui/kis_statusbar.cc
@@ -36,6 +36,8 @@
 #include <KoToolManager.h>
 #include <KoViewConverter.h>
 
+#include <KisUsageLogger.h>
+
 #include <kis_icon_utils.h>
 
 #include <kis_types.h>
@@ -46,6 +48,7 @@
 #include "kis_memory_statistics_server.h"
 
 #include "KisView.h"
+#include "KisDocument.h"
 #include "KisViewManager.h"
 #include "canvas/kis_canvas2.h"
 #include "kis_progress_widget.h"
@@ -297,12 +300,19 @@ void KisStatusBar::updateMemoryStatus()
     if (stats.imageSize > warnLevel ||
             stats.realMemorySize > warnLevel) {
 
+        if (!m_memoryWarningLogged) {
+            m_memoryWarningLogged = true;
+            KisUsageLogger::log(QString("WARNING: %1 is running out of memory:%2\n").arg(m_imageView->document()->url().toLocalFile()).arg(longStats));
+        }
+
         icon = KisIconUtils::loadIcon("dialog-warning");
         QString suffix =
                 i18nc("tooltip on statusbar memory reporting button",
                       "\n\nWARNING:\tOut of memory! Swapping has been started.\n"
                       "\t\tPlease configure more RAM for Krita in Settings dialog");
         longStats += suffix;
+
+
     }
 
     m_shortMemoryTag = shortStats;
diff --git a/libs/ui/kis_statusbar.h b/libs/ui/kis_statusbar.h
index b890f64906d..14467e9180f 100644
--- a/libs/ui/kis_statusbar.h
+++ b/libs/ui/kis_statusbar.h
@@ -133,6 +133,8 @@ private:
     QIcon m_memoryStatusIcon;
 
     QVector<StatusBarItem> m_statusBarItems;
+
+    bool m_memoryWarningLogged {false};
 };
 
 #endif
diff --git a/libs/ui/opengl/kis_opengl.cpp b/libs/ui/opengl/kis_opengl.cpp
index 5728a165ae9..c57df03100e 100644
--- a/libs/ui/opengl/kis_opengl.cpp
+++ b/libs/ui/opengl/kis_opengl.cpp
@@ -38,6 +38,8 @@
 #include <kis_debug.h>
 #include <kis_config.h>
 
+#include <KisUsageLogger.h>
+
 #include <boost/optional.hpp>
 
 #ifndef GL_RENDERER
@@ -107,15 +109,18 @@ void KisOpenGL::initialize()
     QOpenGLContext context;
     if (!context.create()) {
         qDebug() << "OpenGL context cannot be created";
+        KisUsageLogger::log("OpenGL context cannot be created");
         return;
     }
     if (!context.isValid()) {
         qDebug() << "OpenGL context is not valid";
+        KisUsageLogger::log("OpenGL context is not valid");
         return;
     }
 
     if (!context.makeCurrent(&surface)) {
         qDebug() << "OpenGL context cannot be made current";
+        KisUsageLogger::log("OpenGL context cannot be made current");
         return;
     }
 
@@ -123,7 +128,7 @@ void KisOpenGL::initialize()
     openGLCheckResult = OpenGLCheckResult(context);
     debugText.clear();
     QDebug debugOut(&debugText);
-    debugOut << "OpenGL Info";
+    debugOut << "OpenGL Info\n";
     debugOut << "\n  Vendor: " << reinterpret_cast<const char *>(funcs->glGetString(GL_VENDOR));
     debugOut << "\n  Renderer: " << openGLCheckResult->rendererString();
     debugOut << "\n  Version: " << openGLCheckResult->driverVersionString();
@@ -138,7 +143,7 @@ void KisOpenGL::initialize()
     appendPlatformOpenGLDebugText(debugOut);
 
     dbgOpenGL.noquote() << debugText;
-
+    KisUsageLogger::write(debugText);
 }
 
 void KisOpenGL::initializeContext(QOpenGLContext *ctx)
diff --git a/plugins/extensions/buginfo/dlg_buginfo.cpp b/plugins/extensions/buginfo/dlg_buginfo.cpp
index b19dc932a1e..362c9e12538 100644
--- a/plugins/extensions/buginfo/dlg_buginfo.cpp
+++ b/plugins/extensions/buginfo/dlg_buginfo.cpp
@@ -27,6 +27,10 @@
 #include <QDesktopWidget>
 #include <QClipboard>
 #include <QThread>
+#include <QFile>
+#include <QFileInfo>
+#include <QSettings>
+#include <QStandardPaths>
 
 #include "kis_document_aware_spin_box_unit_manager.h"
 
@@ -46,39 +50,50 @@ DlgBugInfo::DlgBugInfo(QWidget *parent)
 
     QString info;
 
-    // NOTE: This is intentionally not translated!
-
-    // Krita version info
-    info.append("Krita");
-    info.append("\n  Version: ").append(KritaVersionWrapper::versionString(true));
-    info.append("\n\n");
-
-    info.append("Qt");
-    info.append("\n  Version (compiled): ").append(QT_VERSION_STR);
-    info.append("\n  Version (loaded): ").append(qVersion());
-    info.append("\n\n");
-
-    // OS information
-    info.append("OS Information");
-    info.append("\n  Build ABI: ").append(QSysInfo::buildAbi());
-    info.append("\n  Build CPU: ").append(QSysInfo::buildCpuArchitecture());
-    info.append("\n  CPU: ").append(QSysInfo::currentCpuArchitecture());
-    info.append("\n  Kernel Type: ").append(QSysInfo::kernelType());
-    info.append("\n  Kernel Version: ").append(QSysInfo::kernelVersion());
-    info.append("\n  Pretty Productname: ").append(QSysInfo::prettyProductName());
-    info.append("\n  Product Type: ").append(QSysInfo::productType());
-    info.append("\n  Product Version: ").append(QSysInfo::productVersion());
-    info.append("\n\n");
-
-    // OpenGL information
-    info.append("\n").append(KisOpenGL::getDebugText());
-    info.append("\n\n");
-    // Hardware information
-    info.append("Hardware Information");
-    info.append(QString("\n Memory: %1").arg(KisImageConfig(true).totalRAM() / 1024)).append(" Gb");
-    info.append(QString("\n Cores: %1").arg(QThread::idealThreadCount()));
-    info.append("\n Swap: ").append(KisImageConfig(true).swapDir());
-
+    const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
+    QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
+
+    if (!kritarc.value("LogUsage", true).toBool() || !QFileInfo(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/krita.log").exists()) {
+
+        // NOTE: This is intentionally not translated!
+
+        // Krita version info
+        info.append("Krita");
+        info.append("\n  Version: ").append(KritaVersionWrapper::versionString(true));
+        info.append("\n\n");
+
+        info.append("Qt");
+        info.append("\n  Version (compiled): ").append(QT_VERSION_STR);
+        info.append("\n  Version (loaded): ").append(qVersion());
+        info.append("\n\n");
+
+        // OS information
+        info.append("OS Information");
+        info.append("\n  Build ABI: ").append(QSysInfo::buildAbi());
+        info.append("\n  Build CPU: ").append(QSysInfo::buildCpuArchitecture());
+        info.append("\n  CPU: ").append(QSysInfo::currentCpuArchitecture());
+        info.append("\n  Kernel Type: ").append(QSysInfo::kernelType());
+        info.append("\n  Kernel Version: ").append(QSysInfo::kernelVersion());
+        info.append("\n  Pretty Productname: ").append(QSysInfo::prettyProductName());
+        info.append("\n  Product Type: ").append(QSysInfo::productType());
+        info.append("\n  Product Version: ").append(QSysInfo::productVersion());
+        info.append("\n\n");
+
+        // OpenGL information
+        info.append("\n").append(KisOpenGL::getDebugText());
+        info.append("\n\n");
+        // Hardware information
+        info.append("Hardware Information");
+        info.append(QString("\n Memory: %1").arg(KisImageConfig(true).totalRAM() / 1024)).append(" Gb");
+        info.append(QString("\n Cores: %1").arg(QThread::idealThreadCount()));
+        info.append("\n Swap: ").append(KisImageConfig(true).swapDir());
+    }
+    else {
+        QFile f(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/krita.log");
+        f.open(QFile::ReadOnly);
+        info = QString::fromUtf8(f.readAll());
+        f.close();
+    }
     // calculate a default height for the widget
     int wheight = m_page->sizeHint().height();
     m_page->txtBugInfo->setText(info);
diff --git a/plugins/tools/basictools/kis_tool_brush.cc b/plugins/tools/basictools/kis_tool_brush.cc
index e1117114e37..a8b313fcab7 100644
--- a/plugins/tools/basictools/kis_tool_brush.cc
+++ b/plugins/tools/basictools/kis_tool_brush.cc
@@ -39,6 +39,8 @@
 #include "kis_slider_spin_box.h"
 #include "kundo2magicstring.h"
 
+#include <KisUsageLogger.h>
+
 #define MAXIMUM_SMOOTHNESS_DISTANCE 1000.0 // 0..1000.0 == weight in gui
 #define MAXIMUM_MAGNETISM 1000
 
@@ -126,8 +128,11 @@ void KisToolBrush::slotSetSmoothingType(int index)
         m_cmbSmoothingType->setCurrentIndex(index);
     }
 
+    if (smoothingOptions()->smoothingType() == index) return;
+
     switch (index) {
     case 0:
+        KisUsageLogger::log("Disabled smoothing.");
         smoothingOptions()->setSmoothingType(KisSmoothingOptions::NO_SMOOTHING);
         showControl(m_sliderSmoothnessDistance, false);
         showControl(m_sliderTailAggressiveness, false);
@@ -138,6 +143,7 @@ void KisToolBrush::slotSetSmoothingType(int index)
         showControl(m_chkStabilizeSensors, false);
         break;
     case 1:
+        KisUsageLogger::log("Enabled simple smoothing.");
         smoothingOptions()->setSmoothingType(KisSmoothingOptions::SIMPLE_SMOOTHING);
         showControl(m_sliderSmoothnessDistance, false);
         showControl(m_sliderTailAggressiveness, false);
@@ -148,6 +154,7 @@ void KisToolBrush::slotSetSmoothingType(int index)
         showControl(m_chkStabilizeSensors, false);
         break;
     case 2:
+        KisUsageLogger::log("Enabled weighted smoothing.");
         smoothingOptions()->setSmoothingType(KisSmoothingOptions::WEIGHTED_SMOOTHING);
         showControl(m_sliderSmoothnessDistance, true);
         showControl(m_sliderTailAggressiveness, true);
@@ -159,6 +166,7 @@ void KisToolBrush::slotSetSmoothingType(int index)
         break;
     case 3:
     default:
+        KisUsageLogger::log("Enabled stabilizer.");
         smoothingOptions()->setSmoothingType(KisSmoothingOptions::STABILIZER);
         showControl(m_sliderSmoothnessDistance, true);
         showControl(m_sliderTailAggressiveness, false);


More information about the kimageshop mailing list