diff --git a/ground/gcs/src/app/main.cpp b/ground/gcs/src/app/main.cpp index fa1e946bb..9644bea5c 100644 --- a/ground/gcs/src/app/main.cpp +++ b/ground/gcs/src/app/main.cpp @@ -84,6 +84,7 @@ #include "qtsingleapplication.h" #include "utils/xmlconfig.h" #include "utils/pathutils.h" +#include "utils/filelogger.h" #include "gcssplashscreen.h" #include @@ -108,7 +109,6 @@ #include #include -namespace { typedef QList PluginSpecSet; typedef QMap AppOptions; typedef QMap AppOptionValues; @@ -286,48 +286,21 @@ void systemInit() QSurfaceFormat::setDefaultFormat(format); } -static QTextStream *logStream; +static FileLogger *logger; void mainMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { - Q_UNUSED(context); - - QTextStream &out = *logStream; - - // logStream << QTime::currentTime().toString("hh:mm:ss.zzz "); - - switch (type) { - case QtDebugMsg: - out << "DBG: "; - break; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) - case QtInfoMsg: - out << "INF: "; - break; -#endif - case QtWarningMsg: - out << "WRN: "; - break; - case QtCriticalMsg: - out << "CRT: "; - break; - case QtFatalMsg: - out << "FTL: "; - break; - } - - out << msg << '\n'; - out.flush(); + logger->log(type, context, msg); } +Q_DECLARE_METATYPE(QtMsgType) + void logInit(QString fileName) { - QFile *file = new QFile(fileName); - - if (file->open(QIODevice::WriteOnly | QIODevice::Text)) { - logStream = new QTextStream(file); - qInstallMessageHandler(mainMessageOutput); - } else { + qRegisterMetaType(); + qInstallMessageHandler(mainMessageOutput); + logger = new FileLogger(); + if (!logger->start(fileName)) { displayError(msgLogfileOpenFailed(fileName)); } } @@ -456,7 +429,6 @@ void loadTranslators(QString language, QTranslator &translator, QTranslator &qtT translator.load(QString()); } } -} // namespace anonymous int main(int argc, char * *argv) { @@ -494,6 +466,8 @@ int main(int argc, char * *argv) if (appOptionValues.contains(LOG_FILE_OPTION)) { QString logFileName = appOptionValues.value(LOG_FILE_OPTION); logInit(logFileName); + // relog command line arguments for the benefit of the file logger... + qDebug() << "Command line" << app.arguments(); } // load user settings @@ -644,5 +618,9 @@ int main(int argc, char * *argv) qDebug() << "main - GCS ran for" << timer.elapsed() << "ms"; + if (logger) { + delete logger; + } + return ret; } diff --git a/ground/gcs/src/libs/utils/filelogger.h b/ground/gcs/src/libs/utils/filelogger.h new file mode 100644 index 000000000..8c5b8d3b1 --- /dev/null +++ b/ground/gcs/src/libs/utils/filelogger.h @@ -0,0 +1,141 @@ +/** + ****************************************************************************** + * + * @file filelogger.h + * @author The LibrePilot Project, http://www.openpilot.org Copyright (C) 2016. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup + * @{ + * + *****************************************************************************/ +/* + * 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, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include "utils_global.h" + +#include +#include +#include +#include +#include + +class QTCREATOR_UTILS_EXPORT FileLogger : public QObject { + Q_OBJECT + +private: + QTextStream * logStream; + QThread *loggerThread; + bool started; + +public: + FileLogger() : QObject(), logStream(NULL), loggerThread(NULL), started(false) + {} + + virtual ~FileLogger() + { + stop(); + if (logStream) { + delete logStream; + } + } + +public: + bool start(const QString &fileName) + { + if (started) { + return false; + } + + QFile *file = new QFile(fileName); + if (!file->open(QIODevice::WriteOnly | QIODevice::Text)) { + return false; + } + + logStream = new QTextStream(file); + + loggerThread = new QThread(this); + moveToThread(loggerThread); + loggerThread->start(); + + started = true; + + return true; + } + + bool stop() + { + if (!started) { + return false; + } + // stop accepting messages + started = false; + + // make sure all messages are flushed by sending a blocking message + QtMsgType type = QtDebugMsg; + const QString msg = "stopping file logger"; + QMetaObject::invokeMethod(this, "doLog", Qt::BlockingQueuedConnection, + Q_ARG(QtMsgType, type), Q_ARG(const QString &, msg)); + + return true; + } + + void log(QtMsgType type, const QMessageLogContext &context, const QString &msg) + { + Q_UNUSED(context); + + if (!started) { + return; + } + + QMetaObject::invokeMethod(this, "doLog", Qt::QueuedConnection, + Q_ARG(QtMsgType, type), Q_ARG(const QString &, msg)); + } + +private slots: + void doLog(QtMsgType type, const QString &msg) + { + QTextStream &out = *logStream; + + // logStream << QTime::currentTime().toString("hh:mm:ss.zzz "); + + switch (type) { + case QtDebugMsg: + out << "DBG: "; + break; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) + case QtInfoMsg: + out << "INF: "; + break; +#endif + case QtWarningMsg: + out << "WRN: "; + break; + case QtCriticalMsg: + out << "CRT: "; + break; + case QtFatalMsg: + out << "FTL: "; + break; + } + + out << msg << '\n'; + out.flush(); + } +}; diff --git a/ground/gcs/src/libs/utils/utils.pro b/ground/gcs/src/libs/utils/utils.pro index 16701460f..4e291df1b 100644 --- a/ground/gcs/src/libs/utils/utils.pro +++ b/ground/gcs/src/libs/utils/utils.pro @@ -121,7 +121,8 @@ HEADERS += \ logfile.h \ crc.h \ mustache.h \ - textbubbleslider.h + textbubbleslider.h \ + filelogger.h HEADERS += xmlconfig.h