diff options
author | Wolfgang Beck <wolfgang.beck@nokia.com> | 2012-05-03 12:38:03 +1000 |
---|---|---|
committer | Lincoln Ramsay <lincoln.ramsay@nokia.com> | 2012-05-11 03:06:21 +0200 |
commit | 57555714f0b9cacefd7c1e2da61ed3c612d7791c (patch) | |
tree | fb4a0463a85d55fda7457f0055a6dfdf87a14d49 | |
parent | 85cc3138442ba282b869788fd4a4fd3a56d74758 (diff) |
Using QLoggingCategory without QT_LOG_CATEGORY macro
Change-Id: I086107777d49f1b9f6bc2396b8276f333ecd0e85
Reviewed-by: Lincoln Ramsay <lincoln.ramsay@nokia.com>
-rw-r--r-- | doc/src/index.qdoc | 75 | ||||
-rw-r--r-- | examples/logger/main.cpp | 18 | ||||
-rw-r--r-- | src/logger/qlogger.cpp | 380 | ||||
-rw-r--r-- | src/logger/qlogger.h | 101 | ||||
-rw-r--r-- | src/logger/qlogger_p.h | 32 | ||||
-rw-r--r-- | tests/auto/logger/logger.pro | 2 | ||||
-rw-r--r-- | tests/auto/logger/tst_qlogger.cpp | 68 |
7 files changed, 494 insertions, 182 deletions
diff --git a/doc/src/index.qdoc b/doc/src/index.qdoc index 7e9a32b..efaa7e8 100644 --- a/doc/src/index.qdoc +++ b/doc/src/index.qdoc @@ -54,9 +54,13 @@ Developer can create their own logging categories. Every category can be turned on or off for logging during runtime. + Each category contains a subset of "debug", "warning" and "critical" subcategories. + In the initialization logging will be performed for all "warning" and "critical" subcategories. + See \l {Default settings} . + \section1 How to Use @@ -70,12 +74,14 @@ #include <qlogger.h> - Note: qDebug, qWarning and qCritical are re-defined by this header. + Note: The current implementation re-defines qDebug, qWarning and qCritical by this header. + \section2 Creating Logging Rules \target logging_rules As mentioned above logging rules are needed to control the behavior of the logging. + The logging rules containing basically the categories and a true/false value for each category: @@ -90,13 +96,13 @@ \endtable Of course you could write Nokia.driver.usb = true, this will enable all subcategories (debug, warning and critical). - Vice versa with Nokia.driver.usb = false. + Vice versa with Nokia.driver.usb = false. - \section3 Wildcards + Wildcard (*) category definitions are possible as well. + The order of the categories in your configuration is important. From top to bottom the category priority is low to high. - Wildcard (*) category definitions are possible as well. The order of the categories in your configuration is important. From top to bottom the category priority is low to high. e.g: \table @@ -106,11 +112,12 @@ \row \li *Nokia*=true \endtable - All categories containing the word Nokia will be logged. - Willdcard "*" can only apply to the beginning or/and to the end of your configuration category entry. + In this example all categories containing the word Nokia will be logged. + Willdcard "*" can only apply to the beginning or/and to the end of your configuration category entry. The usage of qDebug(), qWarning() and qCrititcal results in the category "default". + e.g. \table @@ -121,26 +128,47 @@ \endtable - The logging rule file can be defined by using the environment variable \l QT_LOGGING_CONFIG. - The application developer can set the rule file by using \l qSetLoggingRulesFile() or can - set the rules directly using \l qSetLoggingRules(). + \section2 Create your Category Logging Object in your Project - If there is no configuration available, the \l {Default settings} will be used. + There are two different ways to create your own category object. - \section2 QT_LOGGING_CONFIG - The QT_LOGGING_CONFIG environment variable overrides both qSetLoggingRulesFile() and - qSetLoggingRules() if it points to a file. + 1. Qt provides the \l QT_LOG_CATEGORY() macro to create your logging Categories: - If QT_LOGGING_CONFIG is relative, QStandardPaths::writeableLocation(QStandardPaths::ConfigLocation) will be prepended. + \snippet logger/main.cpp 1 - \section2 Logging usage in your project + 2. You can create your own \l QLoggingCategory object: - Qt provides the \l QT_LOG_CATEGORY() macro to create your logging Categories: + \snippet logger/main.cpp 4 - \snippet logger/main.cpp 1 - In this example a logging category NOKIA_DRIVER_USB with a category string of "Nokia.driver.usb" and NOKIA_DRIVER_EVENT with a category string of "Nokia.driver.event" is created. + \section2 Activate Logging Rules + + There are 3 three different way to activate the logging rules: + + \table + \header + \row \li 1. \li The application developer can set the rule file by using \l qSetLoggingRulesFile() + \snippet logger/main.cpp 2 + + \row \li 2. \li The application developer can set the rules directly using \l qSetLoggingRules(). + \snippet logger/main.cpp 5 + + \row \li 3. \li The logging rule file can be defined by using the environment variable called \section2 QT_LOGGING_CONFIG + + The QT_LOGGING_CONFIG environment variable overrides both qSetLoggingRulesFile() and + + qSetLoggingRules() if it points to a file. + + If QT_LOGGING_CONFIG is relative, QStandardPaths::writeableLocation(QStandardPaths::ConfigLocation) will be prepended. + \endtable + + If there is no loggin rules available, the \l {Default settings} will be used. + + In this example a logging category NOKIA_DRIVER_USB with a category string of "Nokia.driver.usb" + + and NOKIA_DRIVER_EVENT with a category string of "Nokia.driver.event" is created. + In you configuration file you could write: \table @@ -151,16 +179,13 @@ \endtable - Next you need to tell Qt where the logging rules configuration file can be found. - - \snippet logger/main.cpp 2 - - In this example the configuration file "mylogging.cfg" is in the current directory. + In this example the configuration file "logrules.txt" is in the current directory. For category-based logging statements, you need to use the \l qCDebug(), \l qCWarning() and \l qCCritical() macros. \snippet logger/main.cpp 3 + \section1 Default settings The defaults are as follows. @@ -177,5 +202,7 @@ In other words, only \l qCDebug() statements are hidden by default. - \sa QLogging + \section1 Classes + + \annotatedlist qlogging_classes */ diff --git a/examples/logger/main.cpp b/examples/logger/main.cpp index 1443433..c82c02c 100644 --- a/examples/logger/main.cpp +++ b/examples/logger/main.cpp @@ -96,10 +96,18 @@ protected: void LogThread::run() { +//![4] + QLoggingCategory myCategoryObject("My.Category.Object"); +//![4] + for (int i = 0; i < 60; i++) { qDebug() << "loop " << i; //![3] + //Category created by QT_LOG_CATEGORY qCDebug(NOKIA_DRIVER_USB) << "USB legacy loaded"; + + //Category created by using QLoggingCategory directly + qCDebug(myCategoryObject) << "Log with my category object"; //![3] sleep(1); qWarning() << "loop " << i; @@ -133,9 +141,17 @@ int main(int argc, char *argv[]) QFile::remove(LOGOUTPUTFILE); fprintf(stdout, "%s\r\n", "Now you can open the logrules.txt file and de/activate categories"); + if (QFile::exists("./logrules.txt")){ //![2] - QtLogger::qSetLoggingRulesFile("./logrules.txt"); + QtLogger::qSetLoggingRulesFile("./logrules.txt"); //![2] + } + else { +//![5] + QtLogger::qSetLoggingRules(QByteArray("Nokia.driver.usb=true")); +//![5] + } + LogThread logthread; logthread.start(); diff --git a/src/logger/qlogger.cpp b/src/logger/qlogger.cpp index 4307769..d2d868e 100644 --- a/src/logger/qlogger.cpp +++ b/src/logger/qlogger.cpp @@ -49,14 +49,70 @@ #include <QFileSystemWatcher> #include <QThread> #include <QCoreApplication> +#include <QMap> #include "qlogger_p.h" QT_USE_NAMESPACE QT_LOGGER_BEGIN_NAMESPACE +// qDebug truth table +// --------------------------------------- +// Log enabled | Category enabled | do Log +// --------------------------------------- +// false | ignore | true +// true | false | false +// true | true | true + +// qWarning truth table +// --------------------------------------- +// Log enabled | Category enabled | do Log +// --------------------------------------- +// false | ignore | true +// true | false | false +// true | true | true + +// qCritical truth table +// --------------------------------------- +// Log enabled | Category enabled | do Log +// --------------------------------------- +// false | ignore | true +// true | false | false +// true | true | true + +// qCDebug truth table +// --------------------------------------- +// Log enabled | Category enabled | do Log +// --------------------------------------- +// false | ignore | false +// true | false | false +// true | true | true + +// qCWarning truth table +// --------------------------------------- +// Log enabled | Category enabled | do Log +// --------------------------------------- +// false | ignore | true +// true | false | false +// true | true | true + +// qCCritical truth table +// --------------------------------------- +// Log enabled | Category enabled | do Log +// --------------------------------------- +// false | ignore | true +// true | false | false +// true | true | true + + Q_GLOBAL_STATIC(QLoggingPrivate, qLogging) + // Set to true after QLoggingPrivate has destructed +//declare static members static bool privateUnloaded = false; +static QMutex _mutexUnloadedCategory; +static QMutex _mutexPrivateCategoryObjects; +static QMap<QString, QLoggingCategoryPrivate *> _privateCategoryObjects; +static QLoggingCategoryDefault default_QLoggingCategory; // Set to true if a valid config file or set of rules has been specified static bool gEnabled = false; @@ -82,81 +138,174 @@ static void checkEnvironment() } } -namespace QLoggingCategories +/*! + \class QLoggingCategory + \ingroup qlogging_classes + + \brief The QLoggingCategory class represents a category logging object for the category logging framework. + + Users can create a QLoggingCategory object and use it in conjunction with + qCDebug, qCWarning and qCCritical. +*/ + +/*! + Construct a QLoggingCategory object with the provided \a category name. + The object becomes the local identifier for the category. +*/ +QLoggingCategory::QLoggingCategory(const char *category) + : d_ptr(0) + , _categoryName(category) { - QLoggingCategory default_QLoggingCategory("default"); - - QLoggingCategory::QLoggingCategory(const char *cat) - : _enabledDebug(false) - , _enabledWarning(true) - , _enabledCritical(true) - , _registered(false) - , _category(cat) - { - } +} - QLoggingCategory::~QLoggingCategory() - { - if (_registered && !privateUnloaded) { - qLogging()->unregisterCategory(*this); - } - } +/*! + Returns the category name. +*/ +const char* QLoggingCategory::categoryName() +{ + return _categoryName; +} - bool QLoggingCategory::statusMessageType(const QtMsgType &type) - { - switch (type) { - case QtDebugMsg: return _enabledDebug; - case QtWarningMsg: return _enabledWarning; - case QtCriticalMsg: return _enabledCritical; - default: - break; +/*! + \internal Returns the QLoggingCategory object used by the qDebug, qWarning and qCritical macros. +*/ +QLoggingCategory& QLoggingCategory::defaultCategory() +{ + return default_QLoggingCategory; +} + +/*! + Destruct a QLoggingCategory object +*/ +QLoggingCategory::~QLoggingCategory() +{ + if (d_ptr) { + QMutexLocker locker1(&_mutexPrivateCategoryObjects); + QMutexLocker locker(&_mutexUnloadedCategory); + //Don't use QExplicitlySharedDataPointer for only reference counting + //We have to lock the _privateCategoryObjects map anyways and therfore we lock the reference counting as well. + d_ptr->_references--; + if (d_ptr->_references == 0) { + if (d_ptr->_registered && !privateUnloaded) { + qLogging()->unregisterCategory(*this); + } + if (d_ptr->_references == 0) { + QString strcategory = QString::fromLatin1(d_ptr->_categoryName); + QMap<QString, QLoggingCategoryPrivate* >::iterator it = _privateCategoryObjects.find(strcategory); + if (it != _privateCategoryObjects.end()) + _privateCategoryObjects.remove(strcategory); + + delete d_ptr; + } } - return false; } +} - void QLoggingCategory::setStatusMessageType(const QtMsgType &type, bool status) - { - switch (type) { - case QtDebugMsg: _enabledDebug = status; - case QtWarningMsg: _enabledWarning = status; - case QtCriticalMsg: _enabledCritical = status; - default: - break; +/*! + \internal Default category class to create and initialisate a default category object +*/ +QLoggingCategoryDefault::QLoggingCategoryDefault() + : QLoggingCategory("default") +{ + //Note d_func creates private object and assign it to the d_ptr + d_func()->_enabledDebug = true; +} + +/*! + Returns true if a message of type \a msgtype will be printed. Returns false otherwise. + + This function may be useful to avoid doing expensive work to generate data that is only used for debug output. + + \code + // don't run the expensive code if the string won't print + if (CAT.isEnabled(QtDebugMsg)) { + QStringList items; + foreach (obj, list) { + items << format(obj); + } + qCDebug(CAT) << items; } - } + \endcode - bool isEnabled() - { - if (gEnvironment == EnvironmentNotChecked) - checkEnvironment(); - return gEnabled; - } + Note that the expansion of qCDebug() prevents arguments from being evaluated if the string won't print so it is not normally required to check isEnabled(). - bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type) - { - if (!isEnabled()) - return false; - return qLogging()->isEnabled(category, type); + \code + // expensive_func is not called if the string won't print + qCDebug(CAT) << expensive_func(); + \endcode +*/ +bool QLoggingCategory::isEnabled(QtMsgType msgtype) +{ + //Check if the contains of the environment variable QT_LOGGING_CONFIG was checked + //If not checkEnvironment will modify the gEnabled static member. + if (gEnvironment == EnvironmentNotChecked) + checkEnvironment(); + + /* Note that default category (qDebug & co) differs from the category objects + regarding to their message types initialisation values + + Message Type | default categor | category Object + ========================================================================= + QtDebugMsg | true | false + QtWarningMsg | true | true + QtCriticalMsg | true | true + */ + if (!gEnabled) { + //Category logging framework is disable so return the default values + //Note: Default category already exist so d_ptr is valid for default category + if (d_ptr) + return d_ptr->statusMessageType(msgtype); + //We do this because we want to avoid to create a QLoggingCategoryPrivate object + //and doing expensive operations if categroy logging is not active. + switch (msgtype) { + case QtDebugMsg: return false; + case QtWarningMsg: return true; + case QtCriticalMsg: return true; + default: + return false; + } } + return qLogging()->isEnabled(*this, msgtype); +} - QLoggingCategory& defaultCategory() - { - return default_QLoggingCategory; +/*! + \internal Overwrite the private object access function. + */ +QLoggingCategoryPrivate * QLoggingCategory::d_func() +{ + if (!d_ptr) { + QMutexLocker locker(&_mutexPrivateCategoryObjects); + //Another thread can call this function for the same QLoggingCategory object now + //Check the d_ptr after mutex lock again. + if (!d_ptr) { + QString strcategory; + //just for the insane case someone calls this constructor with an empty category parameter + if (_categoryName) + strcategory = QString::fromLatin1(_categoryName); + QMap<QString, QLoggingCategoryPrivate* >::iterator it = _privateCategoryObjects.find(strcategory); + if (it != _privateCategoryObjects.end()) + d_ptr = *it; + else { + d_ptr = new QLoggingCategoryPrivate(_categoryName); + _privateCategoryObjects.insert(strcategory, d_ptr); + } + //Don't use QExplicitlySharedDataPointer for only reference counting + //We have to lock the _privateCategoryObjects map anyways and therfore we lock the reference counting as well. + d_ptr->_references++; + } } + return d_ptr; } -/*! - \namespace QLogging -*/ /*! - \relates QLogging + \relates QLoggingCategory Load logging rules from \a path. If \a path is relative, QStandardPaths::writeableLocation(QStandardPaths::ConfigLocation) will be prepended. Note that if the QT_LOGGING_CONFIG environment variables points to a file, this function does nothing. - \sa QT_LOGGING_CONFIG + \sa {Activate Logging Rules} */ void qSetLoggingRulesFile(const QString &path) { @@ -168,14 +317,14 @@ void qSetLoggingRulesFile(const QString &path) } /*! - \relates QLogging + \relates QLoggingCategory Set logging \a rules directly. This is primarily intended for applications that wish to provide runtime control of their logging rather than relying on the user providing a configuration file. Note that if the QT_LOGGING_CONFIG environment variables points to a file, this function does nothing. - \sa QT_LOGGING_CONFIG + \sa {Activate Logging Rules} */ void qSetLoggingRules(const QByteArray &rules) { @@ -186,42 +335,45 @@ void qSetLoggingRules(const QByteArray &rules) } /*! - \relates QLogging + \relates QLoggingCategory \macro qCDebug(cat) - Works like qDebug() but only prints out if \a cat has been enabled. + Works like qDebug() but using category object \a cat. + Note: this does not process arguments if the string will not be printed so do not rely on side effects. \code qCDebug(CAT) << "my message"; \endcode - \sa QT_LOG_CATEGORY(), {Creating Logging Rules} + \sa QT_LOG_CATEGORY(), {Creating Logging Rules}, QLoggingCategory */ /*! - \relates QLogging + \relates QLoggingCategory \macro qCWarning(cat) - Works like qWarning() and can be disabled with \a cat. + Works like qWarning() but using category object \a cat. + Note: this does not process arguments if the string will not be printed so do not rely on side effects. \code qCWarning(CAT) << "my message"; \endcode - \sa QT_LOG_CATEGORY(), {Creating Logging Rules} + \sa QT_LOG_CATEGORY(), {Creating Logging Rules}, QLoggingCategory */ /*! - \relates QLogging + \relates QLoggingCategory \macro qCCritical(cat) - Works like qCritical() and can be disabled with \a cat. + Works like qCritical() but using category object \a cat. + Note: this does not process arguments if the string will not be printed so do not rely on side effects. \code qCCritical(CAT) << "my message"; \endcode - \sa QT_LOG_CATEGORY(), {Creating Logging Rules} + \sa QT_LOG_CATEGORY(), {Creating Logging Rules}, QLoggingCategory */ /*! - \relates QLogging - \macro QT_LOG_CATEGORY(cat, identifier) - Registers a logging category with local identifier \a cat and complete identifier \a identifier. + \relates QLoggingCategory + \macro QT_LOG_CATEGORY(cat, categoryname) + Registers a logging category with local identifier \a cat and complete identifier \a categoryname. This macro must be used outside of a class or method. - \sa {Logging usage in your project} + \sa {Create your Category Logging Object in your Project}, QLoggingCategory */ @@ -231,9 +383,9 @@ void qSetLoggingRules(const QByteArray &rules) - - - +/********************************* + *Private objects implementation + *********************************/ /*! \internal For Autotest @@ -255,7 +407,7 @@ QLoggingPrivate::QLoggingPrivate() this->moveToThread(QCoreApplication::instance()->thread()); //add default category - _registeredCategories.append(&QLoggingCategories::default_QLoggingCategory); + _registeredCategories.append(&QLoggingCategory::defaultCategory()); } /*! @@ -264,6 +416,7 @@ QLoggingPrivate::QLoggingPrivate() */ QLoggingPrivate::~QLoggingPrivate() { + QMutexLocker locker(&_mutexUnloadedCategory); privateUnloaded = true; } @@ -360,7 +513,7 @@ void QLoggingPrivate::fileChanged(const QString &path) */ void QLoggingPrivate::readSettings(QIODevice &device) { - QMutexLocker locker(&_mutex); + QMutexLocker locker(&_mutexRegisteredCategory); { _logConfigItemList.clear(); @@ -379,7 +532,7 @@ void QLoggingPrivate::readSettings(QIODevice &device) } //Now all the categories are read, so we can update all known QLoggingCategories members. - foreach (QLoggingCategories::QLoggingCategory *category, _registeredCategories) { + foreach (QLoggingCategory *category, _registeredCategories) { updateCategory(category); } @@ -394,18 +547,18 @@ void QLoggingPrivate::readSettings(QIODevice &device) \internal Updates all the registered category members against the filter. */ -void QLoggingPrivate::updateCategory(QLoggingCategories::QLoggingCategory *log) +void QLoggingPrivate::updateCategory(QLoggingCategory *log) { //set the default back (debug disable, warning and critical enabled) - if (log == &QLoggingCategories::default_QLoggingCategory) { - log->_enabledDebug = true; - log->_enabledWarning = true; - log->_enabledCritical = true; + if (log == &QLoggingCategory::defaultCategory()) { + log->d_func()->_enabledDebug = true; + log->d_func()->_enabledWarning = true; + log->d_func()->_enabledCritical = true; } else { - log->_enabledDebug = false; - log->_enabledWarning = true; - log->_enabledCritical = true; + log->d_func()->_enabledDebug = false; + log->d_func()->_enabledWarning = true; + log->d_func()->_enabledCritical = true; } foreach (QLogConfigFilterItem item, _logConfigItemList) { @@ -413,15 +566,15 @@ void QLoggingPrivate::updateCategory(QLoggingCategories::QLoggingCategory *log) int filterpass = item.pass(log, QtDebugMsg); //apply filter if filterpass is not 0 if (filterpass != 0) - log->_enabledDebug = (filterpass > 0); + log->d_func()->_enabledDebug = (filterpass > 0); //Warning filterpass = item.pass(log, QtWarningMsg); if (filterpass != 0) - log->_enabledWarning = (filterpass > 0); + log->d_func()->_enabledWarning = (filterpass > 0); //Critical filterpass = item.pass(log, QtCriticalMsg); if (filterpass != 0) - log->_enabledCritical = (filterpass > 0); + log->d_func()->_enabledCritical = (filterpass > 0); } } @@ -429,36 +582,67 @@ void QLoggingPrivate::updateCategory(QLoggingCategories::QLoggingCategory *log) \internal Function that checks if the category is enabled and registered the category member if not already registered. */ -bool QLoggingPrivate::isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type) +bool QLoggingPrivate::isEnabled(QLoggingCategory &category, QtMsgType type) { - if (category._registered) - return category.statusMessageType(type); + if (category.d_func()->_registered) + return category.d_func()->statusMessageType(type); //category is unregistered. //First update category (let it through the filter) { - QMutexLocker locker(&_mutex); + QMutexLocker locker(&_mutexRegisteredCategory); //lock against _logConfigItemList between updateCategory and readSettings updateCategory(&category); - category._registered = true; + category.d_func()->_registered = true; _registeredCategories.append(&category); } - return category.statusMessageType(type); + return category.d_func()->statusMessageType(type); } /*! \internal Unregister a category object. */ -void QLoggingPrivate::unregisterCategory(QLoggingCategories::QLoggingCategory &category) +void QLoggingPrivate::unregisterCategory(QLoggingCategory &category) { - QMutexLocker locker(&_mutex); + QMutexLocker locker(&_mutexRegisteredCategory); //lock against _logConfigItemList between updateCategory and readSettings - category._registered = false; + category.d_func()->_registered = false; _registeredCategories.removeOne(&category); } +/*! + \internal Constructor of the private QLoggingCategory object +*/ +QLoggingCategoryPrivate::QLoggingCategoryPrivate(const char *categoryname) + : _enabledDebug(false) + , _enabledWarning(true) + , _enabledCritical(true) + , _registered(false) + , _categoryName(categoryname) + , _references(0) +{ +} + +QLoggingCategoryPrivate::~QLoggingCategoryPrivate() +{ +} + +/*! + \internal Returns true if the message type is activated otherwise false; +*/ +bool QLoggingCategoryPrivate::statusMessageType(const QtMsgType &type) +{ + switch (type) { + case QtDebugMsg: return _enabledDebug; + case QtWarningMsg: return _enabledWarning; + case QtCriticalMsg: return _enabledCritical; + default: + break; + } + return false; +} #define INVALID 0x00 #define CATEGORY 0x01 @@ -507,9 +691,9 @@ void QLogConfigFilterItem::parse() \internal return value 1 means filter passed, 0 means filter doesn't influence this category, -1 means category doesn't pass this filter */ -int QLogConfigFilterItem::pass(const QLoggingCategories::QLoggingCategory *log, const QtMsgType &type) +int QLogConfigFilterItem::pass(QLoggingCategory *log, const QtMsgType &type) { - QString fullCategory = QString::fromLatin1(log->_category); + QString fullCategory = QString::fromLatin1(log->categoryName()); switch (type) { case QtDebugMsg: fullCategory += QString::fromLatin1(".debug"); @@ -529,7 +713,7 @@ int QLogConfigFilterItem::pass(const QLoggingCategories::QLoggingCategory *log, //NOKIA.com.debug = true //or //NOKIA.com = true - if (_category == QString::fromLatin1(log->_category) || _category == fullCategory) + if (_category == QString::fromLatin1(log->categoryName()) || _category == fullCategory) return (_active ? 1 : -1); } diff --git a/src/logger/qlogger.h b/src/logger/qlogger.h index aada8c3..ba527de 100644 --- a/src/logger/qlogger.h +++ b/src/logger/qlogger.h @@ -49,28 +49,23 @@ QT_BEGIN_HEADER QT_LOGGER_BEGIN_NAMESPACE -namespace QLoggingCategories { - class Q_LOGGER_EXPORT QLoggingCategory { - public: - QLoggingCategory(const char *cat); - ~QLoggingCategory(); - bool statusMessageType(const QtMsgType &type); - void setStatusMessageType(const QtMsgType &type, bool status); - bool _enabledDebug; - bool _enabledWarning; - bool _enabledCritical; - bool _registered; - const char *_category; - }; - Q_LOGGER_EXPORT QLoggingCategory& defaultCategory(); - Q_LOGGER_EXPORT bool isEnabled(QLoggingCategory &category, QtMsgType type); - Q_LOGGER_EXPORT bool isEnabled(); -} - -// This is here so that QDoc has something to attach the functions -// and macros to. -namespace QLogging { -} +class QLoggingCategoryPrivate; +class Q_LOGGER_EXPORT QLoggingCategory { + Q_DISABLE_COPY(QLoggingCategory) +public: + explicit QLoggingCategory(const char *category); + ~QLoggingCategory(); + bool isEnabled(QtMsgType msgtype); + const char * categoryName(); + static QLoggingCategory& defaultCategory(); +protected: + QLoggingCategoryPrivate * d_func(); +private: + QLoggingCategoryPrivate *d_ptr; + const char *_categoryName; + + friend class QLoggingPrivate; +}; Q_LOGGER_EXPORT void qSetLoggingRules(const QByteArray &rules); Q_LOGGER_EXPORT void qSetLoggingRulesFile(const QString &path); @@ -84,41 +79,55 @@ QT_LOGGER_USE_NAMESPACE # undef qDebug #endif -#define qDebug if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::defaultCategory(), QtDebugMsg)) /*NOP*/; \ - else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug +#define qDebug \ + if (!QLoggingCategory::defaultCategory().isEnabled(QtDebugMsg)) \ + /*NOP*/; \ + else \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug #if defined(qWarning) # undef qWarning #endif -#define qWarning if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::defaultCategory(), QtWarningMsg)) /*NOP*/; \ - else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning +#define qWarning \ + if (!QLoggingCategory::defaultCategory().isEnabled(QtWarningMsg)) \ + /*NOP*/; \ + else \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning #if defined(qCritical) # undef qCritical #endif -#define qCritical if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::defaultCategory(), QtCriticalMsg)) /*NOP*/;\ - else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical - -#define QT_LOG_CATEGORY(categorytype, category) \ - namespace QtLogger { \ - namespace QLoggingCategories \ - { \ - static QLoggingCategory categorytype##_QLoggingCategory(category); \ - } \ +#define qCritical \ + if (!QLoggingCategory::defaultCategory().isEnabled(QtCriticalMsg)) \ + /*NOP*/; \ + else \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical + +//This marco creates the QLoggingCategory object in an empty namespace +//to prevent linker problems if someone else uses the categorytype in an other place. +#define QT_LOG_CATEGORY(categorytype, categoryname) \ + namespace { \ + static QLoggingCategory categorytype(categoryname); \ } -#define qCDebug(category) \ - if (!QLoggingCategories::isEnabled() || !QLoggingCategories::isEnabled(QLoggingCategories::category##_QLoggingCategory, QtDebugMsg)) /*NOP*/; \ - else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug() << QLoggingCategories::category##_QLoggingCategory._category << ": " \ - -#define qCWarning(category) \ - if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::category##_QLoggingCategory, QtWarningMsg)) /*NOP*/; \ - else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning() << QLoggingCategories::category##_QLoggingCategory._category << ": " \ - -#define qCCritical(category) \ - if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::category##_QLoggingCategory, QtCriticalMsg)) /*NOP*/; \ - else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical() << QLoggingCategories::category##_QLoggingCategory._category << ": " \ +#define qCDebug(category) \ + if (!category.isEnabled(QtDebugMsg)) \ + /*NOP*/; \ + else \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug() << category.categoryName() << ": " + +#define qCWarning(category) \ + if (!category.isEnabled(QtWarningMsg)) \ + /*NOP*/; \ + else \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning() << category.categoryName() << ": " + +#define qCCritical(category) \ + if (!category.isEnabled(QtCriticalMsg)) \ + /*NOP*/; \ + else \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical() << category.categoryName() << ": " #endif // QLOGGER_H diff --git a/src/logger/qlogger_p.h b/src/logger/qlogger_p.h index d7d1b8e..17ffd7f 100644 --- a/src/logger/qlogger_p.h +++ b/src/logger/qlogger_p.h @@ -62,7 +62,7 @@ class QLogConfigFilterItem { public: QLogConfigFilterItem(const QString &category, bool active); - int pass(const QLoggingCategories::QLoggingCategory *log, const QtMsgType &type); + int pass(QLoggingCategory *log, const QtMsgType &type); void parse(); int _type; QString _category; @@ -79,13 +79,13 @@ public: static QString resolveConfigFile(const QString &path); void setLoggingRulesFile(const QString &path); void setLoggingRules(const QByteArray &configcontent); - bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type); - void unregisterCategory(QLoggingCategories::QLoggingCategory &category); + bool isEnabled(QLoggingCategory &category, QtMsgType type); + void unregisterCategory(QLoggingCategory &category); Q_INVOKABLE void createFileWatcher(); void readSettings(QIODevice &device); - void updateCategory(QLoggingCategories::QLoggingCategory *log); + void updateCategory(QLoggingCategory *log); #ifdef QT_BUILD_INTERNAL Q_SIGNALS: @@ -97,12 +97,32 @@ public slots: public: QFileSystemWatcher *_configFileWatcher; - QList<QLoggingCategories::QLoggingCategory *> _registeredCategories; + QList<QLoggingCategory *> _registeredCategories; QString _configFile; - QMutex _mutex; + QMutex _mutexRegisteredCategory; QList<QLogConfigFilterItem> _logConfigItemList; }; +class QLoggingCategoryPrivate +{ +public: + QLoggingCategoryPrivate(const char *category); + virtual ~QLoggingCategoryPrivate(); + bool statusMessageType(const QtMsgType &type); + bool _enabledDebug; + bool _enabledWarning; + bool _enabledCritical; + bool _registered; + const char *_categoryName; + int _references; +}; + +class QLoggingCategoryDefault : public QLoggingCategory +{ +public: + QLoggingCategoryDefault(); +}; + Q_AUTOTEST_EXPORT QLoggingPrivate *qtLoggerInstance(); diff --git a/tests/auto/logger/logger.pro b/tests/auto/logger/logger.pro index 4e6b4c7..6a67eb1 100644 --- a/tests/auto/logger/logger.pro +++ b/tests/auto/logger/logger.pro @@ -2,6 +2,6 @@ TEMPLATE = app TARGET = tst_qlogger CONFIG += testcase -QT = core testlib logger +QT = core testlib logger-private SOURCES += tst_qlogger.cpp diff --git a/tests/auto/logger/tst_qlogger.cpp b/tests/auto/logger/tst_qlogger.cpp index 5753818..0bdbb4e 100644 --- a/tests/auto/logger/tst_qlogger.cpp +++ b/tests/auto/logger/tst_qlogger.cpp @@ -40,11 +40,13 @@ ****************************************************************************/ #include <QtTest/QtTest> -#include <QtLogger/QtLogger> -#include <QtTest/QtTest> #include <QFile> #include <QMutexLocker> #include <QtCore/qlogging.h> +#undef protected +#define protected public +#include <QtLogger/QtLogger> +#include <private/qlogger_p.h> QT_LOG_CATEGORY(TST_LOG, "tst.log") QT_LOG_CATEGORY(TST_LOG1, "tst.log1") @@ -106,11 +108,10 @@ static void myCustomMessageHandler(QtMsgType type, const QMessageLogContext &con { QMutexLocker locker(&threadmutex); logMessage = qMyMessageFormatString(type, context, msg); -// if (QLoggingCategories::isEnabled() && context.category){ - if (QLoggingCategories::isEnabled()){ +// if (isEnabled() && context.category){ if (multithreadtest) threadtest.append(logMessage); - } + // } } class CfgFile @@ -219,7 +220,6 @@ inline QString cleanLogLine(QString& qstring) } //QTLOGGER_USE_NAMESPACE - class tst_QLogger : public QObject { Q_OBJECT @@ -521,6 +521,62 @@ private slots: QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); } + void checkLogWithCategoryObject() + { + _configFile->clear(); + _configFile->addKey("LoggingCategoryObject", true); + QLoggingCategory *pcategorybject = 0; + qSetLoggingRules(_configFile->array()); + { + QLoggingCategory mycategoryobject("LoggingCategoryObject"); + pcategorybject = &mycategoryobject; + logMessage = "no change"; + + QString buf = QString::fromLatin1("LoggingCategoryObject: debug, My Category Object"); + qCDebug(mycategoryobject) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + buf = QString::fromLatin1("LoggingCategoryObject: warning, My Category Object"); + qCWarning(mycategoryobject) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + buf = QString::fromLatin1("LoggingCategoryObject: critical, My Category Object"); + qCCritical(mycategoryobject) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + QLoggingCategory mycategoryobject2("LoggingCategoryObject"); + buf = QString::fromLatin1("LoggingCategoryObject: debug, My Category Object"); + qCDebug(mycategoryobject) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + buf = QString::fromLatin1("LoggingCategoryObject: warning, My Category Object"); + qCWarning(mycategoryobject) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + buf = QString::fromLatin1("LoggingCategoryObject: critical, My Category Object"); + qCCritical(mycategoryobject) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + } + //check if mycategoryobject still registered. + QLoggingPrivate *logger = qtLoggerInstance(); + QVERIFY(!logger->_registeredCategories.contains(pcategorybject)); + } + + void checkEmptyCategoryName() + { + QLoggingCategory mycategoryobject(""); + + logMessage = "no change"; + QString buf = QString::fromLatin1("no change"); + qCDebug(mycategoryobject) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + QLoggingCategory mycategoryobject1(0); + buf = QString::fromLatin1("no change"); + qCDebug(mycategoryobject1) << "My Category Object"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + } + void checkMultithreading() { multithreadtest = true; |