diff --git a/src/lib/Application.cpp b/src/lib/Application.cpp index 5cccb8f7..9d7d2da9 100644 --- a/src/lib/Application.cpp +++ b/src/lib/Application.cpp @@ -73,6 +73,8 @@ void Application::loadSettings() std::shared_ptr settings = ApplicationSettings::getInstance(); settings->load(FilePath(UserPaths::getAppSettingsPath())); + LogManager::getInstance()->setLoggingEnabled(settings->getLoggingEnabled()); + loadStyle(settings->getColorSchemePath()); } diff --git a/src/lib/component/ComponentManager.cpp b/src/lib/component/ComponentManager.cpp index 2b8f075f..dded2b8c 100644 --- a/src/lib/component/ComponentManager.cpp +++ b/src/lib/component/ComponentManager.cpp @@ -57,7 +57,7 @@ void ComponentManager::setup(ViewLayout* viewLayout) m_dialogView = m_componentFactory->getViewFactory()->createDialogView(viewLayout, m_componentFactory->getStorageAccess()); std::shared_ptr tabbedView = - m_componentFactory->getViewFactory()->createTabbedView(viewLayout, "Log"); + m_componentFactory->getViewFactory()->createTabbedView(viewLayout, "Log/Error"); m_tabbedViews.push_back(tabbedView); std::shared_ptr errorComponent = m_componentFactory->createErrorComponent(tabbedView.get()); diff --git a/src/lib/component/controller/LogController.cpp b/src/lib/component/controller/LogController.cpp index 3d8b865a..17bd676c 100644 --- a/src/lib/component/controller/LogController.cpp +++ b/src/lib/component/controller/LogController.cpp @@ -2,9 +2,12 @@ #include "data/access/StorageAccess.h" #include "utility/logging/LogManager.h" +#include "settings/ApplicationSettings.h" LogController::LogController() : Logger("WindowLogger") + , m_enabled(false) + , m_previousLogCount(0) { } @@ -12,6 +15,16 @@ LogController::~LogController() { } +void LogController::setEnabled(bool enabled) +{ + m_enabled = enabled; +} + +bool LogController::getEnabled() const +{ + return m_enabled; +} + LogView* LogController::getView() const { return Controller::getView(); @@ -24,21 +37,87 @@ void LogController::clear() void LogController::logInfo(const LogMessage& message ) { - addLog(LOG_INFOS, message); + if (!m_enabled) + { + return; + } + if (m_logLevel & Logger::LOG_INFOS) + { + addLog(LOG_INFOS, message); + } } void LogController::logError(const LogMessage& message ) { - addLog(LOG_ERRORS, message); + if (!m_enabled) + { + return; + } + if (m_logLevel & Logger::LOG_ERRORS) + { + addLog(LOG_ERRORS, message); + } } void LogController::logWarning(const LogMessage& message ) { - addLog(LOG_WARNINGS, message); + if (!m_enabled) + { + return; + } + if (m_logLevel & Logger::LOG_WARNINGS) + { + addLog(LOG_WARNINGS, message); + } +} + +void LogController::handleMessage(MessageLogFilterChanged* message) +{ + m_logLevel = message->logFilter; + ApplicationSettings* settings = ApplicationSettings::getInstance().get(); + settings->setLogFilter(m_logLevel); + settings->save(); + syncLogs(); } void LogController::addLog(Logger::LogLevel type, const LogMessage& message) { - getView()->addLog(type, message); + + m_logs.push_back( + Log( + type, + (message.getFileName().empty() ? "" : message.getFileName() + ": ") + message.message, + message.getTimeString("%H:%M:%S") + ) + ); + + if (m_waiting.try_lock()) + { + std::thread([&]() + { + std::this_thread::sleep_for( std::chrono::seconds(1) ); + syncLogs(); + m_waiting.unlock(); + }).detach(); + } +} + +void LogController::syncLogs() +{ + int logCount = m_logs.size(); + if (logCount > getView()->LogLimit) + { + m_logs.erase(m_logs.begin(),m_logs.begin() + logCount - LogView::LogLimit); + } + std::vector logs; + for( Log log : m_logs ) + { + if (log.type & m_logLevel) + { + logs.push_back(log); + } + } + + getView()->addLogs(logs); } diff --git a/src/lib/component/controller/LogController.h b/src/lib/component/controller/LogController.h index 311a070a..132c07e8 100644 --- a/src/lib/component/controller/LogController.h +++ b/src/lib/component/controller/LogController.h @@ -1,23 +1,32 @@ #ifndef LOG_CONTROLLER_H #define LOG_CONTROLLER_H +#include + #include "component/controller/Controller.h" #include "component/view/LogView.h" #include "utility/logging/Logger.h" #include "utility/logging/LogMessage.h" +#include "utility/messaging/MessageListener.h" +#include "utility/messaging/type/MessageLogFilterChanged.h" class StorageAccess; class LogController : public Controller , public Logger + , public MessageListener { public: LogController(); ~LogController(); + void setEnabled(bool enabled); + bool getEnabled() const; + private: + bool m_enabled; LogView* getView() const; virtual void clear(); @@ -26,7 +35,15 @@ private: virtual void logWarning(const LogMessage& message); virtual void logError(const LogMessage& message); + virtual void handleMessage(MessageLogFilterChanged* message); + + std::vector m_logs; + void addLog(Logger::LogLevel type, const LogMessage& message); + void syncLogs(); + std::mutex m_waiting; + int m_previousLogCount; + Logger::LogLevelMask m_logLevel; }; #endif // LOG_CONTROLLER_H diff --git a/src/lib/component/view/LogView.cpp b/src/lib/component/view/LogView.cpp index 4e98ee98..2e686d45 100644 --- a/src/lib/component/view/LogView.cpp +++ b/src/lib/component/view/LogView.cpp @@ -1,5 +1,7 @@ #include "component/view/LogView.h" +const int LogView::LogLimit = 500; + LogView::LogView(ViewLayout* viewLayout) : View(viewLayout) { @@ -13,3 +15,8 @@ std::string LogView::getName() const { return "Logs"; } + +bool LogView::hasLogLevel(const Logger::LogLevel type, const Logger::LogLevelMask mask) const +{ + return mask & type; +} diff --git a/src/lib/component/view/LogView.h b/src/lib/component/view/LogView.h index 41cdcaff..d8e43b36 100644 --- a/src/lib/component/view/LogView.h +++ b/src/lib/component/view/LogView.h @@ -6,6 +6,17 @@ #include "utility/logging/LogMessage.h" #include "utility/logging/Logger.h" +struct Log +{ + Log(Logger::LogLevel type, std::string message, std::string timestamp) + : type(type) + , message(message) + , timestamp(timestamp){} + Logger::LogLevel type; + std::string message; + std::string timestamp; +}; + class LogView : public View { @@ -13,10 +24,14 @@ public: LogView(ViewLayout* viewLayout); virtual ~LogView(); + virtual std::string getName() const; + virtual bool hasLogLevel(const Logger::LogLevel type, const Logger::LogLevelMask mask) const; virtual void clear() = 0; virtual void addLog(Logger::LogLevel type, const LogMessage& message) = 0; + virtual void addLogs(const std::vector& logs) = 0; + static const int LogLimit; }; #endif // LOG_VIEW_H diff --git a/src/lib/settings/ApplicationSettings.cpp b/src/lib/settings/ApplicationSettings.cpp index 9b5aac7c..bda78737 100644 --- a/src/lib/settings/ApplicationSettings.cpp +++ b/src/lib/settings/ApplicationSettings.cpp @@ -175,6 +175,16 @@ void ApplicationSettings::setVerboseIndexerLoggingEnabled(bool value) setValue("application/verbose_indexer_logging_enabled", value); } +void ApplicationSettings::setLogFilter(int mask) +{ + setValue("application/log_filter", mask); +} + +int ApplicationSettings::getLogFilter() const +{ + return getValue("application/log_filter", Logger::LOG_WARNINGS | Logger::LOG_ERRORS); +} + std::vector ApplicationSettings::getIndexingFilePaths() const { return getPathValues("application/state/indexing_paths/indexing_path"); diff --git a/src/lib/settings/ApplicationSettings.h b/src/lib/settings/ApplicationSettings.h index 323bb15d..8c02e415 100644 --- a/src/lib/settings/ApplicationSettings.h +++ b/src/lib/settings/ApplicationSettings.h @@ -47,12 +47,16 @@ public: float getScrollSpeed() const; void setScrollSpeed(float scrollSpeed); + // logging bool getLoggingEnabled() const; void setLoggingEnabled(bool loggingEnabled); bool getVerboseIndexerLoggingEnabled() const; void setVerboseIndexerLoggingEnabled(bool loggingEnabled); + int getLogFilter() const; + void setLogFilter(int mask); + std::vector getIndexingFilePaths() const; bool setIndexingFilePaths(const std::vector& indexingFiles); diff --git a/src/lib/utility/logging/LogManager.cpp b/src/lib/utility/logging/LogManager.cpp index eaacc3f8..ade8eb54 100644 --- a/src/lib/utility/logging/LogManager.cpp +++ b/src/lib/utility/logging/LogManager.cpp @@ -53,6 +53,16 @@ void LogManager::removeLoggersByType(const std::string& type) m_logManagerImplementation.removeLoggersByType(type); } +Logger* LogManager::getLogger(std::shared_ptr logger) +{ + return m_logManagerImplementation.getLogger(logger); +} + +Logger* LogManager::getLoggerByType(const std::string& type) +{ + return m_logManagerImplementation.getLoggerByType(type); +} + void LogManager::clearLoggers() { m_logManagerImplementation.clearLoggers(); diff --git a/src/lib/utility/logging/LogManager.h b/src/lib/utility/logging/LogManager.h index 57a877b0..a71a910a 100644 --- a/src/lib/utility/logging/LogManager.h +++ b/src/lib/utility/logging/LogManager.h @@ -22,6 +22,8 @@ public: void removeLoggersByType(const std::string& type); void clearLoggers(); int getLoggerCount() const; + Logger* getLoggerByType(const std::string& type); + Logger* getLogger(std::shared_ptr logger); void logInfo( const std::string& message, diff --git a/src/lib/utility/logging/LogManagerImplementation.cpp b/src/lib/utility/logging/LogManagerImplementation.cpp index dfa9477c..5a431cdf 100644 --- a/src/lib/utility/logging/LogManagerImplementation.cpp +++ b/src/lib/utility/logging/LogManagerImplementation.cpp @@ -49,6 +49,31 @@ void LogManagerImplementation::removeLoggersByType(const std::string& type) } } +Logger* LogManagerImplementation::getLogger(std::shared_ptr logger) +{ + std::lock_guard lockGuard(m_loggerMutex); + std::vector>::iterator it = std::find(m_loggers.begin(), m_loggers.end(), logger); + if (it != m_loggers.end()) + { + return (*it).get(); + } + return nullptr; +} + +Logger* LogManagerImplementation::getLoggerByType(const std::string& type) +{ + std::lock_guard lockGuard(m_loggerMutex); + for (unsigned int i = 0; i < m_loggers.size(); i++) + { + if (m_loggers[i]->getType() == type) + { + + return m_loggers[i].get(); + } + } + return nullptr; +} + void LogManagerImplementation::clearLoggers() { m_loggers.clear(); diff --git a/src/lib/utility/logging/LogManagerImplementation.h b/src/lib/utility/logging/LogManagerImplementation.h index 62debcf8..52097e53 100644 --- a/src/lib/utility/logging/LogManagerImplementation.h +++ b/src/lib/utility/logging/LogManagerImplementation.h @@ -26,6 +26,8 @@ public: void removeLoggersByType(const std::string& type); void clearLoggers(); int getLoggerCount() const; + Logger* getLogger(std::shared_ptr logger); + Logger* getLoggerByType(const std::string& type); void logInfo( const std::string& message, @@ -54,4 +56,4 @@ private: mutable std::mutex m_loggerMutex; }; -#endif // LOG_MANAGER_IMPLEMENTATION_H \ No newline at end of file +#endif // LOG_MANAGER_IMPLEMENTATION_H diff --git a/src/lib/utility/messaging/type/MessageLogFilterChanged.h b/src/lib/utility/messaging/type/MessageLogFilterChanged.h new file mode 100644 index 00000000..2db092b2 --- /dev/null +++ b/src/lib/utility/messaging/type/MessageLogFilterChanged.h @@ -0,0 +1,24 @@ +#ifndef MESSAGE_LOG_FILTER_CHANGED_H +#define MESSAGE_LOG_FILTER_CHANGED_H + +#include "utility/messaging/Message.h" +#include "utility/logging/Logger.h" + +class MessageLogFilterChanged + : public Message +{ +public: + MessageLogFilterChanged(const Logger::LogLevelMask filter) + : logFilter(filter) + { + } + + static const std::string getStaticType() + { + return "MessageLogFilterChanged"; + } + + const Logger::LogLevelMask logFilter; +}; + +#endif // MESSAGE_LOG_FILTER_CHANGED_H diff --git a/src/lib_gui/qt/QtApplication.cpp b/src/lib_gui/qt/QtApplication.cpp index 7f50551a..6522fec2 100644 --- a/src/lib_gui/qt/QtApplication.cpp +++ b/src/lib_gui/qt/QtApplication.cpp @@ -6,24 +6,23 @@ #include "utility/messaging/type/MessageDispatchWhenLicenseValid.h" #include "utility/messaging/type/MessageLoadProject.h" #include "utility/logging/LogManager.h" +#include "component/controller/LogController.h" #include "settings/ApplicationSettings.h" QtApplication::QtApplication(int& argc, char** argv) : QApplication(argc, argv) { - connect(this, &QCoreApplication::aboutToQuit, - [=]() - { - LogManager::getInstance()->setLoggingEnabled(false); - }); - } int QtApplication::exec() { - LogManager::getInstance()->setLoggingEnabled(ApplicationSettings::getInstance()->getLoggingEnabled()); + LogController* log = dynamic_cast(LogManager::getInstance()->getLoggerByType("WindowLogger")); + if (log != nullptr) + { + log->setEnabled(true); + } - return QCoreApplication::exec(); + return QApplication::exec(); } // responds to FileOpenEvent specific for Mac diff --git a/src/lib_gui/qt/view/QtLogView.cpp b/src/lib_gui/qt/view/QtLogView.cpp index 626865b6..bab60666 100644 --- a/src/lib_gui/qt/view/QtLogView.cpp +++ b/src/lib_gui/qt/view/QtLogView.cpp @@ -11,6 +11,7 @@ #include "settings/ColorScheme.h" #include "qt/view/QtViewWidgetWrapper.h" #include "utility/messaging/type/MessageRefresh.h" +#include "utility/messaging/type/MessageLogFilterChanged.h" #include "utility/ResourcePaths.h" #include "qt/utility/utilityQt.h" #include "utility/logging/LogManager.h" @@ -20,6 +21,7 @@ QtLogView::QtLogView(ViewLayout* viewLayout) : LogView(viewLayout) , m_addLogFunctor(std::bind(&QtLogView::doAddLog, this, std::placeholders::_1, std::placeholders::_2)) + , m_addLogsFunctor(std::bind(&QtLogView::doAddLogs, this, std::placeholders::_1 )) , m_clearFunctor(std::bind(&QtLogView::doClear, this)) , m_refreshFunctor(std::bind(&QtLogView::doRefreshView, this)) { @@ -46,8 +48,10 @@ void QtLogView::initView() QHBoxLayout* headerLayout = new QHBoxLayout(); headerLayout->addSpacing(10); + ApplicationSettings* settings = ApplicationSettings::getInstance().get(); + m_viewEnabled = new QCheckBox("Logging enabled (file, console logging)"); - m_viewEnabled->setChecked(ApplicationSettings::getInstance()->getLoggingEnabled()); + m_viewEnabled->setChecked(settings->getLoggingEnabled()); connect(m_viewEnabled, &QCheckBox::stateChanged, [=](int){ @@ -58,7 +62,7 @@ void QtLogView::initView() headerLayout->addSpacing(25); m_showAstLogging = new QCheckBox("AST Logging"); m_showAstLogging->setEnabled(m_viewEnabled->isChecked()); - m_showAstLogging->setChecked(ApplicationSettings::getInstance()->getVerboseIndexerLoggingEnabled()); + m_showAstLogging->setChecked(settings->getVerboseIndexerLoggingEnabled()); connect(m_showAstLogging, &QCheckBox::stateChanged, [=](int){ setAstLoggingEnabled(m_showAstLogging->isChecked()); @@ -86,9 +90,11 @@ void QtLogView::initView() QHBoxLayout* filters = new QHBoxLayout(); filters->addSpacing(15); - m_showErrors = createFilterCheckbox("error", filters, true); - m_showWarnings = createFilterCheckbox("warnings", filters, true); - m_showInfo = createFilterCheckbox("info", filters); + m_logLevel = settings->getLogFilter(); + + m_showErrors = createFilterCheckbox("error", filters, m_logLevel & Logger::LOG_ERRORS); + m_showWarnings = createFilterCheckbox("warnings", filters, m_logLevel & Logger::LOG_WARNINGS); + m_showInfo = createFilterCheckbox("info", filters, m_logLevel & Logger::LOG_INFOS); filters->addStretch(); @@ -98,7 +104,7 @@ void QtLogView::initView() { doClear(); }); - filters->addWidget(clearButton); + //filters->addWidget(clearButton); filters->addSpacing(30); updateMask(); @@ -131,7 +137,7 @@ QCheckBox* QtLogView::createFilterCheckbox(const QString& name, QBoxLayout* layo void QtLogView::setLoggingEnabled(bool enabled) { m_showAstLogging->setEnabled(enabled); - LogManager::getInstance()->setLoggingEnabled(true); + LogManager::getInstance()->setLoggingEnabled(enabled); ApplicationSettings::getInstance()->setLoggingEnabled(enabled); ApplicationSettings::getInstance()->save(); @@ -166,6 +172,11 @@ void QtLogView::addLog(Logger::LogLevel type, const LogMessage& message) m_addLogFunctor(type, message); } +void QtLogView::addLogs(const std::vector& logs) +{ + m_addLogsFunctor(logs); +} + void QtLogView::doClear() { if (!m_model->index(0, 0).data(Qt::DisplayRole).toString().isEmpty()) @@ -221,7 +232,7 @@ const char* QtLogView::getLogType(Logger::LogLevel type) const bool QtLogView::isCheckedType(const Logger::LogLevel type) const { - return m_mask & type; + return m_logLevel & type; } void QtLogView::updateTable() @@ -233,20 +244,21 @@ void QtLogView::updateTable() for ( Log log : m_logs ) { - if (log.type & m_mask) + if (log.type & m_logLevel) { addLogToTable(log); } } } - void QtLogView::updateMask() { - m_mask = + m_logLevel = (m_showInfo->isChecked() ? Logger::LOG_INFOS : 0) + (m_showWarnings->isChecked() ? Logger::LOG_WARNINGS : 0) + (m_showErrors->isChecked() ? Logger::LOG_ERRORS : 0); + + MessageLogFilterChanged(m_logLevel).dispatch(); } void QtLogView::addLogToTable(Log log) @@ -265,7 +277,7 @@ void QtLogView::addLogToTable(Log log) void QtLogView::doAddLog(Logger::LogLevel type, const LogMessage& message) { - if (isCheckedType(type)) + if (type & m_logLevel) { Log log( type, @@ -275,3 +287,16 @@ void QtLogView::doAddLog(Logger::LogLevel type, const LogMessage& message) addLogToTable(log); } } + +void QtLogView::doAddLogs(const std::vector& logs) +{ + doClear(); + for(Log log : logs) + { + if( log.type & m_logLevel ) + { + addLogToTable(log); + } + } + +} diff --git a/src/lib_gui/qt/view/QtLogView.h b/src/lib_gui/qt/view/QtLogView.h index babc828f..d7befeda 100644 --- a/src/lib_gui/qt/view/QtLogView.h +++ b/src/lib_gui/qt/view/QtLogView.h @@ -29,6 +29,7 @@ public: // Log View Implementation virtual void clear(); virtual void addLog(Logger::LogLevel type, const LogMessage& message); + virtual void addLogs(const std::vector& logs); private: enum LOGVIEW_COLUMN @@ -38,23 +39,15 @@ private: MESSAGE = 2, }; - struct Log - { - Log(const Logger::LogLevel type, const std::string message, const std::string timestamp) - : type(type) - , message(message) - , timestamp(timestamp){} - const Logger::LogLevel type; - const std::string message; - const std::string timestamp; - }; void doClear(); void doRefreshView(); void doAddLog(Logger::LogLevel type, const LogMessage& message); + void doAddLogs(const std::vector& logs); std::vector m_logs; const char* getLogType(Logger::LogLevel type) const; void addLogToTable(Log log); + void setLogFilter(); bool isCheckedType(const Logger::LogLevel type) const; QCheckBox* createFilterCheckbox(const QString& name, QBoxLayout* layout, bool checked = false); @@ -67,7 +60,7 @@ private: void updateMask(); void updateTable(); - int m_mask; + Logger::LogLevelMask m_logLevel; QtTable* m_table; QStandardItemModel* m_model; @@ -79,6 +72,7 @@ private: QCheckBox* m_showInfo; QtThreadedFunctor m_addLogFunctor; + QtThreadedFunctor&> m_addLogsFunctor; QtThreadedFunctor m_clearFunctor; QtThreadedFunctor m_refreshFunctor; }; diff --git a/src/lib_gui/qt/window/QtMainWindow.cpp b/src/lib_gui/qt/window/QtMainWindow.cpp index 83cb3d29..7c3b1453 100644 --- a/src/lib_gui/qt/window/QtMainWindow.cpp +++ b/src/lib_gui/qt/window/QtMainWindow.cpp @@ -14,6 +14,7 @@ #include "component/view/View.h" #include "component/view/CompositeView.h" #include "component/view/TabbedView.h" +#include "component/controller/LogController.h" #include "LicenseChecker.h" #include "qt/utility/QtContextMenu.h" #include "qt/utility/utilityQt.h" @@ -318,6 +319,11 @@ void QtMainWindow::contextMenuEvent(QContextMenuEvent* event) void QtMainWindow::closeEvent(QCloseEvent* event) { + LogController* log = dynamic_cast(LogManager::getInstance()->getLoggerByType("WindowLogger")); + if (log != nullptr) + { + log->setEnabled(false); + } MessageWindowClosed().dispatch(); }