refs #338 CLogHandler filtering messages using CLogPattern instead of the old prefix-based approach.

This commit is contained in:
Mathew Sutcliffe
2014-10-21 01:25:55 +01:00
parent 24485f6331
commit 4f9d522f7b
2 changed files with 44 additions and 31 deletions

View File

@@ -8,6 +8,7 @@
*/
#include "loghandler.h"
#include "algorithm.h"
#include <QCoreApplication>
#include <QMetaMethod>
@@ -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<CLogCategoryHandler *> CLogHandler::handlersForCategories(const CLogCategoryList &categories) const
QList<CLogPatternHandler *> CLogHandler::handlersForMessage(const CStatusMessage &message) const
{
QList<CLogCategoryHandler *> m_handlers;
for (auto i = m_categoryPrefixHandlers.begin(); i != m_categoryPrefixHandlers.end(); ++i)
QList<CLogPatternHandler *> 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<CLogCategoryHandler *> &handlers) const
bool CLogHandler::isFallThroughEnabled(const QList<CLogPatternHandler *> &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))
{

View File

@@ -12,13 +12,14 @@
//! \file
#include "logpattern.h"
#include "statusmessage.h"
#include <QObject>
#include <QMap>
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<CLogCategoryHandler *> &handlers) const;
QMap<QString, CLogCategoryHandler *> m_categoryPrefixHandlers;
QList<CLogCategoryHandler *> handlersForCategories(const CLogCategoryList &categories) const;
bool isFallThroughEnabled(const QList<CLogPatternHandler *> &handlers) const;
using PatternPair = std::pair<CLogPattern, CLogPatternHandler *>;
QList<PatternPair> m_patternHandlers;
QList<CLogPatternHandler *> 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()