瀏覽代碼

Initial commit on Logging and Debugging system rework

Felix Turo 3 年之前
父節點
當前提交
b9784e253d

+ 1 - 0
CMakeLists.txt

@@ -36,6 +36,7 @@ set(PROJECT_SOURCES
     src/database/adatabase.cpp
     src/database/adatabasesetup.cpp
     src/functions/acalc.cpp
+    src/functions/alog.cpp
     src/functions/areadcsv.cpp
     src/functions/astat.cpp
     src/gui/dialogues/firstrundialog.cpp

+ 1 - 1
mainwindow.cpp

@@ -17,7 +17,7 @@
  */
 #include "mainwindow.h"
 #include "ui_mainwindow.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/database/adatabase.h"
 #include "src/classes/astyle.h"
 

+ 1 - 1
src/classes/adownload.cpp

@@ -16,7 +16,7 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "adownload.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 
 

+ 1 - 1
src/classes/astandardpaths.h

@@ -18,7 +18,7 @@
 #ifndef ASTANDARDPATHS_H
 #define ASTANDARDPATHS_H
 
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include <QStandardPaths>
 #include <QString>
 #include <QMap>

+ 1 - 1
src/classes/astyle.cpp

@@ -25,7 +25,7 @@
 #include <QStyleFactory>
 #include <QApplication>
 #include <QFont>
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/classes/asettings.h"
 #include "src/functions/alog.h"
 

+ 1 - 1
src/database/adatabase.cpp

@@ -16,7 +16,7 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "adatabase.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/classes/astandardpaths.h"
 #include "src/oplconstants.h"
 #include "src/functions/alog.h"

+ 3 - 3
src/database/adatabasesetup.cpp

@@ -17,7 +17,7 @@
  */
 #include "adatabasesetup.h"
 #include "src/database/adatabase.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/functions/areadcsv.h"
 #include "src/classes/astandardpaths.h"
 #include "src/classes/adownload.h"
@@ -432,9 +432,9 @@ bool ADataBaseSetup::createSchemata(const QStringList &statements)
     }
 
     if (!errors.isEmpty()) {
-        DEB_SRC << "The following errors have ocurred: ";
+        DEB << "The following errors have ocurred: ";
         for (const auto& error : qAsConst(errors)) {
-            DEB_RAW << error;
+            DEB << error;
         }
         return false;
     }

+ 1 - 1
src/database/adatabasetypes.h

@@ -19,7 +19,7 @@
 #define DECLARATIONS_H
 
 #include <QtCore>
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 /// \todo Short descriptions
 using RowId_T = int;

+ 1 - 1
src/functions/acalc.cpp

@@ -16,7 +16,7 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "acalc.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/database/adatabase.h"
 #include "src/classes/asettings.h"
 #include "src/oplconstants.h"

+ 1 - 1
src/functions/acalc.h

