From 4f9d522f7ba47d0f58bfd92d5daad9a40ed13c89 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Tue, 21 Oct 2014 01:25:55 +0100 Subject: [PATCH] refs #338 CLogHandler filtering messages using CLogPattern instead of the old prefix-based approach. --- src/blackmisc/loghandler.cpp | 38 ++++++++++++++++++++++-------------- src/blackmisc/loghandler.h | 37 ++++++++++++++++++++--------------- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/blackmisc/loghandler.cpp b/src/blackmisc/loghandler.cpp index af91d0fcf..a1a4c6f0b 100644 --- a/src/blackmisc/loghandler.cpp +++ b/src/blackmisc/loghandler.cpp @@ -8,6 +8,7 @@ */ #include "loghandler.h" +#include "algorithm.h" #include #include @@ -43,27 +44,34 @@ namespace BlackMisc qInstallMessageHandler(m_oldHandler); } - CLogCategoryHandler *CLogHandler::handlerForCategoryPrefix(const QString &category) + CLogPatternHandler *CLogHandler::handlerForPattern(const CLogPattern &pattern) { Q_ASSERT(thread() == QThread::currentThread()); - if (! m_categoryPrefixHandlers.contains(category)) + auto finder = [ & ](const PatternPair &pair) { return pair.first == pattern; }; + auto comparator = [](const PatternPair &a, const PatternPair &b) { return a.first.isProperSubsetOf(b.first); }; + + auto it = std::find_if(m_patternHandlers.begin(), m_patternHandlers.end(), finder); + if (it == m_patternHandlers.end()) { - m_categoryPrefixHandlers[category] = new CLogCategoryHandler(this, m_enableFallThrough); - + auto *handler = new CLogPatternHandler(this, m_enableFallThrough); + topologicallySortedInsert(m_patternHandlers, PatternPair(pattern, handler), comparator); + return handler; + } + else + { + return (*it).second; } - - return m_categoryPrefixHandlers[category]; } - QList CLogHandler::handlersForCategories(const CLogCategoryList &categories) const + QList CLogHandler::handlersForMessage(const CStatusMessage &message) const { - QList m_handlers; - for (auto i = m_categoryPrefixHandlers.begin(); i != m_categoryPrefixHandlers.end(); ++i) + QList m_handlers; + for (const auto &pair : m_patternHandlers) { - if (categories.anyStartWith(i.key())) + if (pair.first.match(message)) { - m_handlers.push_back(i.value()); + m_handlers.push_back(pair.second); } } return m_handlers; @@ -74,13 +82,13 @@ namespace BlackMisc Q_ASSERT(thread() == QThread::currentThread()); m_enableFallThrough = enable; - for (auto *handler : m_categoryPrefixHandlers.values()) + for (const auto &pair : m_patternHandlers) { - handler->enableConsoleOutput(enable); + pair.second->enableConsoleOutput(enable); } } - bool CLogHandler::isFallThroughEnabled(const QList &handlers) const + bool CLogHandler::isFallThroughEnabled(const QList &handlers) const { for (const auto *handler : handlers) { @@ -108,7 +116,7 @@ namespace BlackMisc { collectGarbage(); - auto handlers = handlersForCategories(statusMessage.getCategories()); + auto handlers = handlersForMessage(statusMessage); if (isFallThroughEnabled(handlers)) { diff --git a/src/blackmisc/loghandler.h b/src/blackmisc/loghandler.h index 88e2ccca6..9dea7dc7a 100644 --- a/src/blackmisc/loghandler.h +++ b/src/blackmisc/loghandler.h @@ -12,13 +12,14 @@ //! \file +#include "logpattern.h" #include "statusmessage.h" #include #include namespace BlackMisc { - class CLogCategoryHandler; + class CLogPatternHandler; /*! * Class for subscribing to log messages. @@ -41,9 +42,9 @@ namespace BlackMisc //! Tell the CLogHandler to install itself with qInstallMessageHandler. void install(); - //! Return a category handler for subscribing to all messages with a category starting with the given prefix. + //! Return a pattern handler for subscribing to all messages which match the given pattern. //! \warning This must only be called from the main thread. - CLogCategoryHandler *handlerForCategoryPrefix(const QString &prefix); + CLogPatternHandler *handlerForPattern(const CLogPattern &pattern); signals: //! Emitted when a message is logged in this process. @@ -67,34 +68,38 @@ namespace BlackMisc void collectGarbage(); QtMessageHandler m_oldHandler = nullptr; bool m_enableFallThrough = true; - bool isFallThroughEnabled(const QList &handlers) const; - QMap m_categoryPrefixHandlers; - QList handlersForCategories(const CLogCategoryList &categories) const; + bool isFallThroughEnabled(const QList &handlers) const; + using PatternPair = std::pair; + QList m_patternHandlers; + QList handlersForMessage(const CStatusMessage &message) const; }; /*! - * A class for subscribing to log messages in particular categories. - * \sa CLogHandler::handlerForCategory + * A class for subscribing to log messages which match particular patterns. + * \see CLogHandler::handlerForPattern */ - class CLogCategoryHandler : public QObject + class CLogPatternHandler : public QObject { Q_OBJECT public slots: /*! - * Enable or disable the default Qt handler for messages in relevant categories. - * This can override the setting of the parent CLogHandler. + * Enable or disable the default Qt handler for messages which match the relevant pattern. + * + * The setting of this property in one CLogPatternHandler can override the setting in another + * CLogPatternHandler or the base CLogHandler, if this handler's pattern is a subset of the + * other handler's pattern. Which is to say, more specific patterns can override less specific patterns. */ void enableConsoleOutput(bool enable) { Q_ASSERT(thread() == QThread::currentThread()); m_enableFallThrough = enable; } signals: /*! - * Emitted when a message is logged in a relevant category. + * Emitted when a message is logged which matches the relevant pattern. * - * When all slots are disconnected from this signal, the CLogCategoryHandler could be deleted. + * When all slots are disconnected from this signal, the CLogPatternHandler could be deleted. * - * Note that if a message matches more that one category handler, then this signal will be emitted for all of them, - * so if a slot is connected to all of them then it will be called multiple times. Use the methods + * Note that if a message matches more that one handler's pattern, then this signal will be emitted for all of + * those handlers, so if a slot is connected to all of them then it will be called multiple times. Use the methods * CStatusMessage::markAsHandledBy() and CStatusMessage::wasHandledBy() to detect this case in the slot and avoid * multiple handlings of the same message. Caveat: for this to work, the slot must take its argument by non-const * reference, and be connected by Qt::DirectConnection (i.e. the receiver is in the same thread as the CLogHandler). @@ -103,7 +108,7 @@ namespace BlackMisc private: friend class CLogHandler; - CLogCategoryHandler(QObject *parent, bool enableFallThrough) : QObject(parent), m_enableFallThrough(enableFallThrough) {} + CLogPatternHandler(QObject *parent, bool enableFallThrough) : QObject(parent), m_enableFallThrough(enableFallThrough) {} bool m_enableFallThrough; bool canBeDeleted()