Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qloggingregistry.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/qfile.h>
7#include <QtCore/qlibraryinfo.h>
8#include <QtCore/private/qlocking_p.h>
9#include <QtCore/qstandardpaths.h>
10#include <QtCore/qstringtokenizer.h>
11#include <QtCore/qtextstream.h>
12#include <QtCore/qdir.h>
13#include <QtCore/qcoreapplication.h>
14
15#if QT_CONFIG(settings)
16#include <QtCore/qsettings.h>
17#include <QtCore/private/qsettings_p.h>
18#endif
19
20// We can't use the default macros because this would lead to recursion.
21// Instead let's define our own one that unconditionally logs...
22#define debugMsg QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, "qt.core.logging").debug
23#define warnMsg QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, "qt.core.logging").warning
24
26
27using namespace Qt::StringLiterals;
28
29Q_GLOBAL_STATIC(QLoggingRegistry, qtLoggingRegistry)
30
31
37{
38}
39
45 messageType(-1),
47{
48 parse(pattern);
49}
50
57{
58 // check message type
59 if (messageType > -1 && messageType != msgType)
60 return 0;
61
62 if (flags == FullText) {
63 // full match
64 if (category == cat)
65 return (enabled ? 1 : -1);
66 else
67 return 0;
68 }
69
70 const qsizetype idx = cat.indexOf(category);
71 if (idx >= 0) {
72 if (flags == MidFilter) {
73 // matches somewhere
74 return (enabled ? 1 : -1);
75 } else if (flags == LeftFilter) {
76 // matches left
77 if (idx == 0)
78 return (enabled ? 1 : -1);
79 } else if (flags == RightFilter) {
80 // matches right
81 if (idx == (cat.size() - category.size()))
82 return (enabled ? 1 : -1);
83 }
84 }
85 return 0;
86}
87
97void QLoggingRule::parse(QStringView pattern)
98{
100
101 // strip trailing ".messagetype"
102 if (pattern.endsWith(".debug"_L1)) {
103 p = pattern.chopped(6); // strlen(".debug")
105 } else if (pattern.endsWith(".info"_L1)) {
106 p = pattern.chopped(5); // strlen(".info")
108 } else if (pattern.endsWith(".warning"_L1)) {
109 p = pattern.chopped(8); // strlen(".warning")
111 } else if (pattern.endsWith(".critical"_L1)) {
112 p = pattern.chopped(9); // strlen(".critical")
114 } else {
115 p = pattern;
116 }
117
118 const QChar asterisk = u'*';
119 if (!p.contains(asterisk)) {
120 flags = FullText;
121 } else {
122 if (p.endsWith(asterisk)) {
123 flags |= LeftFilter;
124 p = p.chopped(1);
125 }
126 if (p.startsWith(asterisk)) {
128 p = p.mid(1);
129 }
130 if (p.contains(asterisk)) // '*' only supported at start/end
131 flags = PatternFlags();
132 }
133
134 category = p.toString();
135}
136
157{
158 _rules.clear();
159 for (auto line : qTokenize(content, u'\n'))
160 parseNextLine(line);
161}
162
168{
169 _rules.clear();
171 while (stream.readLineInto(&line))
172 parseNextLine(qToStringViewIgnoringNull(line));
173}
174
180void QLoggingSettingsParser::parseNextLine(QStringView line)
181{
182 // Remove whitespace at start and end of line:
183 line = line.trimmed();
184
185 // comment
186 if (line.startsWith(u';'))
187 return;
188
189 if (line.startsWith(u'[') && line.endsWith(u']')) {
190 // new section
191 auto sectionName = line.mid(1).chopped(1).trimmed();
192 m_inRulesSection = sectionName.compare("rules"_L1, Qt::CaseInsensitive) == 0;
193 return;
194 }
195
196 if (m_inRulesSection) {
197 const qsizetype equalPos = line.indexOf(u'=');
198 if (equalPos != -1) {
199 if (line.lastIndexOf(u'=') == equalPos) {
200 const auto key = line.left(equalPos).trimmed();
201#if QT_CONFIG(settings)
202 QString tmp;
205#else
207#endif
208 const auto valueStr = line.mid(equalPos + 1).trimmed();
209 int value = -1;
210 if (valueStr == "true"_L1)
211 value = 1;
212 else if (valueStr == "false"_L1)
213 value = 0;
215 if (rule.flags != 0 && (value != -1))
216 _rules.append(std::move(rule));
217 else
218 warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
219 } else {
220 warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
221 }
222 }
223 }
224}
225
231 : categoryFilter(defaultCategoryFilter)
232{
233#if defined(Q_OS_ANDROID)
234 // Unless QCoreApplication has been constructed we can't be sure that
235 // we are on Qt's main thread. If we did allow logging here, we would
236 // potentially set Qt's main thread to Android's thread 0, which would
237 // confuse Qt later when running main().
238 if (!qApp)
239 return;
240#endif
241
242 initializeRules(); // Init on first use
243}
244
245static bool qtLoggingDebug()
246{
247 static const bool debugEnv = qEnvironmentVariableIsSet("QT_LOGGING_DEBUG");
248 return debugEnv;
249}
250
252{
253 QFile file(filePath);
255 if (qtLoggingDebug())
256 debugMsg("Loading \"%s\" ...",
260 parser.setContent(stream);
261 return parser.rules();
262 }
263 return QList<QLoggingRule>();
264}
265
272{
273 QList<QLoggingRule> er, qr, cr;
274 // get rules from environment
275 const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF");
276 if (!rulesFilePath.isEmpty())
277 er = loadRulesFromFile(QFile::decodeName(rulesFilePath));
278
279 const QByteArray rulesSrc = qgetenv("QT_LOGGING_RULES").replace(';', '\n');
280 if (!rulesSrc.isEmpty()) {
281 QTextStream stream(rulesSrc);
283 parser.setImplicitRulesSection(true);
284 parser.setContent(stream);
285 er += parser.rules();
286 }
287
288 const QString configFileName = QStringLiteral("qtlogging.ini");
289
290#if !defined(QT_BOOTSTRAPPED)
291 // get rules from Qt data configuration path
292 const QString qtConfigPath
294 qr = loadRulesFromFile(qtConfigPath);
295#endif
296
297 // get rules from user's/system configuration
299 QString::fromLatin1("QtProject/") + configFileName);
300 if (!envPath.isEmpty())
301 cr = loadRulesFromFile(envPath);
302
303 const QMutexLocker locker(&registryMutex);
304
305 ruleSets[EnvironmentRules] = std::move(er);
306 ruleSets[QtConfigRules] = std::move(qr);
307 ruleSets[ConfigRules] = std::move(cr);
308
309 if (!ruleSets[EnvironmentRules].isEmpty() || !ruleSets[QtConfigRules].isEmpty() || !ruleSets[ConfigRules].isEmpty())
310 updateRules();
311}
312
320{
321 const auto locker = qt_scoped_lock(registryMutex);
322
323 const auto oldSize = categories.size();
324 auto &e = categories[cat];
325 if (categories.size() != oldSize) {
326 // new entry
327 e = enableForLevel;
328 (*categoryFilter)(cat);
329 }
330}
331
337{
338 const auto locker = qt_scoped_lock(registryMutex);
339 categories.remove(cat);
340}
341
351 QByteArrayView environment)
352{
353 qtCategoryEnvironmentOverrides.insert(categoryName, environment);
354}
355
361{
363 parser.setImplicitRulesSection(true);
364 parser.setContent(content);
365
366 if (qtLoggingDebug())
367 debugMsg("Loading logging rules set by QLoggingCategory::setFilterRules ...");
368
369 const QMutexLocker locker(&registryMutex);
370
371 ruleSets[ApiRules] = parser.rules();
372
373 updateRules();
374}
375
382void QLoggingRegistry::updateRules()
383{
384 for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it)
385 (*categoryFilter)(*it);
386}
387
394{
395 const auto locker = qt_scoped_lock(registryMutex);
396
397 if (!filter)
398 filter = defaultCategoryFilter;
399
400 QLoggingCategory::CategoryFilter old = categoryFilter;
401 categoryFilter = filter;
402
403 updateRules();
404
405 return old;
406}
407
409{
410 return qtLoggingRegistry();
411}
412
419void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
420{
422 Q_ASSERT(reg->categories.contains(cat));
423 QtMsgType enableForLevel = reg->categories.value(cat);
424
425 // NB: note that the numeric values of the Qt*Msg constants are
426 // not in severity order.
427 bool debug = (enableForLevel == QtDebugMsg);
428 bool info = debug || (enableForLevel == QtInfoMsg);
429 bool warning = info || (enableForLevel == QtWarningMsg);
430 bool critical = warning || (enableForLevel == QtCriticalMsg);
431
432 // hard-wired implementation of
433 // qt.*.debug=false
434 // qt.debug=false
435 if (const char *categoryName = cat->categoryName()) {
436 // == "qt" or startsWith("qt.")
437 if (strcmp(categoryName, "qt") == 0) {
438 debug = false;
439 } else if (strncmp(categoryName, "qt.", 3) == 0) {
440 // may be overridden
441 auto it = reg->qtCategoryEnvironmentOverrides.find(categoryName);
442 if (it == reg->qtCategoryEnvironmentOverrides.end())
443 debug = false;
444 else
445 debug = qEnvironmentVariableIntValue(it.value().data());
446 }
447 }
448
449 const auto categoryName = QLatin1StringView(cat->categoryName());
450
451 for (const auto &ruleSet : reg->ruleSets) {
452 for (const auto &rule : ruleSet) {
453 int filterpass = rule.pass(categoryName, QtDebugMsg);
454 if (filterpass != 0)
455 debug = (filterpass > 0);
456 filterpass = rule.pass(categoryName, QtInfoMsg);
457 if (filterpass != 0)
458 info = (filterpass > 0);
459 filterpass = rule.pass(categoryName, QtWarningMsg);
460 if (filterpass != 0)
461 warning = (filterpass > 0);
462 filterpass = rule.pass(categoryName, QtCriticalMsg);
463 if (filterpass != 0)
464 critical = (filterpass > 0);
465 }
466 }
467
470 cat->setEnabled(QtWarningMsg, warning);
471 cat->setEnabled(QtCriticalMsg, critical);
472}
473
474
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
QByteArray & replace(qsizetype index, qsizetype len, const char *s, qsizetype alen)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:275
\inmodule QtCore
Definition qchar.h:48
\inmodule QtCore
Definition qdir.h:19
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
QString absoluteFilePath(const QString &fileName) const
Returns the absolute path name of a file in the directory.
Definition qdir.cpp:809
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
QString fileName() const override
Returns the name set by setFileName() or to the QFile constructors.
Definition qfile.cpp:277
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition qfile.h:162
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
T value(const Key &key) const noexcept
Definition qhash.h:1044
constexpr qsizetype size() const noexcept
qsizetype indexOf(QStringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
static QString path(LibraryPath p)
Definition qlist.h:74
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
\inmodule QtCore
void(* CategoryFilter)(QLoggingCategory *)
This is a typedef for a pointer to a function with the following signature:
void setEnabled(QtMsgType type, bool enable)
Changes the message type type for the category to enable.
const char * categoryName() const
Returns the name of the category.
void unregisterCategory(QLoggingCategory *category)
static QLoggingRegistry * instance()
void registerCategory(QLoggingCategory *category, QtMsgType enableForLevel)
QLoggingCategory::CategoryFilter installFilter(QLoggingCategory::CategoryFilter filter)
Q_CORE_EXPORT void registerEnvironmentOverrideForCategory(QByteArrayView categoryName, QByteArrayView environment)
void setApiRules(const QString &content)
int pass(QLatin1StringView categoryName, QtMsgType type) const
void setImplicitRulesSection(bool inRulesSection)
QList< QLoggingRule > rules() const
void setContent(QStringView content)
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
iterator find(const Key &key)
Definition qmap.h:640
iterator end()
Definition qmap.h:601
\inmodule QtCore
Definition qmutex.h:317
static bool iniUnescapedKey(QByteArrayView key, QString &result)
static QString locate(StandardLocation type, const QString &fileName, LocateOptions options=LocateFile)
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString trimmed() const &
Definition qstring.h:380
QString chopped(qsizetype n) const
Definition qstring.h:345
QByteArray toUtf8() const &
Definition qstring.h:563
\inmodule QtCore
double e
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ CaseInsensitive
#define qApp
DBusConnection const char * rule
EGLStreamKHR stream
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
QtMsgType
Definition qlogging.h:29
@ QtCriticalMsg
Definition qlogging.h:32
@ QtInfoMsg
Definition qlogging.h:34
@ QtWarningMsg
Definition qlogging.h:31
@ QtDebugMsg
Definition qlogging.h:30
static QList< QLoggingRule > loadRulesFromFile(const QString &filePath)
static bool qtLoggingDebug()
#define warnMsg
#define debugMsg
GLuint64 key
GLuint GLuint end
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbitfield flags
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLsizei GLenum * categories
GLfloat GLfloat p
[1]
GLubyte * pattern
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
constexpr auto qTokenize(Haystack &&h, Needle &&n, Flags...flags) noexcept(QtPrivate::Tok::is_nothrow_constructible_from< Haystack, Needle >::value) -> decltype(QtPrivate::Tok::TokenizerResult< Haystack, Needle >{std::forward< Haystack >(h), std::forward< Needle >(n), flags...})
QStringView qToStringViewIgnoringNull(const QStringLike &s) noexcept
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
ptrdiff_t qsizetype
Definition qtypes.h:70
QFile file
[0]
QFileInfo info(fileName)
[8]