Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
38
47
54{
55 // check message type
56 if (messageType > -1 && messageType != msgType)
57 return 0;
58
59 if (flags == FullText) {
60 // full match
61 if (category == cat)
62 return (enabled ? 1 : -1);
63 else
64 return 0;
65 }
66
67 const qsizetype idx = cat.indexOf(category);
68 if (idx >= 0) {
69 if (flags == MidFilter) {
70 // matches somewhere
71 return (enabled ? 1 : -1);
72 } else if (flags == LeftFilter) {
73 // matches left
74 if (idx == 0)
75 return (enabled ? 1 : -1);
76 } else if (flags == RightFilter) {
77 // matches right
78 if (idx == (cat.size() - category.size()))
79 return (enabled ? 1 : -1);
80 }
81 }
82 return 0;
83}
84
94void QLoggingRule::parse(QStringView pattern)
95{
97
98 // strip trailing ".messagetype"
99 if (pattern.endsWith(".debug"_L1)) {
100 p = pattern.chopped(6); // strlen(".debug")
102 } else if (pattern.endsWith(".info"_L1)) {
103 p = pattern.chopped(5); // strlen(".info")
105 } else if (pattern.endsWith(".warning"_L1)) {
106 p = pattern.chopped(8); // strlen(".warning")
108 } else if (pattern.endsWith(".critical"_L1)) {
109 p = pattern.chopped(9); // strlen(".critical")
111 } else {
112 p = pattern;
113 }
114
115 const QChar asterisk = u'*';
116 if (!p.contains(asterisk)) {
117 flags = FullText;
118 } else {
119 if (p.endsWith(asterisk)) {
120 flags |= LeftFilter;
121 p = p.chopped(1);
122 }
123 if (p.startsWith(asterisk)) {
125 p = p.mid(1);
126 }
127 if (p.contains(asterisk)) // '*' only supported at start/end
128 flags = PatternFlags();
129 }
130
131 category = p.toString();
132}
133
154{
155 _rules.clear();
156 for (auto line : qTokenize(content, u'\n'))
157 parseNextLine(line);
158}
159
165{
166 _rules.clear();
168 while (stream.readLineInto(&line))
169 parseNextLine(qToStringViewIgnoringNull(line));
170}
171
177void QLoggingSettingsParser::parseNextLine(QStringView line)
178{
179 // Remove whitespace at start and end of line:
180 line = line.trimmed();
181
182 // comment
183 if (line.startsWith(u';'))
184 return;
185
186 if (line.startsWith(u'[') && line.endsWith(u']')) {
187 // new section
188 auto sectionName = line.mid(1).chopped(1).trimmed();
189 m_inRulesSection = sectionName.compare("rules"_L1, Qt::CaseInsensitive) == 0;
190 return;
191 }
192
193 if (m_inRulesSection) {
194 const qsizetype equalPos = line.indexOf(u'=');
195 if (equalPos != -1) {
196 if (line.lastIndexOf(u'=') == equalPos) {
197 const auto key = line.left(equalPos).trimmed();
198#if QT_CONFIG(settings)
199 QString tmp;
202#else
204#endif
205 const auto valueStr = line.mid(equalPos + 1).trimmed();
206 int value = -1;
207 if (valueStr == "true"_L1)
208 value = 1;
209 else if (valueStr == "false"_L1)
210 value = 0;
212 if (rule.flags != 0 && (value != -1))
213 _rules.append(std::move(rule));
214 else
215 warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
216 } else {
217 warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
218 }
219 }
220 }
221}
222
228 : categoryFilter(defaultCategoryFilter)
229{
230#if defined(Q_OS_ANDROID)
231 // Unless QCoreApplication has been constructed we can't be sure that
232 // we are on Qt's main thread. If we did allow logging here, we would
233 // potentially set Qt's main thread to Android's thread 0, which would
234 // confuse Qt later when running main().
235 if (!qApp)
236 return;
237#endif
238
239 initializeRules(); // Init on first use
240}
241
242static bool qtLoggingDebug()
243{
244 static const bool debugEnv = [] {
245 bool debug = qEnvironmentVariableIsSet("QT_LOGGING_DEBUG");
246 if (debug)
247 debugMsg("QT_LOGGING_DEBUG environment variable is set.");
248 return debug;
249 }();
250 return debugEnv;
251}
252
253static QList<QLoggingRule> loadRulesFromFile(const QString &filePath)
254{
255 if (qtLoggingDebug()) {
256 debugMsg("Checking \"%s\" for rules",
257 QDir::toNativeSeparators(filePath).toUtf8().constData());
258 }
259
260 QFile file(filePath);
264 parser.setContent(stream);
265 if (qtLoggingDebug())
266 debugMsg("Loaded %td rules", static_cast<ptrdiff_t>(parser.rules().size()));
267 return parser.rules();
268 }
269 return QList<QLoggingRule>();
270}
271
278{
279 if (qtLoggingDebug()) {
280 debugMsg("Initializing the rules database ...");
281 debugMsg("Checking %s environment variable", "QTLOGGING_CONF");
282 }
283 QList<QLoggingRule> er, qr, cr;
284 // get rules from environment
285 const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF");
286 if (!rulesFilePath.isEmpty())
287 er = loadRulesFromFile(QFile::decodeName(rulesFilePath));
288
289 if (qtLoggingDebug())
290 debugMsg("Checking %s environment variable", "QT_LOGGING_RULES");
291
292 const QByteArray rulesSrc = qgetenv("QT_LOGGING_RULES").replace(';', '\n');
293 if (!rulesSrc.isEmpty()) {
294 QTextStream stream(rulesSrc);
296 parser.setImplicitRulesSection(true);
297 parser.setContent(stream);
298
299 if (qtLoggingDebug())
300 debugMsg("Loaded %td rules", static_cast<ptrdiff_t>(parser.rules().size()));
301
302 er += parser.rules();
303 }
304
305 const QString configFileName = QStringLiteral("qtlogging.ini");
306
307#if !defined(QT_BOOTSTRAPPED)
308 // get rules from Qt data configuration path
309 const QString qtConfigPath
311 qr = loadRulesFromFile(qtConfigPath);
312#endif
313
314 // get rules from user's/system configuration
316 QString::fromLatin1("QtProject/") + configFileName);
317 if (!envPath.isEmpty())
318 cr = loadRulesFromFile(envPath);
319
320 const QMutexLocker locker(&registryMutex);
321
322 ruleSets[EnvironmentRules] = std::move(er);
323 ruleSets[QtConfigRules] = std::move(qr);
324 ruleSets[ConfigRules] = std::move(cr);
325
326 if (!ruleSets[EnvironmentRules].isEmpty() || !ruleSets[QtConfigRules].isEmpty() || !ruleSets[ConfigRules].isEmpty())
327 updateRules();
328}
329
337{
338 const auto locker = qt_scoped_lock(registryMutex);
339
340 const auto oldSize = categories.size();
341 auto &e = categories[cat];
342 if (categories.size() != oldSize) {
343 // new entry
344 e = enableForLevel;
345 (*categoryFilter)(cat);
346 }
347}
348
354{
355 const auto locker = qt_scoped_lock(registryMutex);
356 categories.remove(cat);
357}
358
368 const char *environment)
369{
370 qtCategoryEnvironmentOverrides.insert_or_assign(categoryName, environment);
371}
372
378{
380 parser.setImplicitRulesSection(true);
381 parser.setContent(content);
382
383 if (qtLoggingDebug())
384 debugMsg("Loading logging rules set by QLoggingCategory::setFilterRules ...");
385
386 const QMutexLocker locker(&registryMutex);
387
388 ruleSets[ApiRules] = parser.rules();
389
390 updateRules();
391}
392
399void QLoggingRegistry::updateRules()
400{
401 for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it)
402 (*categoryFilter)(*it);
403}
404
411{
412 const auto locker = qt_scoped_lock(registryMutex);
413
414 if (!filter)
415 filter = defaultCategoryFilter;
416
417 QLoggingCategory::CategoryFilter old = categoryFilter;
418 categoryFilter = filter;
419
420 updateRules();
421
422 return old;
423}
424
426{
427 return qtLoggingRegistry();
428}
429
436void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
437{
439 Q_ASSERT(reg->categories.contains(cat));
440 QtMsgType enableForLevel = reg->categories.value(cat);
441
442 // NB: note that the numeric values of the Qt*Msg constants are
443 // not in severity order.
444 bool debug = (enableForLevel == QtDebugMsg);
445 bool info = debug || (enableForLevel == QtInfoMsg);
446 bool warning = info || (enableForLevel == QtWarningMsg);
447 bool critical = warning || (enableForLevel == QtCriticalMsg);
448
449 // hard-wired implementation of
450 // qt.*.debug=false
451 // qt.debug=false
452 if (const char *categoryName = cat->categoryName()) {
453 // == "qt" or startsWith("qt.")
454 if (strcmp(categoryName, "qt") == 0) {
455 debug = false;
456 } else if (strncmp(categoryName, "qt.", 3) == 0) {
457 // may be overridden
458 auto it = reg->qtCategoryEnvironmentOverrides.find(categoryName);
459 if (it == reg->qtCategoryEnvironmentOverrides.end())
460 debug = false;
461 else
463 }
464 }
465
466 const auto categoryName = QLatin1StringView(cat->categoryName());
467
468 for (const auto &ruleSet : reg->ruleSets) {
469 for (const auto &rule : ruleSet) {
470 int filterpass = rule.pass(categoryName, QtDebugMsg);
471 if (filterpass != 0)
472 debug = (filterpass > 0);
473 filterpass = rule.pass(categoryName, QtInfoMsg);
474 if (filterpass != 0)
475 info = (filterpass > 0);
476 filterpass = rule.pass(categoryName, QtWarningMsg);
477 if (filterpass != 0)
478 warning = (filterpass > 0);
479 filterpass = rule.pass(categoryName, QtCriticalMsg);
480 if (filterpass != 0)
481 critical = (filterpass > 0);
482 }
483 }
484
485 cat->setEnabled(QtDebugMsg, debug);
486 cat->setEnabled(QtInfoMsg, info);
487 cat->setEnabled(QtWarningMsg, warning);
488 cat->setEnabled(QtCriticalMsg, critical);
489}
490
491
\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:124
\inmodule QtCore
\inmodule QtCore
Definition qdir.h:20
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
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition qfile.h:162
static QString path(LibraryPath p)
qsizetype size() const noexcept
Definition qlist.h:397
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
\inmodule QtCore
void(* CategoryFilter)(QLoggingCategory *)
This is a typedef for a pointer to a function with the following signature:
void unregisterCategory(QLoggingCategory *category)
static QLoggingRegistry * instance()
Q_CORE_EXPORT void registerEnvironmentOverrideForCategory(const char *categoryName, const char *environment)
void registerCategory(QLoggingCategory *category, QtMsgType enableForLevel)
QLoggingCategory::CategoryFilter installFilter(QLoggingCategory::CategoryFilter filter)
void setApiRules(const QString &content)
int pass(QLatin1StringView categoryName, QtMsgType type) const
void setImplicitRulesSection(bool inRulesSection)
QList< QLoggingRule > rules() const
void setContent(QStringView content)
\inmodule QtCore
Definition qmutex.h:313
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
static bool iniUnescapedKey(QByteArrayView key, QString &result)
static QString locate(StandardLocation type, const QString &fileName, LocateOptions options=LocateFile)
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView chopped(qsizetype n) const noexcept
Returns the substring of length size() - length starting at the beginning of this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:296
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:5455
QString chopped(qsizetype n) const &
Definition qstring.h:398
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
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:5506
QString trimmed() const &
Definition qstring.h:447
QByteArray toUtf8() const &
Definition qstring.h:634
\inmodule QtCore
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
QDebug warning(QAnyStringView fileName, int lineNumber)
#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:165
QFile file
[0]
QHostInfo info
[0]