@@ -24,7 +24,7 @@
 #include <cmath>
 #include <QDateTime>
 #include <QDebug>
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 /*!
  * \brief The ACalc namespace provides various functions for calculations that are performed
  * outside of the database. This includes tasks like converting different units and formats,

+ 114 - 0
src/functions/alog.cpp

@@ -0,0 +1,114 @@
+#include "alog.h"
+
+namespace ALog {
+
+/*!
+ * \brief setLogFileName sets a log file name ("Log_<Date>_<Time>.txt")
+ */
+void setLogFileName()
+{
+    logFileName = QString(logFolderName + QLatin1String("/Log_%1_%2.txt")
+                          ).arg(QDate::currentDate().toString(QStringLiteral("yyyy_MM_dd")),
+                                QTime::currentTime().toString(QStringLiteral("hh_mm_ss")));
+}
+
+/*!
+ * \brief Cleans up old logs and initializes logging by preparing and installing a QMessageHandler
+ *
+ */
+void deleteOldLogs()
+{
+    if(!QDir(logFolderName).exists()) {
+        QDir().mkdir(logFolderName);
+    }
+
+    QDir dir;
+    dir.setSorting(QDir::Time | QDir::Reversed);
+    dir.setPath(logFolderName);
+
+    QFileInfoList logs_list = dir.entryInfoList();
+    if (logs_list.size() <= numberOfLogs) {
+        return;
+    } else {
+        for (int i = 0; i < (logs_list.size() - numberOfLogs); i++) {
+            const QString path = logs_list.at(i).absoluteFilePath();
+            QFile file(path);
+            file.remove();
+        }
+    }
+}
+
+/*!
+ * \brief initialise logging, clean up logfiles and install a QMessageHandler
+ */
+bool init()
+{
+    // Create folder for logfiles if it doesn't exist, move to AStandardPaths later
+    if(!QDir(logFolderName).exists()) {
+        QDir().mkdir(logFolderName);
+    }
+
+    deleteOldLogs();
+    setLogFileName();
+
+    QFile log_file((logFileName));
+    if(log_file.open(QIODevice::WriteOnly | QIODevice::Append)) {
+        qInstallMessageHandler(ALog::aMessageHandler);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/*!
+ * \brief aMessageHandler Intercepts Messages and prints to console and log file
+ *
+ * \abstract The message handler is responsible for intercepting the output from
+ * qDebug(), qInfo(), qWarning() and qCritical(), formatting them and printing them
+ * to the standard console out and to a logfile using QTextStream. Debug messages are
+ * not written to the log file.
+ *
+ */
+void aMessageHandler(QtMsgType type, const QMessageLogContext &context,
+                      const QString& msg)
+{
+    const char *function = context.function ? context.function : "";
+    //check file size and if needed create new log!
+    {
+        QFile outFileCheck(logFileName);
+        int size = outFileCheck.size();
+
+        if (size > sizeOfLogs) {
+            deleteOldLogs();
+            setLogFileName();
+        }
+    }
+    // open the log file and prepare a textstream to write to it
+    QFile log_file(logFileName);
+    log_file.open(QIODevice::WriteOnly | QIODevice::Append);
+    QTextStream log_stream(&log_file);
+
+    switch (type) {
+        case QtDebugMsg:
+            QTextStream(stdout) << "\t\033\[31m" << function << DEB_HEADER << msg << "\033[m" << endl;
+            break;
+        case QtInfoMsg:
+            log_stream << QTime::currentTime().toString(Qt::ISODate) << INFO_HEADER << msg << function << endl;
+            QTextStream(stdout) << INFO_HEADER_CONSOLE << msg  << endl;
+            break;
+        case QtWarningMsg:
+            log_stream << QTime::currentTime().toString(Qt::ISODate) << WARN_HEADER << msg << function << endl;
+            QTextStream(stdout) << WARN_HEADER_CONSOLE << msg << endl;
+            break;
+        case QtCriticalMsg:
+            log_stream << QTime::currentTime().toString(Qt::ISODate) << CRIT_HEADER << msg << function << endl;
+            QTextStream(stdout) << CRIT_HEADER_CONSOLE << msg << endl;
+            break;
+    default:
+            log_stream << QTime::currentTime().toString(Qt::ISODate) << INFO_HEADER << msg << function << endl;
+            QTextStream(stdout) << INFO_HEADER_CONSOLE << msg << endl;
+            break;
+        }
+}
+
+} // namespace ALog

+ 87 - 24
src/functions/alog.h

@@ -1,32 +1,95 @@
-/*
- *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2021 Felix Turowsky
- *
- *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 3 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, see <https://www.gnu.org/licenses/>.
- */
 #ifndef ALOG_H
 #define ALOG_H
 
+#include <QTime>
+#include <QFile>
+#include <QFileInfo>
+#include <QDebug>
+#include <QDir>
+#include <QFileInfoList>
+#include <iostream>
 #include <QDebug>
 
-/* Use QTextStream to print status messages. These messages
- * are oriented towards end-users and will persist even when
- * compiling a release without enabling qDebug. As such, LOG
- * should be used to document "important" enough steps that
- * the user would care about or that are "milestones" that
- * the program runs through.
+#if defined(__GNUC__) || defined(__clang__)
+    #define FUNC_IDENT __PRETTY_FUNCTION__
+#elif defined(_MSC_VER)
+    #define FUNC_IDENT __FUNCSIG__
+#else
+    #define FUNC_IDENT __func__
+#endif
+
+#define DEB qDebug() << FUNC_IDENT << "\n\t"    // Use for debugging
+#define LOG qInfo()                             // Use for logging milestones (silently, will be written to log file and console out only)
+#define INFO qInfo()                            // Use for messages of interest to the user (will be displayed in GUI)
+#define WARN qWarning()                         // Use for warnings (will be displayed in GUI)
+#define CRIT qCritical()                        // Use for critical warnings (will be displayed in GUI)
+#define TODO qCritical() << "!\n\tTo Do:\t"
+
+/*!
+ * \brief The ALog namespace encapsulates constants and functions used to provide logging to files
+ * and logging to console (stdout)
+ *
+ * \abstract
+ *
+ * The console output is color coded - green, amber, magenta for info, warn and crit messages, whereas
+ * the log files are just plain text.
+ *
+ * There is a maximum of <numberOfLogs> log files with a maximum size of <sizeOfLogs>,
+ * at the moment, up to 10 logs of up to 100kB in size are kept, older logs are
+ * automatically deleted.
+ *
+ * Debug output is not written to the logfile.
+ *
+ * In order to start logging, the ALog::init() function has to be called
+ *
+ * Credits to [Andy Dunkel](https://andydunkel.net/) for his excellent blog post on Qt Log File Rotation!
+ */
+namespace ALog
+{
+    static QString logFolderName = "logs"; // To Do: AStandardpaths
+    static QString logFileName;
+    const static int numberOfLogs = 10; // max number of log files to keep
+    const static int sizeOfLogs = 1024 * 100; // max log size in bytes, = 100kB
+
+    const static auto DEB_HEADER  = QLatin1String("\n[OPL - Deb ]: ");
+    const static auto INFO_HEADER = QLatin1String(" [OPL - INFO]: ");
+    const static auto WARN_HEADER = QLatin1String(" [OPL - WARN]: ");
+    const static auto CRIT_HEADER = QLatin1String(" [OPL - CRIT]: ");
+    const static auto INFO_HEADER_CONSOLE = QLatin1String("\033[32m[OPL - INFO]: \033[m");
+    const static auto WARN_HEADER_CONSOLE = QLatin1String("\033[33m[OPL - WARN]: \033[m");
+    const static auto CRIT_HEADER_CONSOLE = QLatin1String("\033[35m[OPL - CRIT]: \033[m");
+
+    bool init();
+    void setLogFileName();
+    void deleteOldLogs();
+    void aMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString& msg);
+} // namespace ALog
+
+/*!
+ * Representation macro for custom classes.
+ *
+ * Usage
+ * -----
+ * class Myclass {
+ *  ...
+ * 	REPR(MyClass,
+ *       "member1=" + object.member1 + ", "
+ *       "something2" + object.calculate()
+ *      )
+ * };
+ *
+ * MyClass mc;
+ * DEB << mc;
+ *
+ * output:
+ * MyClass(member1=3000, something2="A320")
  */
