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>
This commit is contained in:
Kai Koehne 2013-01-10 16:15:05 +01:00 committed by The Qt Project
parent 99f9bf9af6
commit 3efca77e35
12 changed files with 1965 additions and 2 deletions

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(&registryMutex);
if (!categories.contains(cat)) {
categories.append(cat);
(*categoryFilter)(cat);
}
}
/*!
\internal
Unregisters a category object.
*/
void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
{
QMutexLocker locker(&registryMutex);
categories.removeOne(cat);
}
/*!
\internal
Activates a new set of logging rules for the default filter.
*/
void QLoggingRegistry::setRules(const QVector<QLoggingRule> &rules_)
{
QMutexLocker locker(&registryMutex);
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(&registryMutex);
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

View File

@ -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

View File

@ -16,6 +16,7 @@ SUBDIRS=\
qiodevice \
qipaddress \
qlockfile \
qloggingcategory \
qnodebug \
qprocess \
qprocess-noapplication \

View File

@ -0,0 +1,7 @@
TEMPLATE = app
TARGET = tst_qloggingcategory
CONFIG += testcase
QT = core core-private testlib
SOURCES += tst_qloggingcategory.cpp

View File

@ -0,0 +1,818 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite 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 <QtTest>
#include <QMutexLocker>
#include <QLoggingCategory>
Q_LOGGING_CATEGORY(TST_LOG, "tst.log")
Q_LOGGING_CATEGORY(TST_LOG1, "tst.log1")
Q_LOGGING_CATEGORY(Digia_Oslo_Office_com, "Digia.Oslo.Office.com")
Q_LOGGING_CATEGORY(Digia_Oulu_Office_com, "Digia.Oulu.Office.com")
Q_LOGGING_CATEGORY(Digia_Berlin_Office_com, "Digia.Berlin.Office.com")
QT_USE_NAMESPACE
QtMessageHandler oldMessageHandler;
QString logMessage;
bool multithreadtest = false;
QStringList threadtest;
QMutex threadmutex;
bool usedefaultformat = false;
QByteArray qMyMessageFormatString(QtMsgType type, const QMessageLogContext &context,
const QString &str)
{
QByteArray message;
if (!usedefaultformat) {
message.append(context.category);
switch (type) {
case QtDebugMsg: message.append(".debug"); break;
case QtWarningMsg: message.append(".warning"); break;
case QtCriticalMsg:message.append(".critical"); break;
case QtFatalMsg: message.append(".fatal"); break;
}
message.append(": ");
message.append(qPrintable(str));
} else {
message.append(qPrintable(str));
}
return message.simplified();
}
static void myCustomMessageHandler(QtMsgType type,
const QMessageLogContext &context,
const QString &msg)
{
QMutexLocker locker(&threadmutex);
logMessage = qMyMessageFormatString(type, context, msg);
if (multithreadtest)
threadtest.append(logMessage);
}
class Configuration
{
public:
Configuration()
{
}
void addKey(const QString &key, bool val){
// Old key values gets updated
_values.insert(key, (val ? "true" : "false"));
if (!_configitemEntryOrder.contains(key))
_configitemEntryOrder.append(key);
}
void addKey(const QString &key, const QString &val){
// Old key values gets updated
_values.insert(key, val);
if (!_configitemEntryOrder.contains(key))
_configitemEntryOrder.append(key);
}
QByteArray array()
{
QString ret;
QTextStream out(&ret);
for (int a = 0; a < _configitemEntryOrder.count(); a++) {
out << _configitemEntryOrder[a]
<< " = "
<< _values.value(_configitemEntryOrder[a]) << endl;
}
out.flush();
return ret.toLatin1();
}
void clear()
{
_values.clear();
_configitemEntryOrder.clear();
}
private:
QMap<QString, QString> _values;
QStringList _configitemEntryOrder;
};
static Configuration configuration1;
static Configuration configuration2;
class LogThread : public QThread
{
Q_OBJECT
public:
LogThread(const QString &logtext, Configuration *configuration)
: _logtext(logtext), _configuration(configuration)
{}
protected:
void run()
{
for (int i = 0; i < 2000; i++) {
_configuration->addKey("Digia*", true);
QByteArray arr = _configuration->array();
QLoggingCategory::setFilterRules(arr);
qCDebug(Digia_Oslo_Office_com) << "Oslo " << _logtext << " :true";
_configuration->addKey("Digia*", false);
arr = _configuration->array();
QLoggingCategory::setFilterRules(arr);
qCDebug(Digia_Oslo_Office_com) << "Oslo " << _logtext << " :false";
_configuration->addKey("Digia*", true);
arr = _configuration->array();
QLoggingCategory::setFilterRules(arr);
qCDebug(Digia_Berlin_Office_com) << "Berlin " << _logtext << " :true";
_configuration->addKey("Digia*", false);
arr = _configuration->array();
QLoggingCategory::setFilterRules(arr);
qCDebug(Digia_Berlin_Office_com) << "Berlin " << _logtext << " :false";
_configuration->addKey("Digia*", true);
arr = _configuration->array();
QLoggingCategory::setFilterRules(arr);
qCDebug(Digia_Oulu_Office_com) << "Oulu " << _logtext << " :true";
_configuration->addKey("Digia*", false);
arr = _configuration->array();
QLoggingCategory::setFilterRules(arr);
qCDebug(Digia_Oulu_Office_com) << "Oulu " << _logtext << " :false";
}
}
public:
QString _logtext;
Configuration *_configuration;
};
inline QString cleanLogLine(const QString &qstring)
{
QString buf = qstring;
buf.remove("../");
buf.remove("qlog/");
QString ret;
for (int i = 0; i < buf.length(); i++) {
if (buf[i] >= '!' && buf[i] <= 'z')
ret += buf[i];
}
return ret;
}
QStringList customCategoryFilterArgs;
static void customCategoryFilter(QLoggingCategory *category)
{
customCategoryFilterArgs << QLatin1String(category->categoryName());
// invert debug
category->setEnabled(QtDebugMsg, !category->isEnabled(QtDebugMsg));
}
class tst_QLogging : public QObject
{
Q_OBJECT
private:
Configuration *_config;
QStringList logEntries;
private slots:
void initTestCase()
{
qputenv("QT_MESSAGE_PATTERN", QByteArray("%{category}: %{type},%{message}"));
oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler);
// Create configuration
_config = new Configuration();
}
void QLoggingCategory_categoryName()
{
logMessage.clear();
QCOMPARE(QString::fromLatin1(QLoggingCategory::defaultCategory().categoryName()),
QStringLiteral("default"));
QLoggingCategory defaultCategory("default");
QCOMPARE(QString::fromLatin1(defaultCategory.categoryName()),
QStringLiteral("default"));
QLoggingCategory nullCategory(0);
QCOMPARE(QByteArray(nullCategory.categoryName()), QByteArray("default"));
// we rely on the same pointer for any "default" category
QCOMPARE(QLoggingCategory::defaultCategory().categoryName(),
defaultCategory.categoryName());
QCOMPARE(defaultCategory.categoryName(),
nullCategory.categoryName());
QLoggingCategory customCategory("custom");
QCOMPARE(QByteArray(customCategory.categoryName()), QByteArray("custom"));
QLoggingCategory emptyCategory("");
QCOMPARE(QByteArray(emptyCategory.categoryName()), QByteArray(""));
// make sure nothing has printed warnings
QVERIFY(logMessage.isEmpty());
}
void QLoggingCategory_isEnabled()
{
logMessage.clear();
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>(), true);
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled(QtDebugMsg), true);
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtWarningMsg>(), true);
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled(QtWarningMsg), true);
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtCriticalMsg>(), true);
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled(QtCriticalMsg), true);
QLoggingCategory defaultCategory("default");
QCOMPARE(defaultCategory.isEnabled<QtDebugMsg>(), true);
QCOMPARE(defaultCategory.isEnabled(QtDebugMsg), true);
QCOMPARE(defaultCategory.isEnabled<QtWarningMsg>(), true);
QCOMPARE(defaultCategory.isEnabled(QtWarningMsg), true);
QCOMPARE(defaultCategory.isEnabled<QtCriticalMsg>(), true);
QCOMPARE(defaultCategory.isEnabled(QtCriticalMsg), true);
QLoggingCategory customCategory("custom");
QCOMPARE(customCategory.isEnabled<QtDebugMsg>(), false);
QCOMPARE(customCategory.isEnabled(QtDebugMsg), false);
QCOMPARE(customCategory.isEnabled<QtWarningMsg>(), true);
QCOMPARE(customCategory.isEnabled(QtWarningMsg), true);
QCOMPARE(customCategory.isEnabled<QtCriticalMsg>(), true);
QCOMPARE(customCategory.isEnabled(QtCriticalMsg), true);
// make sure nothing has printed warnings
QVERIFY(logMessage.isEmpty());
}
void QLoggingCategory_setEnabled()
{
logMessage.clear();
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>(), true);
QLoggingCategory::defaultCategory().setEnabled(QtDebugMsg, false);
QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>(), false);
QLoggingCategory::defaultCategory().setEnabled(QtDebugMsg, true);
// make sure nothing has printed warnings
QVERIFY(logMessage.isEmpty());
}
void QLoggingCategory_installFilter()
{
QVERIFY(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
QLoggingCategory::CategoryFilter defaultFilter =
QLoggingCategory::installFilter(customCategoryFilter);
QVERIFY(defaultFilter);
customCategoryFilterArgs.clear();
QVERIFY(!QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
QLoggingCategory cat("custom");
QCOMPARE(customCategoryFilterArgs, QStringList() << "custom");
QVERIFY(cat.isEnabled<QtDebugMsg>());
customCategoryFilterArgs.clear();
// install default filter
QLoggingCategory::CategoryFilter currentFilter =
QLoggingCategory::installFilter(defaultFilter);
QCOMPARE((void*)currentFilter, (void*)customCategoryFilter);
QCOMPARE(customCategoryFilterArgs.size(), 0);
QVERIFY(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
QVERIFY(!cat.isEnabled<QtDebugMsg>());
// install default filter
currentFilter =
QLoggingCategory::installFilter(0);
QCOMPARE((void*)defaultFilter, (void*)currentFilter);
QCOMPARE(customCategoryFilterArgs.size(), 0);
QVERIFY(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
QVERIFY(!cat.isEnabled<QtDebugMsg>());
}
void qDebugMacros()
{
QString buf;
// Check default debug
buf = QStringLiteral("default.debug: Check debug with no filter active");
qDebug("%s", "Check debug with no filter active");
QCOMPARE(logMessage, buf);
// Check default warning
buf = QStringLiteral("default.warning: Check warning with no filter active");
qWarning("%s", "Check warning with no filter active");
QCOMPARE(logMessage, buf);
// Check default critical
buf = QStringLiteral("default.critical: Check critical with no filter active");
qCritical("%s", "Check critical with no filter active");
QCOMPARE(logMessage, buf);
// install filter (inverts rules for qtdebug)
QLoggingCategory::installFilter(customCategoryFilter);
// Check default debug
logMessage.clear();
qDebug("%s", "Check debug with filter active");
QCOMPARE(logMessage, QString());
// reset to default filter
QLoggingCategory::installFilter(0);
// Check default debug
buf = QStringLiteral("default.debug: Check debug with no filter active");
qDebug("%s", "Check debug with no filter active");
QCOMPARE(logMessage, buf);
}
void qCDebugMacros()
{
QString buf;
QLoggingCategory defaultCategory("default");
// Check default debug
buf = QStringLiteral("default.debug: Check debug with no filter active");
qCDebug(defaultCategory) << "Check debug with no filter active";
QCOMPARE(logMessage, buf);
// Check default warning
buf = QStringLiteral("default.warning: Check warning with no filter active");
qCWarning(defaultCategory) << "Check warning with no filter active";
QCOMPARE(logMessage, buf);
// Check default critical
buf = QStringLiteral("default.critical: Check critical with no filter active");
qCCritical(defaultCategory) << "Check critical with no filter active";
QCOMPARE(logMessage, buf);
QLoggingCategory customCategory("custom");
// Check custom debug
logMessage.clear();
qCDebug(customCategory) << "Check debug with no filter active";
QCOMPARE(logMessage, QString());
// Check custom warning
buf = QStringLiteral("custom.warning: Check warning with no filter active");
qCWarning(customCategory) << "Check warning with no filter active";
QCOMPARE(logMessage, buf);
// Check custom critical
buf = QStringLiteral("custom.critical: Check critical with no filter active");
qCCritical(customCategory) << "Check critical with no filter active";
QCOMPARE(logMessage, buf);
// install filter (inverts rules for qtdebug)
QLoggingCategory::installFilter(customCategoryFilter);
// Check custom debug
buf = QStringLiteral("custom.debug: Check debug with filter active");
qCDebug(customCategory) << "Check debug with filter active";
QCOMPARE(logMessage, buf);
// reset to default filter
QLoggingCategory::installFilter(0);
// Check custom debug
logMessage.clear();
qCDebug(customCategory) << "Check debug with no filter active";
QCOMPARE(logMessage, QString());
}
void checkLegacyMessageLogger()
{
usedefaultformat = true;
// This should just not crash.
QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug() << "checkLegacyMessageLogger1";
QCOMPARE(logMessage, QStringLiteral("checkLegacyMessageLogger1"));
QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning() << "checkLegacyMessageLogger2";
QCOMPARE(logMessage, QStringLiteral("checkLegacyMessageLogger2"));
QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical() << "checkLegacyMessageLogger3";
QCOMPARE(logMessage, QStringLiteral("checkLegacyMessageLogger3"));
usedefaultformat = false;
}
// Check the Debug, Warning and critical without having category active. should be active.
void checkNoCategoryLogActive()
{
// Check default debug
QString buf = QStringLiteral("default.debug: Check default Debug with no log active");
qDebug() << "Check default Debug with no log active";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check default warning
buf = QStringLiteral("default.warning: Check default Warning with no log active");
qWarning() << "Check default Warning with no log active";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check default critical
buf = QStringLiteral("default.critical: Check default Critical with no log active");
qCritical() << "Check default Critical with no log active";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check category debug
logMessage = "should not change";
buf = logMessage;
qCDebug(TST_LOG) << "Check category Debug with no log active";
QCOMPARE(logMessage, buf);
// Check default warning
buf = QStringLiteral("tst.log.warning: Check category Warning with no log active");
qCWarning(TST_LOG) << "Check category Warning with no log active";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check default critical
buf = QStringLiteral("tst.log.critical: Check category Critical with no log active");
qCCritical(TST_LOG) << "Check category Critical with no log active";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
}
void writeCategoryLogs()
{
usedefaultformat = false;
// Activate TST_LOG category
logMessage = "";
_config->addKey("tst.log", true);
QLoggingCategory::setFilterRules(_config->array());
QString buf = QStringLiteral("tst.log.debug: Check for default messagePattern");
qCDebug(TST_LOG) << "Check for default messagePattern";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Activate TST_LOG category with default enabled function info
_config->addKey("tst.log1", true);
QLoggingCategory::setFilterRules(_config->array());
qCDebug(TST_LOG) << "1";
buf = QStringLiteral("tst.log.debug: 1");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Write out all different types
qCDebug(TST_LOG) << "DebugType";
buf = QStringLiteral("tst.log.debug: DebugType");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCWarning(TST_LOG) << "WarningType";
buf = QStringLiteral("tst.log.warning: WarningType");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCCritical(TST_LOG) << "CriticalType";
buf = QStringLiteral("tst.log.critical: CriticalType");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
}
void checkLegacyLogs()
{
logMessage = "";
qDebug() << "DefaultDebug";
QString buf = QStringLiteral("default.debug: DefaultDebug");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// debug off by default, warning and critical are on
qWarning() << "DefaultWarning";
buf = QStringLiteral("default.warning: DefaultWarning");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCritical() << "DefaultCritical";
buf = QStringLiteral("default.critical: DefaultCritical");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Enable debug
_config->addKey("default.debug", true);
QLoggingCategory::setFilterRules(_config->array());
qDebug() << "DefaultDebug1";
buf = QStringLiteral("default.debug: DefaultDebug1");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qWarning() << "DefaultWarning1";
buf = QStringLiteral("default.warning: DefaultWarning1");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCritical() << "DefaultCritical1";
buf = QStringLiteral("default.critical: DefaultCritical1");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Disable warning
_config->addKey("default.warning", false);
QLoggingCategory::setFilterRules(_config->array());
qDebug() << "DefaultDebug2";
buf = QStringLiteral("default.debug: DefaultDebug2");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
logMessage = "no change";
qWarning() << "DefaultWarning2";
buf = QStringLiteral("no change");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCritical() << "DefaultCritical2";
buf = QStringLiteral("default.critical: DefaultCritical2");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Disable critical
_config->addKey("default.critical", false);
_config->addKey("default.debug", false);
QLoggingCategory::setFilterRules(_config->array());
logMessage = "no change";
qDebug() << "DefaultDebug3";
buf = QStringLiteral("no change");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qWarning() << "DefaultWarning3";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCritical() << "DefaultCritical3";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Enable default logs
_config->addKey("default.critical", true);
_config->addKey("default.warning", true);
_config->addKey("default.debug", true);
QLoggingCategory::setFilterRules(_config->array());
// Ensure all are on
qDebug() << "DefaultDebug4";
buf = QStringLiteral("default.debug: DefaultDebug4");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qWarning() << "DefaultWarning4";
buf = QStringLiteral("default.warning: DefaultWarning4");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCritical() << "DefaultCritical4";
buf = QStringLiteral("default.critical: DefaultCritical4");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Disable default log
_config->addKey("default", false);
QLoggingCategory::setFilterRules(_config->array());
// Ensure all are off
logMessage = "no change";
buf = QStringLiteral("no change");
qDebug() << "DefaultDebug5";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qWarning() << "DefaultWarning5";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCritical() << "DefaultCritical5";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Reset
_config->clear();
QLoggingCategory::setFilterRules(_config->array());
}
void checkFiltering()
{
// Enable default logs
_config->clear();
_config->addKey("Digia.Oslo.Office.com", false);
_config->addKey("Digia.Oulu.Office.com", false);
_config->addKey("Digia.Berlin.Office.com", false);
_config->addKey("MessagePattern", QString("%{category}: %{message}"));
QLoggingCategory::setFilterRules(_config->array());
logMessage = "no change";
QString buf = QStringLiteral("no change");
qCDebug(Digia_Oslo_Office_com) << "Digia.Oslo.Office.com 1";
qCDebug(Digia_Oulu_Office_com) << "Digia.Oulu.Office.com 1";
qCDebug(Digia_Berlin_Office_com) << "Digia.Berlin.Office.com 1";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
_config->addKey("Digia.Oslo.Office.com", true);
_config->addKey("Digia.Oulu.Office.com", true);
_config->addKey("Digia.Berlin.Office.com", true);
QLoggingCategory::setFilterRules(_config->array());
qCDebug(Digia_Oslo_Office_com) << "Digia.Oslo.Office.com 2";
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Digia.Oslo.Office.com 2");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCDebug(Digia_Oulu_Office_com) << "Digia.Oulu.Office.com 2";
buf = QStringLiteral("Digia.Oulu.Office.com.debug: Digia.Oulu.Office.com 2");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCDebug(Digia_Berlin_Office_com) << "Digia.Berlin.Office.com 2";
buf = QStringLiteral("Digia.Berlin.Office.com.debug: Digia.Berlin.Office.com 2");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check right filter
_config->addKey("Digia.Oslo.Office.com", false);
_config->addKey("Digia.Oulu.Office.com", false);
_config->addKey("Digia.Berlin.Office.com", false);
_config->addKey("*Office.com*", true);
QLoggingCategory::setFilterRules(_config->array());
qCDebug(Digia_Oslo_Office_com) << "Digia.Oslo.Office.com 3";
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Digia.Oslo.Office.com 3");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCDebug(Digia_Oulu_Office_com) << "Digia.Oulu.Office.com 3";
buf = QStringLiteral("Digia.Oulu.Office.com.debug: Digia.Oulu.Office.com 3");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCDebug(Digia_Berlin_Office_com) << "Digia.Berlin.Office.com 3";
buf = QStringLiteral("Digia.Berlin.Office.com.debug: Digia.Berlin.Office.com 3");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check left filter
_config->addKey("*Office.com*", false);
_config->addKey("*Office.com.debug", true);
QLoggingCategory::setFilterRules(_config->array());
qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 4";
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Debug: Digia.Oslo.Office.com 4");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
logMessage = "no change";
buf = QStringLiteral("no change");
qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 4";
qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 4";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check right filter
_config->addKey("*Office.com.debug", false);
_config->addKey("Digia.*", true);
QLoggingCategory::setFilterRules(_config->array());
qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 5";
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Debug: Digia.Oslo.Office.com 5");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 5";
buf = QStringLiteral("Digia.Oulu.Office.com.warning: Warning: Digia.Oulu.Office.com 5");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 5";
buf = QStringLiteral("Digia.Berlin.Office.com.critical: Critical: Digia.Berlin.Office.com 5");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// Check mid filter
_config->addKey("Digia.*", false);
QLoggingCategory::setFilterRules(_config->array());
logMessage = "no change";
buf = QStringLiteral("no change");
qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 6";
qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 6";
qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 6";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
_config->addKey("*.Office.*", true);
QLoggingCategory::setFilterRules(_config->array());
qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 7";
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Debug: Digia.Oslo.Office.com 7");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 7";
buf = QStringLiteral("Digia.Oulu.Office.com.warning: Warning: Digia.Oulu.Office.com 7");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 7";
buf = QStringLiteral("Digia.Berlin.Office.com.critical: Critical: Digia.Berlin.Office.com 7");
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
}
void checkLogWithCategoryObject()
{
_config->clear();
_config->addKey("LoggingCategoryObject", true);
QLoggingCategory *pcategorybject = 0;
QLoggingCategory::setFilterRules(_config->array());
{
QLoggingCategory mycategoryobject("LoggingCategoryObject");
pcategorybject = &mycategoryobject;
logMessage = "no change";
QString buf = QStringLiteral("LoggingCategoryObject.debug: My Category Object");
qCDebug(mycategoryobject) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
buf = QStringLiteral("LoggingCategoryObject.warning: My Category Object");
qCWarning(mycategoryobject) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
buf = QStringLiteral("LoggingCategoryObject.critical: My Category Object");
qCCritical(mycategoryobject) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
QLoggingCategory mycategoryobject2("LoggingCategoryObject");
buf = QStringLiteral("LoggingCategoryObject.debug: My Category Object");
qCDebug(mycategoryobject) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
buf = QStringLiteral("LoggingCategoryObject.warning: My Category Object");
qCWarning(mycategoryobject) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
buf = QStringLiteral("LoggingCategoryObject.critical: My Category Object");
qCCritical(mycategoryobject) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
}
}
void checkEmptyCategoryName()
{
// "" -> custom category
QLoggingCategory mycategoryobject1("");
logMessage = "no change";
QString buf = QStringLiteral("no change");
qCDebug(mycategoryobject1) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
// 0 -> default category
QLoggingCategory mycategoryobject2(0);
buf = QStringLiteral("default.debug:MyCategoryObject");
qCDebug(mycategoryobject2) << "My Category Object";
QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
}
void checkMultithreading()
{
multithreadtest = true;
// Init two configurations, one for each thread
configuration1.addKey("Digia*", true);
configuration2.addKey("Digia*", true);
QByteArray arr = configuration1.array();
QLoggingCategory::setFilterRules(arr);
LogThread thgread1(QString("from Thread 1"), &configuration1);
LogThread thgread2(QString("from Thread 2"), &configuration2);
// Writing out stuff from 2 different threads into the same areas
thgread1.start();
thgread2.start();
thgread1.wait();
thgread2.wait();
// Check if each log line is complete
QStringList compareagainst;
QString buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 1\" :true");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 1\" :true");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 1\" :true");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 1\" :false");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 1\" :false");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 1\" :false");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 2\" :true");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 2\" :true");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 2\" :true");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 2\" :false");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 2\" :false");
compareagainst.append(cleanLogLine(buf));
buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 2\" :false");
compareagainst.append(cleanLogLine(buf));
for (int i = 0; i < threadtest.count(); i++) {
if (!compareagainst.contains(cleanLogLine(threadtest[i]))){
fprintf(stdout, "%s\r\n", threadtest[i].toLatin1().constData());
QVERIFY2(false, "Multithread log is not complete!");
}
}
}
void cleanupTestCase()
{
delete _config;
qInstallMessageHandler(oldMessageHandler);
}
};
QTEST_MAIN(tst_QLogging)
#include "tst_qloggingcategory.moc"

View File

@ -49,6 +49,7 @@
#include <QtCore/QtCore>
#include <QtCore/QtDebug>
#include <QtCore/QLoggingCategory>
#include <QtTest/QtTest>
class tst_QNoDebug: public QObject
@ -61,12 +62,16 @@ private slots:
void tst_QNoDebug::noDebugOutput() const
{
QLoggingCategory cat("custom");
// should do nothing
qDebug() << "foo";
qCDebug(cat) << "foo";
// qWarning still works, though
QTest::ignoreMessage(QtWarningMsg, "bar ");
QTest::ignoreMessage(QtWarningMsg, "custom-bar ");
qWarning() << "bar";
qCWarning(cat) << "custom-bar";
}
void tst_QNoDebug::streaming() const