From c21c15c6a2412da1dea6afc3b6ad24f759c3ae00 Mon Sep 17 00:00:00 2001 From: Wolfgang Beck Date: Mon, 2 Apr 2012 13:30:56 +1000 Subject: Create category logging module Change-Id: I12bd44a23e92abb8938af9b7ee22ffcae0391d8d Reviewed-by: Lincoln Ramsay Reviewed-by: Wolfgang Beck --- doc/doc.pri | 7 + doc/images/logger-example.png | Bin 0 -> 50823 bytes doc/logger.qdocconf | 78 +++++ doc/src/examples/logging.qdoc | 55 ++++ doc/src/index.qdoc | 192 +++++++++++++ doc/style.css | 146 ++++++++++ examples/examples.pro | 8 + examples/logger/logger.pro | 20 ++ examples/logger/logrules.txt | 6 + examples/logger/main.cpp | 143 +++++++++ modules/qt_logger.pri | 15 + qlogger.pro | 24 ++ src/logger/logger.pro | 26 ++ src/logger/qlogger.cpp | 411 ++++++++++++++++++++++++++ src/logger/qlogger.h | 117 ++++++++ src/logger/qlogger_p.h | 103 +++++++ src/logger/qloggerglobal.h | 71 +++++ src/src.pro | 3 + sync.profile | 23 ++ tests/auto/auto.pro | 4 + tests/auto/logger/logger.pro | 7 + tests/auto/logger/tst_qlogger.cpp | 588 ++++++++++++++++++++++++++++++++++++++ tests/tests.pro | 2 + 23 files changed, 2049 insertions(+) create mode 100644 doc/doc.pri create mode 100644 doc/images/logger-example.png create mode 100644 doc/logger.qdocconf create mode 100644 doc/src/examples/logging.qdoc create mode 100644 doc/src/index.qdoc create mode 100644 doc/style.css create mode 100644 examples/examples.pro create mode 100644 examples/logger/logger.pro create mode 100644 examples/logger/logrules.txt create mode 100644 examples/logger/main.cpp create mode 100644 modules/qt_logger.pri create mode 100644 qlogger.pro create mode 100644 src/logger/logger.pro create mode 100644 src/logger/qlogger.cpp create mode 100644 src/logger/qlogger.h create mode 100644 src/logger/qlogger_p.h create mode 100644 src/logger/qloggerglobal.h create mode 100644 src/src.pro create mode 100644 sync.profile create mode 100644 tests/auto/auto.pro create mode 100644 tests/auto/logger/logger.pro create mode 100644 tests/auto/logger/tst_qlogger.cpp create mode 100644 tests/tests.pro diff --git a/doc/doc.pri b/doc/doc.pri new file mode 100644 index 0000000..41457fe --- /dev/null +++ b/doc/doc.pri @@ -0,0 +1,7 @@ +OTHER_FILES += $$PWD/logger.qdocconf + +docs_target.target = docs +docs_target.commands = qdoc $$PWD/logger.qdocconf + +QMAKE_EXTRA_TARGETS = docs_target +QMAKE_CLEAN += "-r $$PWD/html" diff --git a/doc/images/logger-example.png b/doc/images/logger-example.png new file mode 100644 index 0000000..5b4b67b Binary files /dev/null and b/doc/images/logger-example.png differ diff --git a/doc/logger.qdocconf b/doc/logger.qdocconf new file mode 100644 index 0000000..bb20bf8 --- /dev/null +++ b/doc/logger.qdocconf @@ -0,0 +1,78 @@ +# alias.i = e + +project = QLogger +description = QLogger Documentation + +exampledirs = ../examples +headerdirs = ./src ../src +imagedirs = images +sourcedirs = ./src ../src + +Cpp.ignoretokens = \ + QT_BEGIN_HEADER \ + QT_END_HEADER \ + Q_ENUMS \ + Q_INVOKABLE \ + QT_LOGGER_BEGIN_NAMESPACE \ + QT_LOGGER_END_NAMESPACE \ + Q_LOGGER_EXPORT + +# The following parameters are for creating a qhp file, the qhelpgenerator +# program can convert the qhp file into a qch file which can be opened in +# Qt Assistant and/or Qt Creator. + +# Defines the name of the project. You cannot use operators (+, =, -) in +# the name. Properties for this project are set using a qhp..property +# format. +qhp.projects = QLogger + +# Sets the name of the output qhp file. +qhp.QLogger.file = QLogger.qhp + +# Namespace for the output file. This namespace is used to distinguish between +# different documentation files in Creator/Assistant. The namespace ends with +# a version being a number containing a major, minor and revision element. +# E.g. version 1.0 becomes 100. +qhp.QLogger.namespace = com.nokia.qlogger.100 + +# Title for the package, will be the main title for the package in +# Assistant/Creator. +qhp.QLogger.indexTitle = QLogger Reference Documentation + +# Extra files to add to the output which are not linked to from anywhere +# using a qdoc \l command. +qhp.QLogger.extraFiles = style/style.css \ + index.html + +# Only update the name of the project for the next variables. +qhp.QLogger.virtualFolder = qdoc +qhp.QLogger.subprojects = classes +qhp.QLogger.subprojects.classes.title = Classes +qhp.QLogger.subprojects.classes.selectors = class fake:headerfile +qhp.QLogger.subprojects.classes.sortPages = true + + +# Do NOT change the variables after this line unless you know what you are doing. + +outputdir = html +outputformats = HTML + +examples.fileextensions = "*.cpp *.h *.js *.svg *.xml *.ui *.qml" +examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng" +headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx" +sources.fileextensions = "*.cpp *.qdoc *.mm *.qml" + +HTML.nobreadcrumbs = "true" + +HTML.templatedir = . +HTML.stylesheets = style.css + +HTML.headerstyles = " \n" +HTML.endheader = "\n" + +HTML.postheader = \ + "
\n" \ + "
\n" \ + " QLogger Reference" \ + "
\n" \ + "
\n" diff --git a/doc/src/examples/logging.qdoc b/doc/src/examples/logging.qdoc new file mode 100644 index 0000000..fb02d96 --- /dev/null +++ b/doc/src/examples/logging.qdoc @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example logger + \title Logger Example + + The Logger example demonstrates the usage of logging categories in a file. + + \image logger-example.png + + + \section1 How to Use + + Compile and start the logger example in a console. + + + You can see debug traces created by this example. + + + Note that the "My.Category.B" doesn't appear. + + + Now open the logrules.txt file in an editor and modify the last line from + + + My.Category.B=false to My.Category.B=true. + + + Now you can see the "My.Category.B" appearing on the debug traces. +*/ diff --git a/doc/src/index.qdoc b/doc/src/index.qdoc new file mode 100644 index 0000000..e8dbf6d --- /dev/null +++ b/doc/src/index.qdoc @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of QtLogger +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page index.html + \title QLogger Reference + \brief The Qt Logging API provides the application developer a categorized logging mechanism. + + \section1 Introduction + + The Qt Logging API provides the application developer a categorized logging mechanism. + + + \section1 Overview + + The logging is designed to provide a flexible logging mechanism in an efficent manner. + + + \section1 Features + + + 1. Enable or disable logging without recompiling your project. + + Logging can be activated by providing a logging rules file or providing a QByteArray that contains the + \l {logging_rules} {rules}. + + + 2. Logging with categories + + Developer can create their own logging categories. + + Every category can be turned on or off for logging during runtime. + Each category contains a subset of "debug", "warning" and "critical" subcategories. + In the initialization logging will be performed for all "warning" and "critical" subcategories. + + + \section1 How to Use + + \section2 Add QLogger to Your Project + + First you need to add the QLogger library dependency to your application: + + LIBS += -lQtLogger + + or use + + QT+= logger + + In your application you need to include the QLogger header: + + #include + + Note: qDebug, qWarning and qCritical getting redefined in this header so make sure that the QLogger header gets included after qlogging.h. + + \section2 Creating Logging Rules + \target logging_rules + + As mentioned above logging rules are needed to control the behavior of the logging. + The logging rules containing basically the categories and a true/false value for each category: + + + Here is an example of some logging rules: + + + \table + \header + \row \li Nokia.driver.usb.debug = true + \row \li Nokia.driver.usb.warning = true + \row \li Nokia.driver.event = false + \endtable + + Of course you could write Nokia.driver.usb = true, this will enable all subcategories (debug, warning and critical). + Vice versa with Nokia.driver.usb = false. + + + \section3 Wildcards + + + Wildcard (*) category definitions are possible as well. The order of the categories in your configuration is important. From top to bottom the category priority is low to high. + e.g: + + \table + \header + \row \li Nokia*=false + \row \li *Nokia=true + \row \li *Nokia*=true + \endtable + + All categories containing the word Nokia will be logged. + Willdcard "*" can only apply to the beginning or/and to the end of your configuration category entry. + + + The usage of qDebug(), qWarning() and qCrititcal results in the category "default". + e.g. + + \table + \header \li Macro \li category + \row \li qDebug \li "default.debug" + \row \li qWarning \li "default.warning" + \row \li qCritical \li "default.critical" + \endtable + + + The logging rule file can be defined by using the environment variable QT_LOGGING_CONFIG. + The application developer can set the rule file by using: + + + qSetLoggingRulesFile(const QString &path) + + + or by defining a QByteArray containing the rules and call: + + + qSetLoggingRules(const QByteArray &configcontent) + + + If there is no configuration available logging will not be performed. + Note: QT_LOGGING_CONFIG will overwrite the qSetLoggingRulesFile and qSetLoggingRules calls. + + + \section2 Logging usage in your project + + Qt provides a macro to create your logging Categories: + + \snippet logger/main.cpp 1 + + In this example a logging category NOKIA_DRIVER_USB with a category string of "Nokia.driver.usb" and NOKIA_DRIVER_EVENT with a category string of "Nokia.driver.event" is created. + In you configuration file you could write: + + \table + \header + \row \li Nokia.driver.usb = true + \row \li Nokia.driver.event = true + \row \li or even: Nokia.driver.* = true + \endtable + + + Next you need to tell Qt where the logging rules configuration file can be found. + + \snippet logger/main.cpp 2 + + In this example the configuration file "mylogging.cfg" is in the current directory. + + A category logging can be done by using the qCDebug(), qCWarning() or the qCCritical() macro. + + \snippet logger/main.cpp 3 + + \section1 Default settings + If there is no logging rules defined "debug" subcategories are disabled but "warning" and "critical" are enabled. + + + + \section1 Functions + + + \section2 + qSetLoggingRules(const QByteArray &rules) + + Set the logging rules with the given \a rules byte array. + + + \section2 + qSetLoggingRulesFile(const QString &path) + + Set the config file with the given \a path which contains the logging rules for category logging. + The parameter \a path can contain only the file name. + In this case the standard path for configuration files QStandardPaths will be used. +*/ diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..24b0e0e --- /dev/null +++ b/doc/style.css @@ -0,0 +1,146 @@ +a:link, a:visited { + color: #00732F; + text-decoration: none; + font-weight: bold; +} + +body { + font: normal 400 14px/1.2 Arial; +# margin-top: 85px; +} + +h1 { + margin: 0; +} + +h2 { + font: 500 20px/1.2 Arial; +} + +h3.fn, span.fn { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border-width: 1px; + border-style: solid; + border-color: #E6E6E6; + word-spacing: 3px; + padding: 3px 5px; +} + +table, pre { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #E6E6E6; + border-collapse: separate; + font-size: 12px; + line-height: 1.2; + margin-bottom: 25px; + margin-left: 15px; +} + +table td { + padding: 3px 15px 3px 20px; +} + +table tr.even { + background-color: white; + color: #66666E; +} + +table tr.odd { + background-color: #F6F6F6; + color: #66666E; +} + +li { + margin-bottom: 10px; + padding-left: 12px; +} + +.cpp { + display: block; + margin: 10; + overflow: hidden; + overflow-x: hidden; + overflow-y: hidden; + padding: 20px 0 20px 0; +} + +.footer { + margin-top: 50px; +} + +.memItemLeft { + padding-right: 3px; +} + +.memItemRight { + padding: 3px 15px 3px 0; +} + +.qml { + display: block; + margin: 10; + overflow: hidden; + overflow-x: hidden; + overflow-y: hidden; + padding: 20px 0 20px 0; +} + +.qmldefault { + padding-left: 5px; + float: right; + color: red; +} + +.qmlreadonly { + padding-left: 5px; + float: right; + color: #254117; +} + +.rightAlign { + padding: 3px 5px 3px 10px; + text-align: right; +} + +.header { + background-color: #F6F6F6; + border: 1px solid #DDD; + padding: 5px 5px; + margin: 5px 5px; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; +} + +.title { + background-color: white; + color: #44A51C; + font-family: Verdana; + font-size: 35px; + font-weight: normal; + left: 0; + padding-bottom: 5px; + padding-left: 16px; + padding-top: 5px; +# position: absolute; + right: 0; + top: 0; +} + +.toc { + float: right; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #DDD; + margin: 0 20px 10px 10px; + padding: 20px 15px 20px 20px; + height: auto; + width: 200px; +} diff --git a/examples/examples.pro b/examples/examples.pro new file mode 100644 index 0000000..531c5c0 --- /dev/null +++ b/examples/examples.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +SUBDIRS = \ + logger + +# install +sources.files = README *.pro +sources.path = $$[QT_INSTALL_EXAMPLES] +INSTALLS += sources diff --git a/examples/logger/logger.pro b/examples/logger/logger.pro new file mode 100644 index 0000000..85d5c72 --- /dev/null +++ b/examples/logger/logger.pro @@ -0,0 +1,20 @@ +TARGET = logger +TEMPLATE = app +QT += core logger +QT -= gui +CONFIG += console +CONFIG -= app_bundle +SOURCES = main.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qtbase/logger +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS logger.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qtbase/logger +INSTALLS += target sources + +!equals(PWD, $${OUT_PWD}) { + #shadow build + QMAKE_SUBSTITUTES += copy + copy.input = $$PWD/logrules.txt + copy.output = $$OUT_PWD/logrules.txt +} diff --git a/examples/logger/logrules.txt b/examples/logger/logrules.txt new file mode 100644 index 0000000..4579fdc --- /dev/null +++ b/examples/logger/logrules.txt @@ -0,0 +1,6 @@ +default.*=true +default.critical=false +default.warning=true +default.debug=false +*.Category.*=true +My.Category.B=false diff --git a/examples/logger/main.cpp b/examples/logger/main.cpp new file mode 100644 index 0000000..1443433 --- /dev/null +++ b/examples/logger/main.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the demonstration applications of the logger module +** of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_LOG_CATEGORY(My_Category_A, "My.Category.A") +QT_LOG_CATEGORY(My_Category_B, "My.Category.B") +QT_LOG_CATEGORY(My_Category_C, "My.Category.C") + +#define LOGOUTPUTFILE "./logs.txt" +#define LOGRULESFILE "./logrules.txt" + +//![1] +QT_LOG_CATEGORY(NOKIA_DRIVER_USB, "Nokia.driver.usb") +QT_LOG_CATEGORY(NOKIA_DRIVER_EVENT, "Nokia.driver.event") +//![1] + +QMutex mutex; +QMessageHandler oldMessageHandler; + +QT_LOGGER_USE_NAMESPACE + +//Messagehandler to write into a file +static void myCustomMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *msg) +{ + //Lock against other threads accessing the file + QMutexLocker locker(&mutex); + QFile outFile(LOGOUTPUTFILE); + if (outFile.open(QIODevice::WriteOnly | QIODevice::Append)) { + QByteArray message; +// message.append("<"); +// message.append(context.category); +// message.append(">"); + + message.append(msg); + message.append('\n'); + outFile.write(message); + } + oldMessageHandler(type, context, msg); +} + +class LogThread : public QThread +{ +public: + LogThread() {} + +protected: + void run(); +}; + +void LogThread::run() +{ + for (int i = 0; i < 60; i++) { + qDebug() << "loop " << i; +//![3] + qCDebug(NOKIA_DRIVER_USB) << "USB legacy loaded"; +//![3] + sleep(1); + qWarning() << "loop " << i; + sleep(1); + qCritical() << "loop " << i; + sleep(1); + qCDebug(My_Category_A) << "loop " << i; + qCDebug(My_Category_B) << "loop " << i; + qCDebug(My_Category_C) << "loop " << i; + sleep(1); + qCWarning(My_Category_A) << "loop " << i; + qCWarning(My_Category_B) << "loop " << i; + qCWarning(My_Category_C) << "loop " << i; + sleep(1); + qCCritical(My_Category_A) << "loop " << i; + qCCritical(My_Category_B) << "loop " << i; + qCCritical(My_Category_C) << "loop " << i; + sleep(1); + } +} + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + +// qputenv ("QT_MESSAGE_PATTERN", QString("%{category}: %{type},%{message}").toLatin1()); + qputenv ("QT_MESSAGE_PATTERN", QString("%{type} %{message}").toLatin1()); + oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler); + + //delete old logoutput file + QFile::remove(LOGOUTPUTFILE); + + fprintf(stdout, "%s\r\n", "Now you can open the logrules.txt file and de/activate categories"); +//![2] + QtLogger::qSetLoggingRulesFile("./logrules.txt"); +//![2] + LogThread logthread; + logthread.start(); + + return a.exec(); +} diff --git a/modules/qt_logger.pri b/modules/qt_logger.pri new file mode 100644 index 0000000..4dc58e1 --- /dev/null +++ b/modules/qt_logger.pri @@ -0,0 +1,15 @@ +QT.logger.VERSION = 5.0.0 +QT.logger.MAJOR_VERSION = 5 +QT.logger.MINOR_VERSION = 0 +QT.logger.PATCH_VERSION = 0 + +QT.logger.name = QtLogger +QT.logger.bins = $$QT_MODULE_BIN_BASE +QT.logger.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtLogger +QT.logger.private_includes = $$QT_MODULE_INCLUDE_BASE/QtLogger/$$QT.logger.VERSION +QT.logger.sources = $$QT_MODULE_BASE/src/logger +QT.logger.libs = $$QT_MODULE_LIB_BASE +QT.logger.depends = core +QT.logger.DEFINES = QT_LOGGER_LIB + +QT_CONFIG += logger diff --git a/qlogger.pro b/qlogger.pro new file mode 100644 index 0000000..48eb777 --- /dev/null +++ b/qlogger.pro @@ -0,0 +1,24 @@ +TEMPLATE = subdirs + +SUBDIRS += module_qlogger_src +module_qlogger_src.subdir = src +module_qlogger_src.target = module-qlogger-src + +SUBDIRS += module_qlogger_tests +module_qlogger_tests.subdir = tests +module_qlogger_tests.target = module-qlogger-tests +module_qlogger_tests.depends = module_qlogger_src +module_qlogger_tests.CONFIG = no_default_install +!contains(QT_BUILD_PARTS,tests) { + module_qlogger_tests.CONFIG += no_default_target +} + +SUBDIRS += module_qlogger_examples +module_qlogger_examples.subdir = examples +module_qlogger_examples.target = module-qlogger-examples +module_qlogger_examples.depends = module_qlogger_src +!contains(QT_BUILD_PARTS,examples) { + module_qlogger_examples.CONFIG = no_default_target no_default_install +} + +include(doc/doc.pri) diff --git a/src/logger/logger.pro b/src/logger/logger.pro new file mode 100644 index 0000000..4dc96b9 --- /dev/null +++ b/src/logger/logger.pro @@ -0,0 +1,26 @@ +load(qt_module) + +TARGET = QtLogger +QPRO_PWD = $PWD +CONFIG += module +MODULE_PRI = ../../modules/qt_logger.pri + +QT = core + +DEFINES += QT_BUILD_LOGGER_LIB QT_MAKEDLL + +load(qt_module_config) +VERSION = $$QT.logger.VERSION + + +PUBLIC_HEADERS += \ + qlogger.h \ + qloggerglobal.h + +PRIVATE_HEADERS += \ + qlogger_p.h + +SOURCES += \ + qlogger.cpp + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/src/logger/qlogger.cpp b/src/logger/qlogger.cpp new file mode 100644 index 0000000..302a6f4 --- /dev/null +++ b/src/logger/qlogger.cpp @@ -0,0 +1,411 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the logger module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qlogger_p.h" + +QT_USE_NAMESPACE +QT_LOGGER_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QLoggingPrivate, qLogging) + +namespace QLoggingCategories +{ + bool _enabled = false; + QLoggingCategory default_QLoggingCategory("default"); + + QLoggingCategory::QLoggingCategory(const char *cat) + : _enabledDebug(false) + , _enabledWarning(true) + , _enabledCritical(true) + , _registered(false) + , _category(cat) + {} + + bool QLoggingCategory::statusMessageType(const QtMsgType &type) + { + switch (type) { + case QtDebugMsg: return _enabledDebug; + case QtWarningMsg: return _enabledWarning; + case QtCriticalMsg: return _enabledCritical; + default: + break; + } + return false; + } + + void QLoggingCategory::setStatusMessageType(const QtMsgType &type, bool status) + { + switch (type) { + case QtDebugMsg: _enabledDebug = status; + case QtWarningMsg: _enabledWarning = status; + case QtCriticalMsg: _enabledCritical = status; + default: + break; + } + } + + bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type) + { + return qLogging()->isEnabled(category, type); + } + + bool isEnabled() + { + return _enabled; + } + + QLoggingCategory& defaultCategory() + { + return default_QLoggingCategory; + } +} + +void qSetLoggingRulesFile(const QString &path) +{ + qLogging()->setLoggingRulesFile(path); +} + +void qSetLoggingRules(const QByteArray &rules) +{ + qLogging()->setLoggingRules(rules); +} + +/*! + \internal + QLoggingPrivate constructor + */ +QLoggingPrivate::QLoggingPrivate() + : _configFileWatcher(0) +{ + //add default category + _registeredCategories.append(&QLoggingCategories::default_QLoggingCategory); + + //Set the config file by using the envidonment variable QT_LOGGING_CONFIG + QByteArray ba = qgetenv("QT_LOGGING_CONFIG"); + if (!ba.isEmpty()) { + setLoggingRulesFile(QString::fromLocal8Bit(ba)); + _configFileEnvironmentVar = _configFile; + } +} + +/*! + \internal + QLoggingPrivate destructor + */ +QLoggingPrivate::~QLoggingPrivate() +{ +} + +/*! + \internal + Function to set the logging config file. + This function set the new QLogging configuration config file. + If QT_LOGGING_CONFIG is set this function will do nothing. +*/ +void QLoggingPrivate::setLoggingRulesFile(const QString &path) +{ + if (!_configFileEnvironmentVar.isEmpty()) + return; + + //Default no logging + QLoggingCategories::_enabled = false; + + //check the file if its only a filename + QFileInfo fi(path); + // If we have only a file, it lives in the config location + if (fi.fileName() == path) + fi.setFile(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1Char('/') + path); + _configFile = fi.absoluteFilePath(); + + //Check if logging rule file exits + if (QFile::exists(_configFile)) { + + //Create filewatcher only if a config file exists + if (!_configFileWatcher) { + _configFileWatcher = new QFileSystemWatcher(this); + connect(_configFileWatcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString))); + } + + QStringList oldfiles = _configFileWatcher->files(); + if (!oldfiles.isEmpty()) + _configFileWatcher->removePaths(oldfiles); + _configFileWatcher->addPath(_configFile); + + QFile cfgfile(_configFile); + readSettings(cfgfile); + } +} + +/*! + \internal + Function to set the logging rules. + This function set the new logging configuration. + If QT_LOGGING_CONFIG environment vaiable is in use, this function will not make any changes. +*/ +void QLoggingPrivate::setLoggingRules(const QByteArray &rules) +{ + if (!_configFileEnvironmentVar.isEmpty()) + return; + + //Disable file watcher + if (_configFileWatcher) { + delete _configFileWatcher; + _configFileWatcher = 0; + } + + //Default no logging + QLoggingCategories::_enabled = false; + QBuffer buffer; + buffer.setData(rules); + readSettings(buffer); +} + +/*! + \internal + Slot for filewatcher +*/ +void QLoggingPrivate::fileChanged(const QString &path) +{ + //check if the logging rule file was changed + if (path == _configFile){ + QFile cfgfile(_configFile); + readSettings(cfgfile); + _configFileWatcher->addPath(path); + } +} + +/*! + \internal + Reads the configuration out from a io device. +*/ +void QLoggingPrivate::readSettings(QIODevice &device) +{ + QMutexLocker locker(&_mutex); + { + _logConfigItemList.clear(); + + if (device.open(QIODevice::ReadOnly)) { + QByteArray truearray("true"); + QByteArray line; + while (!device.atEnd()) { + //Simplify the string before creating pair + line = device.readLine().replace(" ", ""); + line = line.simplified(); + const QList pair = line.split('='); + if (pair.count() == 2) + _logConfigItemList.append(QLogConfigFilterItem(QString::fromLatin1(pair.at(0)) + , (pair.at(1).toLower() == truearray))); + } + } + + //Now all the categories are read, so we can update all known QLoggingCategories members. + foreach (QLoggingCategories::QLoggingCategory *category, _registeredCategories) { + updateCategory(category); + } + + QLoggingCategories::_enabled = true; + } +} + +/*! + \internal + Updates all the registered category members against the filter. +*/ +void QLoggingPrivate::updateCategory(QLoggingCategories::QLoggingCategory *log) +{ + //set the default back (debug disable, warning and critical enabled) + if (log == &QLoggingCategories::default_QLoggingCategory) { + log->_enabledDebug = true; + log->_enabledWarning = true; + log->_enabledCritical = true; + + } else { + log->_enabledDebug = false; + log->_enabledWarning = true; + log->_enabledCritical = true; + } + + foreach (QLogConfigFilterItem item, _logConfigItemList) { + //Debug + int filterpass = item.pass(log, QtDebugMsg); + //apply filter if filterpass is not 0 + if (filterpass != 0) + log->_enabledDebug = (filterpass > 0); + //Warning + filterpass = item.pass(log, QtWarningMsg); + if (filterpass != 0) + log->_enabledWarning = (filterpass > 0); + //Critical + filterpass = item.pass(log, QtCriticalMsg); + if (filterpass != 0) + log->_enabledCritical = (filterpass > 0); + } +} + +/*! + \internal + Function that checks if the category is enabled and registered the category member if not already registered. +*/ +bool QLoggingPrivate::isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type) +{ + if (category._registered) + return category.statusMessageType(type); + + //category is unregistered. + //First update category (let it through the filter) + { + QMutexLocker locker(&_mutex); + //lock against _logConfigItemList between updateCategory and readSettings + updateCategory(&category); + category._registered = true; + _registeredCategories.append(&category); + } + + return category.statusMessageType(type); +} + +#define INVALID 0x00 +#define CATEGORY 0x01 +#define LEFTFILTER 0x02 +#define RIGHTFILTER 0x04 +#define MIDFILTER 0x06 +/*! + \internal + Constructor of a filter item. +*/ +QLogConfigFilterItem::QLogConfigFilterItem(const QString &category, bool active) + : _category(category) + , _active(active) +{ + parse(); +} + +/*! + \internal + Parses the category and check witch kind of wildcard the filter can contain. + Allowed is f.e.g.: + com.Nokia.* LEFTFILTER + *.Nokia RIGHTFILTER + *.Nokia* MIDFILTER + */ +void QLogConfigFilterItem::parse() +{ + _type = INVALID; + int index = _category.indexOf(QString::fromLatin1("*")); + if (index < 0) + _type |= CATEGORY; + else { + if (index == 0) { + _type |= RIGHTFILTER; + _category = _category.remove(0, 1); + index = _category.indexOf(QString::fromLatin1("*")); + } + if (index == (_category.length() - 1)) { + _type |= LEFTFILTER; + _category = _category.remove(_category.length() - 1, 1); + } + } +} + +/*! + \internal + return value 1 means filter passed, 0 means filter doesn't influence this category, -1 means category doesn't pass this filter + */ +int QLogConfigFilterItem::pass(const QLoggingCategories::QLoggingCategory *log, const QtMsgType &type) +{ + QString fullCategory = QString::fromLatin1(log->_category); + switch (type) { + case QtDebugMsg: + fullCategory += QString::fromLatin1(".debug"); + break; + case QtWarningMsg: + fullCategory += QString::fromLatin1(".warning"); + break; + case QtCriticalMsg: + fullCategory += QString::fromLatin1(".critical"); + break; + default: + break; + } + + if (_type == CATEGORY) { + //Can be + //NOKIA.com.debug = true + //or + //NOKIA.com = true + if (_category == QString::fromLatin1(log->_category) || _category == fullCategory) + return (_active ? 1 : -1); + } + + int idx = 0; + if (_type == MIDFILTER) { + //e.g. *.Nokia* + idx = fullCategory.indexOf(_category); + if (idx >= 0) + return (_active ? 1 : -1); + } else { + idx = fullCategory.indexOf(_category); + if (_type == LEFTFILTER) { + //e.g. com.Nokia.* + if (idx == 0) + return (_active ? 1 : -1); + } else if (_type == RIGHTFILTER) { + //e.g. *.Nokia + if (idx == (fullCategory.count() - _category.count())) + return (_active ? 1 : -1); + } + } + return 0; +} + +#include "moc_qlogger_p.cpp" + +QT_LOGGER_END_NAMESPACE + + diff --git a/src/logger/qlogger.h b/src/logger/qlogger.h new file mode 100644 index 0000000..24943b2 --- /dev/null +++ b/src/logger/qlogger.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the logger module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOGGER_H +#define QLOGGER_H + +#include +#include + +QT_BEGIN_HEADER +QT_LOGGER_BEGIN_NAMESPACE + +namespace QLoggingCategories { + class Q_LOGGER_EXPORT QLoggingCategory { + public: + QLoggingCategory(const char *cat); + bool statusMessageType(const QtMsgType &type); + void setStatusMessageType(const QtMsgType &type, bool status); + bool _enabledDebug; + bool _enabledWarning; + bool _enabledCritical; + bool _registered; + const char *_category; + }; + Q_LOGGER_EXPORT QLoggingCategory& defaultCategory(); + Q_LOGGER_EXPORT bool isEnabled(QLoggingCategory &category, QtMsgType type); + Q_LOGGER_EXPORT bool isEnabled(); +} + +Q_LOGGER_EXPORT void qSetLoggingRules(const QByteArray &rules); +Q_LOGGER_EXPORT void qSetLoggingRulesFile(const QString &path); + +QT_END_HEADER +QT_LOGGER_END_NAMESPACE + +QT_LOGGER_USE_NAMESPACE + +#if defined(qDebug) +# undef qDebug +#endif + +#define qDebug if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::defaultCategory(), QtDebugMsg)) /*NOP*/; \ + else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug + +#if defined(qWarning) +# undef qWarning +#endif + +#define qWarning if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::defaultCategory(), QtWarningMsg)) /*NOP*/; \ + else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning + +#if defined(qCritical) +# undef qCritical +#endif + +#define qCritical if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::defaultCategory(), QtCriticalMsg)) /*NOP*/;\ + else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical + +#define QT_LOG_CATEGORY(categorytype, category) \ + namespace QtLogger { \ + namespace QLoggingCategories \ + { \ + static QLoggingCategory categorytype##_QLoggingCategory(category); \ + } \ + } + +#define qCDebug(category) \ + if (!QLoggingCategories::isEnabled() || !QLoggingCategories::isEnabled(QLoggingCategories::category##_QLoggingCategory, QtDebugMsg)) /*NOP*/; \ + else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug() << QLoggingCategories::category##_QLoggingCategory._category << ": " \ + +#define qCWarning(category) \ + if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::category##_QLoggingCategory, QtWarningMsg)) /*NOP*/; \ + else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning() << QLoggingCategories::category##_QLoggingCategory._category << ": " \ + +#define qCCritical(category) \ + if (QLoggingCategories::isEnabled() && !QLoggingCategories::isEnabled(QLoggingCategories::category##_QLoggingCategory, QtCriticalMsg)) /*NOP*/; \ + else QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical() << QLoggingCategories::category##_QLoggingCategory._category << ": " \ + +#endif // QLOGGER_H diff --git a/src/logger/qlogger_p.h b/src/logger/qlogger_p.h new file mode 100644 index 0000000..4a3fee0 --- /dev/null +++ b/src/logger/qlogger_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtLogger module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOGGING_P_H +#define QLOGGING_P_H + + +#include +#include +#include +#include +#include +#include "qlogger.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE +class QFileSystemWatcher; +QT_END_NAMESPACE + +QT_LOGGER_BEGIN_NAMESPACE + +class QLogConfigFilterItem +{ +public: + QLogConfigFilterItem(const QString &category, bool active); + int pass(const QLoggingCategories::QLoggingCategory *log, const QtMsgType &type); + void parse(); + int _type; + QString _category; + bool _active; +}; + +class QLoggingPrivate : public QObject +{ + Q_OBJECT +public: + QLoggingPrivate(); + virtual ~QLoggingPrivate(); + + void setLoggingRulesFile(const QString &path); + void setLoggingRules(const QByteArray &configcontent); + bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type); + +private slots: + void fileChanged(const QString &path); + +private: + void readSettings(QIODevice &device); + void updateCategory(QLoggingCategories::QLoggingCategory *log); + +private: + QFileSystemWatcher *_configFileWatcher; + QList _registeredCategories; + QString _configFileEnvironmentVar; + QString _configFile; + QString _logFile; + QMutex _mutex; + QList _logConfigItemList; +}; + +QT_END_HEADER +QT_LOGGER_END_NAMESPACE + +#endif //QLOGGING_P_H diff --git a/src/logger/qloggerglobal.h b/src/logger/qloggerglobal.h new file mode 100644 index 0000000..f5199e3 --- /dev/null +++ b/src/logger/qloggerglobal.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the logger module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOGGERGLOBAL_H +#define QLOGGERGLOBAL_H + +#include + +#if defined(QT_NAMESPACE) +# define QT_LOGGER_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::QtLogger::name +# define QT_LOGGER_BEGIN_NAMESPACE namespace QT_NAMESPACE { namespace QtLogger { +# define QT_LOGGER_END_NAMESPACE } } +# define QT_LOGGER_USE_NAMESPACE using namespace QT_NAMESPACE; using namespace QtLogger; +#else +# define QT_LOGGER_PREPEND_NAMESPACE(name) ::QtLogger::name +# define QT_LOGGER_BEGIN_NAMESPACE namespace QtLogger { +# define QT_LOGGER_END_NAMESPACE } +# define QT_LOGGER_USE_NAMESPACE using namespace QtLogger; +#endif + +#if !defined(Q_LOGGER_EXPORT) +# if defined(QT_SHARED) +# define Q_LOGGER_EXPORT Q_DECL_EXPORT +# else +# define Q_LOGGER_EXPORT +# endif +#endif + +#define QT_LOGGER_VERSION_NAME "org.qt-project.Qt.logger.api.version" +#define QT_LOGGER_IMPLEMENTATION_VERSION_NAME "org.qt-project.Qt.logger.implementation.version" +#define QT_LOGGER_VERSION 1 + +#endif diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 0000000..8b25934 --- /dev/null +++ b/src/src.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = logger diff --git a/sync.profile b/sync.profile new file mode 100644 index 0000000..e612e90 --- /dev/null +++ b/sync.profile @@ -0,0 +1,23 @@ +%modules = ( # path to module name map + "QtLogger" => "$basedir/src/logger", +); +%moduleheaders = ( # restrict the module headers to those found in relative path +); +%classnames = ( +); +%mastercontent = ( + "logger" => "#include \n", +); +%modulepris = ( + "QtLogger" => "$basedir/modules/qt_logger.pri", +); +# Module dependencies. +# Every module that is required to build this module should have one entry. +# Each of the module version specifiers can take one of the following values: +# - A specific Git revision. +# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) +# +%dependencies = ( + "qtbase" => "refs/heads/master", +); + diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro new file mode 100644 index 0000000..8cda6e3 --- /dev/null +++ b/tests/auto/auto.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + logger diff --git a/tests/auto/logger/logger.pro b/tests/auto/logger/logger.pro new file mode 100644 index 0000000..f5ecb0e --- /dev/null +++ b/tests/auto/logger/logger.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = tst_qsensor + +CONFIG += testcase +QT = core testlib logger + +SOURCES += tst_qlogger.cpp diff --git a/tests/auto/logger/tst_qlogger.cpp b/tests/auto/logger/tst_qlogger.cpp new file mode 100644 index 0000000..5753818 --- /dev/null +++ b/tests/auto/logger/tst_qlogger.cpp @@ -0,0 +1,588 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +QT_LOG_CATEGORY(TST_LOG, "tst.log") +QT_LOG_CATEGORY(TST_LOG1, "tst.log1") +QT_LOG_CATEGORY(Nokia_Brisbane_Office_com, "Nokia.Brisbane.Office.com") +QT_LOG_CATEGORY(Nokia_Tampere_Office_com, "Nokia.Tampere.Office.com") +QT_LOG_CATEGORY(Nokia_Ulm_Office_com, "Nokia.Ulm.Office.com") + +QT_USE_NAMESPACE + +QMessageHandler oldMessageHandler; +QString logMessage; +bool multithreadtest = false; +QStringList threadtest; +QMutex threadmutex; +bool usedefaultformat = true; + +QByteArray qMyMessageFormatString(QtMsgType type, const QMessageLogContext &context, + const char *str) +{ +/* + QByteArray message; + if (!usedefaultformat) { + message.append(context.category); + message.append(": "); + 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(str); + message.append('\n'); + } else { + message.append(str); + message.append('\n'); + } +*/ + QByteArray message; + if (!usedefaultformat) { + message.append(str); + int idx = message.indexOf(":"); + switch (type) { + case QtDebugMsg: message.insert(idx + 1, "debug,"); break; + case QtWarningMsg: message.insert(idx + 1, "warning,"); break; + case QtCriticalMsg:message.insert(idx + 1, "critical,"); break; + case QtFatalMsg: message.insert(idx + 1, "fatal,"); break; + } + message.append('\n'); + } else { + message.append(str); + message.append('\n'); + } + + return message; +} + +static void myCustomMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *msg) +{ + QMutexLocker locker(&threadmutex); + logMessage = qMyMessageFormatString(type, context, msg); +// if (QLoggingCategories::isEnabled() && context.category){ + if (QLoggingCategories::isEnabled()){ + if (multithreadtest) + threadtest.append(logMessage); + } +} + +class CfgFile +{ +public: + CfgFile() + { + } + + 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 _values; + QStringList _configitemEntryOrder; +}; + +static CfgFile cfg1; +static CfgFile cfg2; + +class LogThread : public QThread +{ + Q_OBJECT + +public: + LogThread(const QString &logtext, CfgFile *cfgFile) + : _logtext(logtext), _cfgFile(cfgFile) + {} +protected: + void run() + { + for (int i = 0; i < 2000; i++){ + + _cfgFile->addKey("Nokia*", true); + QByteArray arr = _cfgFile->array(); + qSetLoggingRules(arr); + qCDebug(Nokia_Brisbane_Office_com) << "Brisbane " << _logtext << " :true"; + _cfgFile->addKey("Nokia*", false); + arr = _cfgFile->array(); + qSetLoggingRules(arr); + qCDebug(Nokia_Brisbane_Office_com) << "Brisbane " << _logtext << " :false"; + + _cfgFile->addKey("Nokia*", true); + arr = _cfgFile->array(); + qSetLoggingRules(arr); + qCDebug(Nokia_Ulm_Office_com) << "Ulm " << _logtext << " :true"; + _cfgFile->addKey("Nokia*", false); + arr = _cfgFile->array(); + qSetLoggingRules(arr); + qCDebug(Nokia_Ulm_Office_com) << "Ulm " << _logtext << " :false"; + + _cfgFile->addKey("Nokia*", true); + arr = _cfgFile->array(); + qSetLoggingRules(arr); + qCDebug(Nokia_Tampere_Office_com) << "Tampere " << _logtext << " :true"; + _cfgFile->addKey("Nokia*", false); + arr = _cfgFile->array(); + qSetLoggingRules(arr); + qCDebug(Nokia_Tampere_Office_com) << "Tampere " << _logtext << " :false"; + } + } + +public: + QString _logtext; + CfgFile *_cfgFile; +}; + +inline QString cleanLogLine(QString& qstring) +{ + QString buf = qstring.replace("../", ""); + buf = buf.replace("qlog/", ""); + QString ret; + for (int i = 0; i < buf.length(); i++) { + if (buf[i] >= '!' && buf[i] <= 'z') + ret += buf[i]; + } + return ret; +} + +//QTLOGGER_USE_NAMESPACE + +class tst_QLogger : public QObject +{ + Q_OBJECT + +private: + CfgFile *_configFile; + QStringList logEntries; + +private slots: + void initTestCase() + { + qputenv ("QT_MESSAGE_PATTERN", QString("%{category}: %{type},%{message}").toLatin1()); + oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler); + //create QLog config file + _configFile = new CfgFile(); + } + + //Check the Debug, Warning and critical without having category active. should be active. + void checkNoCategoryLogActive() + { + //check default debug + QString buf = QString::fromLatin1("Check default Debug with no log active"); + qDebug() << "Check default Debug with no log active"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //check default warning + buf = QString::fromLatin1("Check default Warning with no log active"); + qWarning() << "Check default Warning with no log active"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //check default critical + buf = QString::fromLatin1("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 = QString::fromLatin1("Check category Warning with no log active"); + buf = QString::fromLatin1("tst.log: 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 = QString::fromLatin1("Check category Critical with no log active"); + buf = QString::fromLatin1("tst.log: 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 = ""; + _configFile->addKey("tst.log", true); + qSetLoggingRules(_configFile->array()); + QString buf = QString::fromLatin1("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 + _configFile->addKey("tst.log1", true); + qSetLoggingRules(_configFile->array()); + qCDebug(TST_LOG) << "1"; + buf = QString::fromLatin1("tst.log: debug,1"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //wite out all different types + qCDebug(TST_LOG) << "DebugType"; + buf = QString::fromLatin1("tst.log: debug,DebugType"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCWarning(TST_LOG) << "WarningType"; + buf = QString::fromLatin1("tst.log: warning,WarningType"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCCritical(TST_LOG) << "CriticalType"; + buf = QString::fromLatin1("tst.log: critical,CriticalType"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + } + + void checkLegacyLogs() + { + logMessage = ""; + qDebug() << "DefaultDebug"; +// QString buf = QString::fromLatin1("default: debug,DefaultDebug"); + QString buf = QString::fromLatin1("debug,DefaultDebug"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //default Debug off by default, warning and critical are on + qWarning() << "DefaultWarning"; +// buf = QString::fromLatin1("default: warning,DefaultWarning"); + buf = QString::fromLatin1("warning,DefaultWarning"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCritical() << "DefaultCritical"; +// buf = QString::fromLatin1("default: critical,DefaultCritical"); + buf = QString::fromLatin1("critical,DefaultCritical"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //enable default debug + _configFile->addKey("default.debug", true); + qSetLoggingRules(_configFile->array()); + + qDebug() << "DefaultDebug1"; +// buf = QString::fromLatin1("default: debug,DefaultDebug1"); + buf = QString::fromLatin1("debug,DefaultDebug1"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qWarning() << "DefaultWarning1"; +// buf = QString::fromLatin1("default: warning,DefaultWarning1"); + buf = QString::fromLatin1("warning,DefaultWarning1"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCritical() << "DefaultCritical1"; +// buf = QString::fromLatin1("default: critical,DefaultCritical1"); + buf = QString::fromLatin1("critical,DefaultCritical1"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //disable qWarning + _configFile->addKey("default.warning", false); + qSetLoggingRules(_configFile->array()); + + qDebug() << "DefaultDebug2"; +// buf = QString::fromLatin1("default: debug,DefaultDebug2"); + buf = QString::fromLatin1("debug,DefaultDebug2"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + logMessage = "no change"; + qWarning() << "DefaultWarning2"; + buf = QString::fromLatin1("no change"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCritical() << "DefaultCritical2"; +// buf = QString::fromLatin1("default: critical,DefaultCritical2"); + buf = QString::fromLatin1("critical,DefaultCritical2"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //disable qCritical + _configFile->addKey("default.critical", false); + _configFile->addKey("default.debug", false); + qSetLoggingRules(_configFile->array()); + + logMessage = "no change"; + qDebug() << "DefaultDebug3"; + buf = QString::fromLatin1("no change"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qWarning() << "DefaultWarning3"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCritical() << "DefaultCritical3"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //enable default logs + _configFile->addKey("default.critical", true); + _configFile->addKey("default.warning", true); + _configFile->addKey("default.debug", true); + qSetLoggingRules(_configFile->array()); + + //ensure all are on + qDebug() << "DefaultDebug4"; +// buf = QString::fromLatin1("default: debug,DefaultDebug4"); + buf = QString::fromLatin1("debug,DefaultDebug4"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qWarning() << "DefaultWarning4"; +// buf = QString::fromLatin1("default: warning,DefaultWarning4"); + buf = QString::fromLatin1("warning,DefaultWarning4"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCritical() << "DefaultCritical4"; +// buf = QString::fromLatin1("default: critical,DefaultCritical4"); + buf = QString::fromLatin1("critical,DefaultCritical4"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //disable default log + _configFile->addKey("default", false); + qSetLoggingRules(_configFile->array()); + + //ensure all are off + logMessage = "no change"; + buf = QString::fromLatin1("no change"); + qDebug() << "DefaultDebug5"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qWarning() << "DefaultWarning5"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCritical() << "DefaultCritical5"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + } + + void checkLegacyMessageLogger() + { + usedefaultformat = true; + //This should just not crash. + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug() << "checkLegacyMessageLogger1"; + QCOMPARE(cleanLogLine(logMessage), QString("checkLegacyMessageLogger1")); + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning() << "checkLegacyMessageLogger2"; + QCOMPARE(cleanLogLine(logMessage), QString("checkLegacyMessageLogger2")); + QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical() << "checkLegacyMessageLogger3"; + QCOMPARE(cleanLogLine(logMessage), QString("checkLegacyMessageLogger3")); + } + + void checkFiltering() + { + usedefaultformat = false; + //enable default logs + _configFile->clear(); + _configFile->addKey("Nokia.Brisbane.Office.com", false); + _configFile->addKey("Nokia.Tampere.Office.com", false); + _configFile->addKey("Nokia.Ulm.Office.com", false); + _configFile->addKey("MessagePattern", QString("%{category}: %{message}")); + qSetLoggingRules(_configFile->array()); + + logMessage = "no change"; + QString buf = QString::fromLatin1("no change"); + qCDebug(Nokia_Brisbane_Office_com) << "Nokia.Brisbane.Office.com 1"; + qCDebug(Nokia_Tampere_Office_com) << "Nokia.Tampere.Office.com 1"; + qCDebug(Nokia_Ulm_Office_com) << "Nokia.Ulm.Office.com 1"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + _configFile->addKey("Nokia.Brisbane.Office.com", true); + _configFile->addKey("Nokia.Tampere.Office.com", true); + _configFile->addKey("Nokia.Ulm.Office.com", true); + qSetLoggingRules(_configFile->array()); + + qCDebug(Nokia_Brisbane_Office_com) << "Nokia.Brisbane.Office.com 2"; + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Nokia.Brisbane.Office.com 2"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCDebug(Nokia_Tampere_Office_com) << "Nokia.Tampere.Office.com 2"; + buf = QString::fromLatin1("Nokia.Tampere.Office.com: debug,Nokia.Tampere.Office.com 2"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCDebug(Nokia_Ulm_Office_com) << "Nokia.Ulm.Office.com 2"; + buf = QString::fromLatin1("Nokia.Ulm.Office.com: debug,Nokia.Ulm.Office.com 2"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //Check right filter + _configFile->addKey("Nokia.Brisbane.Office.com", false); + _configFile->addKey("Nokia.Tampere.Office.com", false); + _configFile->addKey("Nokia.Ulm.Office.com", false); + _configFile->addKey("*Office.com*", true); + qSetLoggingRules(_configFile->array()); + + qCDebug(Nokia_Brisbane_Office_com) << "Nokia.Brisbane.Office.com 3"; + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Nokia.Brisbane.Office.com 3"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCDebug(Nokia_Tampere_Office_com) << "Nokia.Tampere.Office.com 3"; + buf = QString::fromLatin1("Nokia.Tampere.Office.com: debug,Nokia.Tampere.Office.com 3"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCDebug(Nokia_Ulm_Office_com) << "Nokia.Ulm.Office.com 3"; + buf = QString::fromLatin1("Nokia.Ulm.Office.com: debug,Nokia.Ulm.Office.com 3"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //Check left filter + _configFile->addKey("*Office.com*", false); + _configFile->addKey("*Office.com.debug", true); + qSetLoggingRules(_configFile->array()); + + qCDebug(Nokia_Brisbane_Office_com) << "Debug: Nokia.Brisbane.Office.com 4"; + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Debug: Nokia.Brisbane.Office.com 4"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + logMessage = "no change"; + buf = QString::fromLatin1("no change"); + qCWarning(Nokia_Tampere_Office_com) << "Warning: Nokia.Tampere.Office.com 4"; + qCCritical(Nokia_Ulm_Office_com) << "Critical: Nokia.Ulm.Office.com 4"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //Check right filter + _configFile->addKey("*Office.com.debug", false); + _configFile->addKey("Nokia.*", true); + qSetLoggingRules(_configFile->array()); + + qCDebug(Nokia_Brisbane_Office_com) << "Debug: Nokia.Brisbane.Office.com 5"; + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Debug: Nokia.Brisbane.Office.com 5"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCWarning(Nokia_Tampere_Office_com) << "Warning: Nokia.Tampere.Office.com 5"; + buf = QString::fromLatin1("Nokia.Tampere.Office.com: warning,Warning: Nokia.Tampere.Office.com 5"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCCritical(Nokia_Ulm_Office_com) << "Critical: Nokia.Ulm.Office.com 5"; + buf = QString::fromLatin1("Nokia.Ulm.Office.com: critical,Critical: Nokia.Ulm.Office.com 5"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + //Check mid filter + _configFile->addKey("Nokia.*", false); + qSetLoggingRules(_configFile->array()); + + logMessage = "no change"; + buf = QString::fromLatin1("no change"); + qCDebug(Nokia_Brisbane_Office_com) << "Debug: Nokia.Brisbane.Office.com 6"; + qCWarning(Nokia_Tampere_Office_com) << "Warning: Nokia.Tampere.Office.com 6"; + qCCritical(Nokia_Ulm_Office_com) << "Critical: Nokia.Ulm.Office.com 6"; + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + + _configFile->addKey("*.Office.*", true); + qSetLoggingRules(_configFile->array()); + + qCDebug(Nokia_Brisbane_Office_com) << "Debug: Nokia.Brisbane.Office.com 7"; + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Debug: Nokia.Brisbane.Office.com 7"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCWarning(Nokia_Tampere_Office_com) << "Warning: Nokia.Tampere.Office.com 7"; + buf = QString::fromLatin1("Nokia.Tampere.Office.com: warning,Warning: Nokia.Tampere.Office.com 7"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + qCCritical(Nokia_Ulm_Office_com) << "Critical: Nokia.Ulm.Office.com 7"; + buf = QString::fromLatin1("Nokia.Ulm.Office.com: critical,Critical: Nokia.Ulm.Office.com 7"); + QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); + } + + void checkMultithreading() + { + multithreadtest = true; + //init two cfgconf files fone for each thread + cfg1.addKey("Nokia*", true); + cfg2.addKey("Nokia*", true); + QByteArray arr = cfg1.array(); + qSetLoggingRules(arr); + + LogThread thgread1(QString("from Thread 1"), &cfg1); + LogThread thgread2(QString("from Thread 2"), &cfg2); + //Writing out stuff from 2 different threads into the same LOG_CFG2 + thgread1.start(); + thgread2.start(); + thgread1.wait(); + thgread2.wait(); + + //Check if each log line is complete + QStringList compareagainst; + QString buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Brisbane \"from Thread 1\" :true"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Tampere.Office.com: debug,Tampere \"from Thread 1\" :true"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Ulm.Office.com: debug,Ulm \"from Thread 1\" :true"); + compareagainst.append(cleanLogLine(buf)); + + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Brisbane \"from Thread 1\" :false"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Tampere.Office.com: debug,Tampere \"from Thread 1\" :false"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Ulm.Office.com: debug,Ulm \"from Thread 1\" :false"); + compareagainst.append(cleanLogLine(buf)); + + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Brisbane \"from Thread 2\" :true"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Tampere.Office.com: debug,Tampere \"from Thread 2\" :true"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Ulm.Office.com: debug,Ulm \"from Thread 2\" :true"); + compareagainst.append(cleanLogLine(buf)); + + buf = QString::fromLatin1("Nokia.Brisbane.Office.com: debug,Brisbane \"from Thread 2\" :false"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Tampere.Office.com: debug,Tampere \"from Thread 2\" :false"); + compareagainst.append(cleanLogLine(buf)); + buf = QString::fromLatin1("Nokia.Ulm.Office.com: debug,Ulm \"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 _configFile; + qInstallMessageHandler(oldMessageHandler); + } +}; + + +QTEST_MAIN(tst_QLogger) +#include "tst_qlogger.moc" diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..157ef34 --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += auto -- cgit v1.2.3