diff options
author | Kai Koehne <kai.koehne@digia.com> | 2013-01-10 16:15:05 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-20 23:45:06 +0200 |
commit | 3efca77e35c0c336961f5e9640382ef87e83e794 (patch) | |
tree | 0b57aabfb4b3b4cf793f484fb555a09d91cde457 /src | |
parent | 99f9bf9af68530302fcb5a920f477a224adc0e09 (diff) |
Import qlogger framework
Merge most parts of the qlogger framework from
git://gitorious.org/qtplayground/qlogger.git
The categorized logging feature is a replacement for qDebug, qWarning and
friends. With logging statements in an app/library, a developer can
turn on the statements they care about and turn off the ones they don't.
Most work for this was done by Wolfgang Beck and Lincoln Ramsay.
Task-number: QTBUG-25694
Change-Id: Ib0cdfbbf3694f86ad9ec553b2ea36f09a477cded
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/doc/snippets/qloggingcategory/main.cpp | 113 | ||||
-rw-r--r-- | src/corelib/global/qlogging.cpp | 11 | ||||
-rw-r--r-- | src/corelib/io/io.pri | 9 | ||||
-rw-r--r-- | src/corelib/io/qloggingcategory.cpp | 352 | ||||
-rw-r--r-- | src/corelib/io/qloggingcategory.h | 138 | ||||
-rw-r--r-- | src/corelib/io/qloggingcategory_p.h | 66 | ||||
-rw-r--r-- | src/corelib/io/qloggingregistry.cpp | 312 | ||||
-rw-r--r-- | src/corelib/io/qloggingregistry_p.h | 135 |
8 files changed, 1134 insertions, 2 deletions
diff --git a/src/corelib/doc/snippets/qloggingcategory/main.cpp b/src/corelib/doc/snippets/qloggingcategory/main.cpp new file mode 100644 index 0000000000..d6d9ae0ff3 --- /dev/null +++ b/src/corelib/doc/snippets/qloggingcategory/main.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QCoreApplication> +#include <QLoggingCategory> + +//![1] +// in a header +Q_DECLARE_LOGGING_CATEGORY(QT_DRIVER_USB) + +// in one source file +Q_LOGGING_CATEGORY(QT_DRIVER_USB, "qt.driver.usb") +//![1] + + +// Completely made up example, inspired by en.wikipedia.org/wiki/USB :) +struct UsbEntry { + int id; + int classtype; +}; + +QDebug operator<<(QDebug &dbg, const UsbEntry &entry) +{ + dbg.nospace() << "" << entry.id << " (" << entry.classtype << ")"; + return dbg.space(); +} + +QList<UsbEntry> usbEntries() { + QList<UsbEntry> entries; + return entries; +} + +void main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + +//![2] + // don't run the expensive code if the string won't print + if (QT_DRIVER_USB().isEnabled<QtDebugMsg>()) { + QStringList items; + foreach (const UsbEntry &entry, usbEntries()) + items << QString("%1 (%2)").arg(entry.id, entry.classtype); + qCDebug(QT_DRIVER_USB) << "devices: " << items; + } +//![2] + +//![3] + // usbEntries() will only be called if QT_DRIVER_USB category is enabled + qCDebug(QT_DRIVER_USB) << "devices: " << usbEntries(); +//![3] + + { +//![10] + QLoggingCategory category("qt.driver.usb"); + qCDebug(category) << "a debug message"; +//![10] + } + + { +//![11] + QLoggingCategory category("qt.driver.usb"); + qCWarning(category) << "a warning message"; +//![11] + } + + { +//![12] + QLoggingCategory category("qt.driver.usb"); + qCCritical(category) << "a critical message"; +//![12] + } +} + +//![20] +void myCategoryFilter(QLoggingCategory *); +//![20] diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 5aaa0716f1..1cd11ad667 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -49,6 +49,8 @@ #ifndef QT_BOOTSTRAPPED #include "qcoreapplication.h" #include "qthread.h" +#include "qloggingcategory.h" +#include "private/qloggingregistry_p.h" #endif #ifdef Q_OS_WIN #include <qt_windows.h> @@ -920,6 +922,14 @@ static void qDefaultMsgHandler(QtMsgType type, const char *buf) static void qt_message_print(QtMsgType msgType, const QMessageLogContext &context, const QString &message) { +#ifndef QT_BOOTSTRAPPED + // qDebug, qWarning, ... macros do not check whether category is enabled + if (!context.category || (strcmp(context.category, "default") == 0)) { + if (!QLoggingCategory::defaultCategory().isEnabled(msgType)) + return; + } +#endif + if (!msgHandler) msgHandler = qDefaultMsgHandler; if (!messageHandler) @@ -1151,6 +1161,7 @@ void qSetMessagePattern(const QString &pattern) qMessagePattern()->setPattern(pattern); } + /*! Copies context information from \a logContext into this QMessageLogContext \internal diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index c00947dd97..b7fc1bc600 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -49,7 +49,10 @@ HEADERS += \ io/qfilesystemmetadata_p.h \ io/qfilesystemiterator_p.h \ io/qfileselector.h \ - io/qfileselector_p.h + io/qfileselector_p.h \ + io/qloggingcategory.h \ + io/qloggingcategory_p.h \ + io/qloggingregistry_p.h SOURCES += \ io/qabstractfileengine.cpp \ @@ -86,7 +89,9 @@ SOURCES += \ io/qfilesystemwatcher_polling.cpp \ io/qfilesystementry.cpp \ io/qfilesystemengine.cpp \ - io/qfileselector.cpp + io/qfileselector.cpp \ + io/qloggingcategory.cpp \ + io/qloggingregistry.cpp win32 { SOURCES += io/qsettings_win.cpp diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp new file mode 100644 index 0000000000..562cf25964 --- /dev/null +++ b/src/corelib/io/qloggingcategory.cpp @@ -0,0 +1,352 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qloggingcategory.h" +#include "qloggingcategory_p.h" +#include "qloggingregistry_p.h" + +QT_BEGIN_NAMESPACE + +const char qtDefaultCategoryName[] = "default"; + +Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory, + (qtDefaultCategoryName)) + +/*! + \class QLoggingCategory + \inmodule QtCore + \since 5.2 + + \brief A category, or 'area' in the logging infrastructure. + + QLoggingCategory represents a certain logging category - identified + by a string - at runtime. Whether a category should be actually logged or + not can be checked with the \l isEnabled() methods. + + \section1 Creating category objects + + Qt provides the \l Q_LOGGING_CATEGORY(), Q_DECLARE_LOGGING_CATEGORY() macros + to conveniently create static QLoggingCategory objects on the heap: + + \snippet qloggingcategory/main.cpp 1 + + \section1 Checking category configuration + + QLoggingCategory provides two isEnabled methods, a template one and a + non-template one, for checking whether the current category is enabled. + The template version checks for the most common case that no special rules + are applied in inline code, and should be preferred: + + \snippet qloggingcategory/main.cpp 2 + + Note that qCDebug() prevents arguments from being evaluated + if the string won't print, so calling isEnabled explicitly is not needed: + \l isEnabled(). + + \snippet qloggingcategory/main.cpp 3 + + \section1 Default configuration + + In the default configuration \l isEnabled() will return true for all + \l QtMsgType types except QtDebugMsg: QtDebugMsg is only active by default + for the \c "default" category. + + \section1 Changing configuration + + The default configuration can be changed by calling \l setEnabled(). However, + this only affects the current category object, not e.g. another object for the + same category name. Use either \l setFilterRules() or \l installFilter() to + configure categories globally. +*/ + +/*! + Constructs a QLoggingCategory object with the provided \a category name. + The object becomes the local identifier for the category. + + If \a category is \c{0}, the category name is changed to \c{"default"}. +*/ +QLoggingCategory::QLoggingCategory(const char *category) + : name(0), + enabledDebug(false), + enabledWarning(true), + enabledCritical(true) +{ + bool isDefaultCategory + = (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0); + + if (isDefaultCategory) { + // normalize default category names, so that we can just do + // pointer comparison in QLoggingRegistry::updateCategory + name = qtDefaultCategoryName; + enabledDebug = true; + } else { + name = category; + } + + if (QLoggingRegistry *reg = QLoggingRegistry::instance()) + reg->registerCategory(this);} + +/*! + Destructs a QLoggingCategory object +*/ +QLoggingCategory::~QLoggingCategory() +{ + if (QLoggingRegistry *reg = QLoggingRegistry::instance()) + reg->unregisterCategory(this); +} + +/*! + \fn const char *QLoggingCategory::categoryName() const + + Returns the name of the category. +*/ + +/*! + \fn bool QLoggingCategory::isEnabled() const + + Returns true if a message of the template \c QtMsgType argument should be + shown. Returns false otherwise. + + \note The qCDebug, qCWarning, qCCritical macros already do this check before + executing any code. However, calling this method may be useful to avoid + expensive generation of data that is only used for debug output. +*/ + +/*! + Returns true if a message of type \a msgtype for the category should be + shown. Returns false otherwise. + + \note The templated, inline version of this method, \l isEnabled(), is + optimized for the common case that no configuration is set, and should + generally be preferred. +*/ +bool QLoggingCategory::isEnabled(QtMsgType msgtype) const +{ + switch (msgtype) { + case QtDebugMsg: return enabledDebug; + case QtWarningMsg: return enabledWarning; + case QtCriticalMsg: return enabledCritical; + case QtFatalMsg: return true; + default: break; + } + return false; +} + +/*! + Changes the type \a type for the category to \a enable. + + Changes only affect the current QLoggingCategory object, and won't + change e.g. the settings of another objects for the same category name. + + \note QtFatalMsg cannot be changed. It will always return true. +*/ +void QLoggingCategory::setEnabled(QtMsgType type, bool enable) +{ + switch (type) { + case QtDebugMsg: enabledDebug = enable; break; + case QtWarningMsg: enabledWarning = enable; break; + case QtCriticalMsg: enabledCritical = enable; break; + case QtFatalMsg: + default: break; + } +} + +/*! + \fn QLoggingCategory &QLoggingCategory::operator()() + + Returns the object itself. This allows both a QLoggingCategory variable, and + a factory method returning a QLoggingCategory, to be used in qCDebug(), + qCWarning(), qCCritial() macros. + */ + +/*! + Returns the category "default" that is used e.g. by qDebug(), qWarning(), + qCritical(), qFatal(). + */ +QLoggingCategory &QLoggingCategory::defaultCategory() +{ + return *qtDefaultCategory(); +} + +/*! + \typedef QLoggingCategory::CategoryFilter + + This is a typedef for a pointer to a function with the following + signature: + + \snippet qloggingcategory/main.cpp 20 + + A function with this signature can be installed with \l installFilter(). +*/ + +/*! + Installs a function \a filter that is used to determine which categories + and message types should be enabled. Returns a pointer to the previous + installed filter. + + Every QLoggingCategory object created is passed to the filter, and the + filter is free to change the respective category configuration with + \l setEnabled(). + + An alternative way of configuring the default filter is via + \l setFilterRules(). + */ +QLoggingCategory::CategoryFilter +QLoggingCategory::installFilter(QLoggingCategory::CategoryFilter filter) +{ + return QLoggingRegistry::instance()->installFilter(filter); +} + + +/*! + Configures which categories and message types should be enabled through a + a set of \a rules. + + Each line in \a rules must have the format + + \code + <category>[.<type>] = true|false + \endcode + + where \c <category> is the name of the category, potentially with \c{*} as a + wildcard symbol at the start and/or the end. The optional \c <type> must + be either \c debug, \c warning, or \c critical. + + The rules might be ignored if a custom category filter is installed with + \l installFilter(). +*/ +void QLoggingCategory::setFilterRules(const QString &rules) +{ + QLoggingRegistry::instance()->rulesParser.setRules(rules); +} + +/*! + \macro qCDebug(category) + \relates QLoggingCategory + \since 5.2 + + Returns an output stream for debug messages in the logging category + \a category. + + The macro expands to code that first checks whether + \l QLoggingCategory::isEnabled() evaluates for debug output to \c{true}. + If so, the stream arguments are processed and sent to the message handler. + + Example: + + \snippet qloggingcategory/main.cpp 10 + + \note Arguments are not processed if debug output for the category is not + enabled, so do not rely on any side effects. + + \sa qDebug() +*/ + +/*! + \macro qCWarning(category) + \relates QLoggingCategory + \since 5.2 + + Returns an output stream for warning messages in the logging category + \a category. + + The macro expands to code that first checks whether + \l QLoggingCategory::isEnabled() evaluates for warning output to \c{true}. + If so, the stream arguments are processed and sent to the message handler. + + Example: + + \snippet qloggingcategory/main.cpp 11 + + \note Arguments are not processed if warning output for the category is not + enabled, so do not rely on any side effects. + + \sa qWarning() +*/ + +/*! + \macro qCCritical(category) + \relates QLoggingCategory + \since 5.2 + + Returns an output stream for critical messages in the logging category + \a category. + + The macro expands to code that first checks whether + \l QLoggingCategory::isEnabled() evaluates for critical output to \c{true}. + If so, the stream arguments are processed and sent to the message handler. + + Example: + + \snippet qloggingcategory/main.cpp 12 + + \note Arguments are not processed if critical output for the category is not + enabled, so do not reply on any side effects. + + \sa qCritical() +*/ + +/*! + \macro Q_DECLARE_LOGGING_CATEGORY(name) + \relates QLoggingCategory + \since 5.2 + + Declares a logging category \a name. The macro can be used to declare + a common logging category shared in different parts of the program. + + This macro must be used outside of a class or method. +*/ + +/*! + \macro Q_LOGGING_CATEGORY(name, string) + \relates QLoggingCategory + \since 5.2 + + Defines a logging category \a name, and makes it configurable under the + \a string identifier. + + Only one translation unit in a library or executable can define a category + with a specific name. + + This macro must be used outside of a class or method. +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h new file mode 100644 index 0000000000..90111c96fa --- /dev/null +++ b/src/corelib/io/qloggingcategory.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOGGINGCATEGORY_H +#define QLOGGINGCATEGORY_H + +#include <QtCore/qglobal.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QLoggingCategory +{ + Q_DISABLE_COPY(QLoggingCategory) +public: + explicit QLoggingCategory(const char *category); + ~QLoggingCategory(); + + template <QtMsgType T> + bool isEnabled() const + { + return isEnabled(T); + } + + bool isEnabled(QtMsgType type) const; + void setEnabled(QtMsgType type, bool enable); + + const char *categoryName() const { return name; } + + // allows usage of both factory method and variable in qCX macros + QLoggingCategory &operator()() { return *this; } + + static QLoggingCategory &defaultCategory(); + + typedef void (*CategoryFilter)(QLoggingCategory*); + static CategoryFilter installFilter(CategoryFilter); + + static void setFilterRules(const QString &rules); + +private: + const char *name; + + bool enabledDebug; + bool enabledWarning; + bool enabledCritical; + + friend class QLoggingRegistry; +}; + +template <> +inline bool QLoggingCategory::isEnabled<QtDebugMsg>() const +{ + return enabledDebug; +} + +template <> +inline bool QLoggingCategory::isEnabled<QtWarningMsg>() const +{ + return enabledWarning; +} + +template <> +inline bool QLoggingCategory::isEnabled<QtCriticalMsg>() const +{ + return enabledCritical; +} + +#define Q_DECLARE_LOGGING_CATEGORY(name) \ + extern QLoggingCategory &name(); + +// relies on QLoggingCategory(QString) being thread safe! +#define Q_LOGGING_CATEGORY(name, string) \ + QLoggingCategory &name() \ + { \ + static QLoggingCategory category(string); \ + return category; \ + } + +#define qCDebug(category) \ + for (bool enabled = category().isEnabled<QtDebugMsg>(); enabled; enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).debug() +#define qCWarning(category) \ + for (bool enabled = category().isEnabled<QtWarningMsg>(); enabled; enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).warning() +#define qCCritical(category) \ + for (bool enabled = category().isEnabled<QtCriticalMsg>(); enabled; enabled = false) \ + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).critical() + +#if defined(QT_NO_DEBUG_OUTPUT) +# undef qCDebug +# define qCDebug(category) QT_NO_QDEBUG_MACRO() +#endif +#if defined(QT_NO_WARNING_OUTPUT) +# undef qCWarning +# define qCWarning(category) QT_NO_QWARNING_MACRO() +#endif + +QT_END_NAMESPACE + +#endif // QLOGGINGCATEGORY_H diff --git a/src/corelib/io/qloggingcategory_p.h b/src/corelib/io/qloggingcategory_p.h new file mode 100644 index 0000000000..7802f017fd --- /dev/null +++ b/src/corelib/io/qloggingcategory_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOGGINGCATEGORY_P_H +#define QLOGGINGCATEGORY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +// unique pointer to default category +// (allows to compare for pointers instead of strings) +extern const char qtDefaultCategoryName[]; + +QT_END_NAMESPACE + +#endif // QLOGGINGCATEGORY_P_H diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp new file mode 100644 index 0000000000..a82e6f65f4 --- /dev/null +++ b/src/corelib/io/qloggingregistry.cpp @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qloggingregistry_p.h" +#include "qloggingcategory_p.h" + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QLoggingRegistry, qtLoggingRegistry) + +/*! + \internal + Constructs a logging rule with default values. +*/ +QLoggingRule::QLoggingRule() : + flags(Invalid), + enabled(false) +{ +} + +/*! + \internal + Constructs a logging rule. +*/ +QLoggingRule::QLoggingRule(const QString &pattern, bool enabled) : + pattern(pattern), + flags(Invalid), + enabled(enabled) +{ + 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 QLoggingRule::pass(const QString &categoryName, QtMsgType msgType) const +{ + QString fullCategory = categoryName; + switch (msgType) { + case QtDebugMsg: + fullCategory += QLatin1String(".debug"); + break; + case QtWarningMsg: + fullCategory += QLatin1String(".warning"); + break; + case QtCriticalMsg: + fullCategory += QLatin1String(".critical"); + break; + default: + break; + } + + if (flags == FullText) { + // can be + // qtproject.org.debug = true + // or + // qtproject.org = true + if (pattern == categoryName + || pattern == fullCategory) + return (enabled ? 1 : -1); + } + + int idx = 0; + if (flags == MidFilter) { + // e.g. *.qtproject* + idx = fullCategory.indexOf(pattern); + if (idx >= 0) + return (enabled ? 1 : -1); + } else { + idx = fullCategory.indexOf(pattern); + if (flags == LeftFilter) { + // e.g. org.qtproject.* + if (idx == 0) + return (enabled ? 1 : -1); + } else if (flags == RightFilter) { + // e.g. *.qtproject + if (idx == (fullCategory.count() - pattern.count())) + return (enabled ? 1 : -1); + } + } + return 0; +} + +/*! + \internal + Parses the category and checks which kind of wildcard the filter can contain. + Allowed is f.ex.: + org.qtproject.logging FullText + org.qtproject.* LeftFilter + *.qtproject RightFilter + *.qtproject* MidFilter + */ +void QLoggingRule::parse() +{ + int index = pattern.indexOf(QLatin1Char('*')); + if (index < 0) { + flags = FullText; + } else { + flags = Invalid; + if (index == 0) { + flags |= RightFilter; + pattern = pattern.remove(0, 1); + index = pattern.indexOf(QLatin1Char('*')); + } + if (index == (pattern.length() - 1)) { + flags |= LeftFilter; + pattern = pattern.remove(pattern.length() - 1, 1); + } + } +} + +/*! + \internal + Creates a new QLoggingRules object. +*/ +QLoggingRulesParser::QLoggingRulesParser(QLoggingRegistry *registry) : + registry(registry) +{ +} + +/*! + \internal + Sets logging rules string. +*/ +void QLoggingRulesParser::setRules(const QString &content) +{ + QString content_ = content; + QTextStream stream(&content_, QIODevice::ReadOnly); + parseRules(stream); +} + +/*! + \internal + Parses rules out of a QTextStream. +*/ +void QLoggingRulesParser::parseRules(QTextStream &stream) +{ + QVector<QLoggingRule> rules; + + while (!stream.atEnd()) { + QString line = stream.readLine(); + + // Remove all whitespace from line + line = line.simplified(); + line.remove(QLatin1Char(' ')); + + const QStringList pair = line.split(QLatin1Char('=')); + if (pair.count() == 2) { + const QString pattern = pair.at(0); + bool enabled = (QString::compare(pair.at(1), + QLatin1String("true"), + Qt::CaseInsensitive) == 0); + rules.append(QLoggingRule(pattern, enabled)); + } + } + + registry->setRules(rules); +} + +/*! + \internal + QLoggingPrivate constructor + */ +QLoggingRegistry::QLoggingRegistry() + : rulesParser(this), + categoryFilter(defaultCategoryFilter) +{ +} + +/*! + \internal + Registers a category object. + + This method might be called concurrently for the same category object. +*/ +void QLoggingRegistry::registerCategory(QLoggingCategory *cat) +{ + QMutexLocker locker(®istryMutex); + + if (!categories.contains(cat)) { + categories.append(cat); + (*categoryFilter)(cat); + } +} + +/*! + \internal + Unregisters a category object. +*/ +void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat) +{ + QMutexLocker locker(®istryMutex); + + categories.removeOne(cat); +} + +/*! + \internal + Activates a new set of logging rules for the default filter. +*/ +void QLoggingRegistry::setRules(const QVector<QLoggingRule> &rules_) +{ + QMutexLocker locker(®istryMutex); + + rules = rules_; + + if (categoryFilter != defaultCategoryFilter) + return; + + foreach (QLoggingCategory *cat, categories) + (*categoryFilter)(cat); +} + +/*! + \internal + Installs a custom filter rule. +*/ +QLoggingCategory::CategoryFilter +QLoggingRegistry::installFilter(QLoggingCategory::CategoryFilter filter) +{ + QMutexLocker locker(®istryMutex); + + if (filter == 0) + filter = defaultCategoryFilter; + + QLoggingCategory::CategoryFilter old = categoryFilter; + categoryFilter = filter; + + foreach (QLoggingCategory *cat, categories) + (*categoryFilter)(cat); + + return old; +} + +QLoggingRegistry *QLoggingRegistry::instance() +{ + return qtLoggingRegistry(); +} + +/*! + \internal + Updates category settings according to rules. +*/ +void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat) +{ + // QLoggingCategory() normalizes all "default" strings + // to qtDefaultCategoryName + bool debug = (cat->categoryName() == qtDefaultCategoryName); + bool warning = true; + bool critical = true; + + QString categoryName = QLatin1String(cat->categoryName()); + QLoggingRegistry *reg = QLoggingRegistry::instance(); + foreach (const QLoggingRule &item, reg->rules) { + int filterpass = item.pass(categoryName, QtDebugMsg); + if (filterpass != 0) + debug = (filterpass > 0); + filterpass = item.pass(categoryName, QtWarningMsg); + if (filterpass != 0) + warning = (filterpass > 0); + filterpass = item.pass(categoryName, QtCriticalMsg); + if (filterpass != 0) + critical = (filterpass > 0); + } + + cat->setEnabled(QtDebugMsg, debug); + cat->setEnabled(QtWarningMsg, warning); + cat->setEnabled(QtCriticalMsg, critical); +} + + +QT_END_NAMESPACE diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h new file mode 100644 index 0000000000..cbf7aecc4f --- /dev/null +++ b/src/corelib/io/qloggingregistry_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOGGINGREGISTRY_P_H +#define QLOGGINGREGISTRY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qloggingcategory.h> +#include <QtCore/qmap.h> +#include <QtCore/qmutex.h> +#include <QtCore/qstring.h> +#include <QtCore/qtextstream.h> +#include <QtCore/qvector.h> + +QT_BEGIN_NAMESPACE + +class QLoggingRule +{ +public: + QLoggingRule(); + QLoggingRule(const QString &pattern, bool enabled); + int pass(const QString &categoryName, QtMsgType type) const; + + enum PatternFlag { + Invalid = 0x0, + FullText = 0x1, + LeftFilter = 0x2, + RightFilter = 0x4, + MidFilter = LeftFilter | RightFilter + }; + Q_DECLARE_FLAGS(PatternFlags, PatternFlag) + + QString pattern; + PatternFlags flags; + bool enabled; + +private: + void parse(); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QLoggingRule::PatternFlags) +Q_DECLARE_TYPEINFO(QLoggingRule, Q_MOVABLE_TYPE); + +class QLoggingRulesParser +{ +private: + explicit QLoggingRulesParser(class QLoggingRegistry *logging); + +public: + void setRules(const QString &content); + +private: + void parseRules(QTextStream &stream); + QLoggingRegistry *registry; + + friend class QLoggingRegistry; +}; + +class QLoggingRegistry +{ +public: + QLoggingRegistry(); + + void registerCategory(QLoggingCategory *category); + void unregisterCategory(QLoggingCategory *category); + + void setRules(const QVector<QLoggingRule> &rules); + + QLoggingCategory::CategoryFilter + installFilter(QLoggingCategory::CategoryFilter filter); + + static QLoggingRegistry *instance(); + + QLoggingRulesParser rulesParser; + +private: + static void defaultCategoryFilter(QLoggingCategory *category); + + QMutex registryMutex; + QVector<QLoggingRule> rules; + QList<QLoggingCategory*> categories; + QLoggingCategory::CategoryFilter categoryFilter; +}; + +QT_END_NAMESPACE + +#endif // QLOGGINGREGISTRY_P_H |