diff options
author | Kai Koehne <kai.koehne@digia.com> | 2014-02-04 16:35:26 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-02-11 20:59:15 +0100 |
commit | a2bfd114938e1fdd5067f2dac812a8d3a5d89fd3 (patch) | |
tree | 3a0341ab6973bc827c7e2c0f4787f23820d7adb3 /src/corelib/io | |
parent | dc09a02e3a4ea93388197d7f8a0cfebe194e9886 (diff) |
Allow configuration of logging rules from file system
Allow configuration of logging rules from outside of the application,
either through a configuration file (.config/QtProject/qtlogging.ini),
or through a file specified by a QT_LOGGING_CONF environment
variable.
The logging rules from the different sources are concatenated: First
the rules from QtProject/qtlogging.ini are applied, then
QLoggingCategory::setLoggingRules(), finally from the environment.
This allows an application to overwrite/augment the system wide rules,
and in turn that can be tailored for a specific run by setting a
configuration in the environment variable.
[ChangeLog][QtCore][Logging] The logging framework can now be configured
with an .ini file.
Change-Id: I442efde1b7e0a2ebe135c6f6e0a4b656483fe4b1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/qloggingcategory.cpp | 73 | ||||
-rw-r--r-- | src/corelib/io/qloggingregistry.cpp | 129 | ||||
-rw-r--r-- | src/corelib/io/qloggingregistry_p.h | 36 |
3 files changed, 181 insertions, 57 deletions
diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index 5fa346dce5..168087659f 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -86,12 +86,62 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory, In the default configuration \l isWarningEnabled() , \l isDebugEnabled() and \l isCriticalEnabled() will return \c true. - \section1 Changing the configuration of a category + \section1 Configuring Categories - Use either \l setFilterRules() or \l installFilter() to - configure categories, for example + Categories can be centrally configured by either setting logging rules, + or by installing a custom filter. - \snippet qloggingcategory/main.cpp 2 + \section2 Logging Rules + + Logging rules allow to enable or disable logging for categories in a flexible + way. Rules are specified in text, where every line must have the format + + \code + <category>[.<type>] = true|false + \endcode + + \c <category> is the name of the category, potentially with \c{*} as a + wildcard symbol as the first or last character (or at both positions). + The optional \c <type> must be either \c debug, \c warning, or \c critical. + Lines that do not fit to his scheme are ignored. + + Rules are evaluated in text order, from first to last. That is, if two rules + apply to a category/type, the rule that comes later is applied. + + Rules can be set via \l setFilterRules(). Since Qt 5.3 logging rules + are also automatically loaded from the \c [rules] section of a logging + configuration file. Such configuration files are looked up in the QtProject + configuration directory, or explicitly set in a \c QT_LOGGING_CONF + environment variable. + + Rules set by \l setFilterRules() take precedence over rules specified + in the QtProject configuration directory, and can, in turn, be + overwritten by rules from the configuration file specified by + \c QT_LOGGING_CONF. + + Order of evaluation: + \list + \li Rules from QtProject/qlogging.ini + \li Rules set by \l setFilterRules() + \li Rules from file in \c QT_LOGGING_CONF + \endlist + + The \c QtProject/qlogging.ini file is looked up in all directories returned + by QStandardPaths::GenericConfigLocation, e.g. + + \list + \li on Mac OS X: \c ~/Library/Preferences + \li on Unix: \c ~/.config, \c /etc/xdg + \li on Windows: \c %LOCALAPPDATA%, \c %ProgramData%, + \l QCoreApplication::applicationDirPath(), + QCoreApplication::applicationDirPath() + \c "/data" + \endlist + + \section2 Installing a Custom Filter + + As a lower-level alternative to the text rules you can also implement a + custom filter via \l installFilter(). All filter rules are ignored in this + case. \section1 Printing the category @@ -278,27 +328,18 @@ QLoggingCategory::installFilter(QLoggingCategory::CategoryFilter 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. - Example: \snippet qloggingcategory/main.cpp 2 \note The rules might be ignored if a custom category filter is installed - with \l installFilter(). + with \l installFilter(), or if the user defined a custom logging + configuration file in the \c QT_LOGGING_CONF environment variable. */ void QLoggingCategory::setFilterRules(const QString &rules) { - QLoggingRegistry::instance()->rulesParser.setRules(rules); + QLoggingRegistry::instance()->setApiRules(rules); } /*! diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index fd25ff697e..b8fef16c0e 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -42,6 +42,10 @@ #include "qloggingregistry_p.h" #include "qloggingcategory_p.h" +#include <QtCore/qfile.h> +#include <QtCore/qstandardpaths.h> +#include <QtCore/qtextstream.h> + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QLoggingRegistry, qtLoggingRegistry) @@ -150,33 +154,38 @@ void QLoggingRule::parse() } /*! + \class QLoggingSettingsParser + \since 5.3 \internal - Creates a new QLoggingRules object. + + Parses a .ini file with the following format: + + [rules] + rule1=[true|false] + rule2=[true|false] + ... + + [rules] is the default section, and therefore optional. */ -QLoggingRulesParser::QLoggingRulesParser(QLoggingRegistry *registry) : - registry(registry) -{ -} /*! \internal - Sets logging rules string. + Parses configuration from \a content. */ -void QLoggingRulesParser::setRules(const QString &content) +void QLoggingSettingsParser::setContent(const QString &content) { QString content_ = content; QTextStream stream(&content_, QIODevice::ReadOnly); - parseRules(stream); + setContent(stream); } /*! \internal - Parses rules out of a QTextStream. + Parses configuration from \a stream. */ -void QLoggingRulesParser::parseRules(QTextStream &stream) +void QLoggingSettingsParser::setContent(QTextStream &stream) { - QVector<QLoggingRule> rules; - + _rules.clear(); while (!stream.atEnd()) { QString line = stream.readLine(); @@ -184,31 +193,79 @@ void QLoggingRulesParser::parseRules(QTextStream &stream) 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)); + // comment + if (line.startsWith(QLatin1Char(';'))) + continue; + + if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) { + // new section + _section = line.mid(1, line.size() - 2); + continue; } - } - registry->setRules(rules); + if (_section == QLatin1String("rules")) { + int equalPos = line.indexOf(QLatin1Char('=')); + if ((equalPos != -1) + && (line.lastIndexOf(QLatin1Char('=')) == equalPos)) { + const QString pattern = line.left(equalPos); + const QStringRef value = line.midRef(equalPos + 1); + bool enabled = (value.compare(QLatin1String("true"), + Qt::CaseInsensitive) == 0); + _rules.append(QLoggingRule(pattern, enabled)); + } + } + } } /*! \internal - QLoggingPrivate constructor + QLoggingRegistry constructor */ QLoggingRegistry::QLoggingRegistry() - : rulesParser(this), - categoryFilter(defaultCategoryFilter) + : categoryFilter(defaultCategoryFilter) { } /*! \internal + Initializes the rules database by loading + .config/QtProject/qtlogging.ini and $QT_LOGGING_CONF. + */ +void QLoggingRegistry::init() +{ + // get rules from environment + const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF"); + if (!rulesFilePath.isEmpty()) { + QFile file(QFile::decodeName(rulesFilePath)); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream stream(&file); + QLoggingSettingsParser parser; + parser.setContent(stream); + envRules = parser.rules(); + } + } + + // get rules from qt configuration + QString envPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, + QStringLiteral("QtProject/qtlogging.ini")); + if (!envPath.isEmpty()) { + QFile file(envPath); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream stream(&file); + QLoggingSettingsParser parser; + parser.setContent(stream); + configRules = parser.rules(); + } + } + + if (!envRules.isEmpty() || !configRules.isEmpty()) { + QMutexLocker locker(®istryMutex); + updateRules(); + } +} + +/*! + \internal Registers a category object. This method might be called concurrently for the same category object. @@ -236,17 +293,33 @@ void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat) /*! \internal - Activates a new set of logging rules for the default filter. -*/ -void QLoggingRegistry::setRules(const QVector<QLoggingRule> &rules_) + Installs logging rules as specified in \a content. + */ +void QLoggingRegistry::setApiRules(const QString &content) { + QLoggingSettingsParser parser; + parser.setSection(QStringLiteral("rules")); + parser.setContent(content); + QMutexLocker locker(®istryMutex); + apiRules = parser.rules(); - rules = rules_; + updateRules(); +} +/*! + \internal + Activates a new set of logging rules for the default filter. + + (The caller must lock registryMutex to make sure the API is thread safe.) +*/ +void QLoggingRegistry::updateRules() +{ if (categoryFilter != defaultCategoryFilter) return; + rules = configRules + apiRules + envRules; + foreach (QLoggingCategory *cat, categories) (*categoryFilter)(cat); } diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h index cbf7aecc4f..d4b97d42b8 100644 --- a/src/corelib/io/qloggingregistry_p.h +++ b/src/corelib/io/qloggingregistry_p.h @@ -60,6 +60,8 @@ #include <QtCore/qtextstream.h> #include <QtCore/qvector.h> +class tst_QLoggingRegistry; + QT_BEGIN_NAMESPACE class QLoggingRule @@ -89,45 +91,53 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(QLoggingRule::PatternFlags) Q_DECLARE_TYPEINFO(QLoggingRule, Q_MOVABLE_TYPE); -class QLoggingRulesParser +class Q_AUTOTEST_EXPORT QLoggingSettingsParser { -private: - explicit QLoggingRulesParser(class QLoggingRegistry *logging); - public: - void setRules(const QString &content); + void setSection(const QString §ion) { _section = section; } -private: - void parseRules(QTextStream &stream); - QLoggingRegistry *registry; + void setContent(const QString &content); + void setContent(QTextStream &stream); + + QVector<QLoggingRule> rules() const { return _rules; } - friend class QLoggingRegistry; +private: + QString _section; + QVector<QLoggingRule> _rules; }; -class QLoggingRegistry +class Q_AUTOTEST_EXPORT QLoggingRegistry { public: QLoggingRegistry(); + void init(); + void registerCategory(QLoggingCategory *category); void unregisterCategory(QLoggingCategory *category); - void setRules(const QVector<QLoggingRule> &rules); + void setApiRules(const QString &content); QLoggingCategory::CategoryFilter installFilter(QLoggingCategory::CategoryFilter filter); static QLoggingRegistry *instance(); - QLoggingRulesParser rulesParser; - private: + void updateRules(); + static void defaultCategoryFilter(QLoggingCategory *category); QMutex registryMutex; + + QVector<QLoggingRule> configRules; + QVector<QLoggingRule> envRules; + QVector<QLoggingRule> apiRules; QVector<QLoggingRule> rules; QList<QLoggingCategory*> categories; QLoggingCategory::CategoryFilter categoryFilter; + + friend class ::tst_QLoggingRegistry; }; QT_END_NAMESPACE |