-#define LOG QTextStream(stdout) << "openPilotLog - "
+#define REPR(cls, str) \
+friend \
+QDebug operator<<(QDebug qdb, const cls& object) \
+{ \
+    qdb << QString(#cls) + '(' + str + ')'; \
+    return qdb; \
+}
 
 #endif // ALOG_H

+ 1 - 1
src/functions/astat.cpp

@@ -17,7 +17,7 @@
  */
 #include "astat.h"
 #include "src/database/adatabase.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 /*!
  * \brief AStat::totalTime Looks up Total Blocktime in the flights database

+ 1 - 1
src/functions/atime.h

@@ -21,7 +21,7 @@
 #include <QtCore>
 #include <QTime>
 #include "src/oplconstants.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 namespace ATime {
 

+ 1 - 1
src/gui/dialogues/firstrundialog.cpp

@@ -17,7 +17,7 @@
  */
 #include "firstrundialog.h"
 #include "ui_firstrundialog.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/database/adatabase.h"
 #include "src/database/adatabasesetup.h"
 #include "src/classes/apilotentry.h"

+ 1 - 1
src/gui/dialogues/newflightdialog.cpp

@@ -24,7 +24,7 @@
 #include "src/database/adatabase.h"
 #include "src/oplconstants.h"
 
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ///                                         constants                                           ///

+ 1 - 1
src/gui/dialogues/newpilotdialog.cpp

@@ -20,7 +20,7 @@
 
 #include "src/database/adatabase.h"
 #include "src/classes/aentry.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 /* Examples for names around the world:
  * José Eduardo Santos Tavares Melo Silva

+ 1 - 1
src/gui/dialogues/newtaildialog.cpp

@@ -17,7 +17,7 @@
  */
 #include "newtaildialog.h"
 #include "ui_newtail.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/oplconstants.h"
 
 static const auto REG_VALID = QPair<QString, QRegularExpression> {

+ 1 - 1
src/gui/widgets/aircraftwidget.cpp

@@ -22,7 +22,7 @@
 #include "src/database/adatabase.h"
 #include "src/classes/atailentry.h"
 #include "src/classes/aflightentry.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 AircraftWidget::AircraftWidget(QWidget *parent) :
     QWidget(parent),

+ 2 - 2
src/gui/widgets/backupwidget.cpp

@@ -1,7 +1,7 @@
 #include "backupwidget.h"
 #include "ui_backupwidget.h"
 #include "src/classes/astandardpaths.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/database/adatabase.h"
 #include "src/functions/adatetime.h"
 
@@ -132,7 +132,7 @@ void BackupWidget::on_restoreLocalPushButton_clicked()
 
 void BackupWidget::on_deleteSelectedPushButton_clicked()
 {
-    NOT_IMPLEMENTED("Test external deletion");
+    TODO << "Test external deletion";
     if(selectedFileInfo == nullptr) {
         INFO << "No backup was selected";
         return;

+ 1 - 1
src/gui/widgets/debugwidget.h

@@ -35,7 +35,7 @@
 
 #include "src/testing/abenchmark.h"
 #include "src/testing/atimer.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 namespace Ui {
 class DebugWidget;

+ 1 - 1
src/gui/widgets/homewidget.cpp

@@ -17,7 +17,7 @@
  */
 #include "homewidget.h"
 #include "ui_homewidget.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/database/adatabase.h"
 #include "src/functions/atime.h"
 #include "src/classes/asettings.h"

+ 1 - 1
src/gui/widgets/logbookwidget.cpp

@@ -22,7 +22,7 @@
 #include "src/database/adatabase.h"
 #include "src/classes/asettings.h"
 #include "src/gui/dialogues/newflightdialog.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/functions/alog.h"
 
 const QMap<int, QString> FILTER_MAP = {

+ 1 - 1
src/gui/widgets/pilotswidget.cpp

@@ -17,7 +17,7 @@
  */
 #include "pilotswidget.h"
 #include "ui_pilotswidget.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/database/adatabase.h"
 #include "src/classes/apilotentry.h"
 

+ 1 - 1
src/gui/widgets/settingswidget.cpp

@@ -17,7 +17,7 @@
  */
 #include "settingswidget.h"
 #include "ui_settingswidget.h"
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 #include "src/classes/astyle.h"
 #include "src/classes/asettings.h"
 #include "src/database/adatabase.h"

+ 1 - 1
src/testing/abenchmark.h

@@ -19,7 +19,7 @@
 #define ABENCHMARK_H
 
 #include <QObject>
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 /*!
  * \brief The ABenchmark class provides quick access to benchmarking two functions for

+ 2 - 1
src/testing/adebug.h

@@ -1,6 +1,7 @@
 #ifndef ADEBUG_H
 #define ADEBUG_H
 
+/*
 #include <QDebug>
 
 #if defined(__GNUC__) || defined(__clang__)
@@ -31,7 +32,7 @@
 #define CRIT qCritical() << "critical:"
 //#define NOT_IMPLEMENTED qCritical() << FUNC_IDENT << "\n\t" << "~~ NOT IMPLEMENTED ~~";
 #define NOT_IMPLEMENTED(msg) qCritical() << FUNC_IDENT << "\n\tNOT IMPLEMENTED:" << msg
-
+*/
 /*!
  * Representation macro for custom classes.
  *

+ 1 - 1
src/testing/atimer.h

@@ -21,7 +21,7 @@
 #include <QObject>
 #include <chrono>
 #include <QDebug>
-#include "src/testing/adebug.h"
+#include "src/functions/alog.h"
 
 /*!
  * \brief The ATimer class provides an easy to use performance timer.