13#include "private/qcoreapplication_p.h"
17#include "private/qlocking_p.h"
19#include "private/qloggingregistry_p.h"
23#include "qtcore_tracepoints_p.h"
38#include <android/log.h>
42#include <QtCore/private/qohoslogger_p.h>
46#include <QtCore/private/qcore_mac_p.h>
49#if QT_CONFIG(journald)
50# define SD_JOURNAL_SUPPRESS_LOCATION
51# include <systemd/sd-journal.h>
58# include <sys/types.h>
61# include "private/qcore_unix_p.h"
65#include <emscripten/emscripten.h>
72#ifdef QLOGGING_HAVE_BACKTRACE
73# include <qregularexpression.h>
76#ifdef QLOGGING_USE_EXECINFO_BACKTRACE
80# include BACKTRACE_HEADER
93#include <qt_windows.h>
94#include <processthreadsapi.h>
99using namespace Qt::StringLiterals;
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
135template <
typename String>
139 const QString &formattedMessage);
152 int value = str.toInt(&ok, 0);
153 return (ok && value >= 0) ? value : 1;
158 static const int Uninitialized = 0;
159 static const int NeverFatal = 1;
160 static const int ImmediatelyFatal = 2;
162 int v = n.loadRelaxed();
163 if (v == Uninitialized) {
167 if (env == NeverFatal) {
169 n.storeRelaxed(NeverFatal);
171 }
else if (env == ImmediatelyFatal) {
173 }
else if (n.testAndSetRelaxed(Uninitialized, env - 1, v)) {
180 while (v > ImmediatelyFatal && !n.testAndSetRelaxed(v, v - 1, v))
185 return v == ImmediatelyFatal;
188Q_CONSTINIT
static QBasicAtomicInt fatalCriticalsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
189Q_CONSTINIT
static QBasicAtomicInt fatalWarningsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
197 return isFatalCountDown(
"QT_FATAL_CRITICALS", fatalCriticalsCount);
200 return isFatalCountDown(
"QT_FATAL_WARNINGS", fatalWarningsCount);
210#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
211static bool qt_append_thread_name_to(QString &message)
213 std::array<
char, 16> name{};
214 if (pthread_getname_np(pthread_self(), name.data(), name.size()) == 0) {
215 QUtf8StringView threadName(name.data());
216 if (!threadName.isEmpty()) {
217 message.append(threadName);
223#elif defined(Q_OS_WIN)
224static bool qt_append_thread_name_to(QString &message)
226 PWSTR description =
nullptr;
227 HRESULT hr = GetThreadDescription(GetCurrentThread(), &description);
228 std::unique_ptr<WCHAR,
decltype(&LocalFree)> descriptionOwner(description, &LocalFree);
230 QStringView threadName(description);
231 if (!threadName.isEmpty()) {
232 message.append(threadName);
249
250
251
252
253
256#if defined(Q_OS_HARMONY)
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
285 static const bool stderrHasConsoleAttached = []() ->
bool {
289 if (qEnvironmentVariableIntValue(
"QT_ASSUME_STDERR_HAS_CONSOLE"))
293 return GetConsoleWindow();
294#elif defined(Q_OS_UNIX)
296# define _PATH_TTY "/dev/tty"
301 if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
302 qt_safe_close(ttyDevice);
304 }
else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
306 return isatty(STDERR_FILENO);
315 return stderrHasConsoleAttached;
322
323
324
325
326
327
328
329
332 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
344
345
346
347
348
349
350
351
352
353
354
355
356
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
377#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
378static inline void convert_to_wchar_t_elided(
wchar_t *d, size_t space,
const char *s)
noexcept
380 size_t len = qstrlen(s);
381 if (len + 1 > space) {
382 const size_t skip = len - space + 4;
385 for (
int i = 0; i < 3; ++i)
395
396
400 QString buf = QString::vasprintf(msg, ap);
401 qt_message_print(msgType, context, buf);
402 qt_maybe_message_fatal(msgType, context, buf);
406
407
408
409
410
411void QMessageLogger::debug(
const char *msg, ...)
const
413 QInternalMessageLogContext ctxt(context);
416 qt_message(QtDebugMsg, ctxt, msg, ap);
421
422
423
424
425
426
427void QMessageLogger::info(
const char *msg, ...)
const
429 QInternalMessageLogContext ctxt(context);
432 qt_message(QtInfoMsg, ctxt, msg, ap);
437
438
439
440
441
442
443
444
445
446
447
448
449
450
453
454
455
456
457
458
459void QMessageLogger::debug(
const QLoggingCategory &cat,
const char *msg, ...)
const
461 if (!cat.isDebugEnabled())
464 QInternalMessageLogContext ctxt(context, cat());
468 qt_message(QtDebugMsg, ctxt, msg, ap);
473
474
475
476
477
478
479void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
480 const char *msg, ...)
const
482 const QLoggingCategory &cat = (*catFunc)();
483 if (!cat.isDebugEnabled())
486 QInternalMessageLogContext ctxt(context, cat());
490 qt_message(QtDebugMsg, ctxt, msg, ap);
494#ifndef QT_NO_DEBUG_STREAM
497
498
499
500
501QDebug QMessageLogger::debug()
const
503 QDebug dbg = QDebug(QtDebugMsg);
504 QMessageLogContext &ctxt = dbg.stream->context;
505 ctxt.copyContextFrom(context);
510
511
512
513
514
515QDebug QMessageLogger::debug(
const QLoggingCategory &cat)
const
517 QDebug dbg = QDebug(QtDebugMsg);
518 if (!cat.isDebugEnabled())
519 dbg.stream->message_output =
false;
521 QMessageLogContext &ctxt = dbg.stream->context;
522 ctxt.copyContextFrom(context);
523 ctxt.category = cat.categoryName();
529
530
531
532
533
534QDebug QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc)
const
536 return debug((*catFunc)());
541
542
543
544
545
546
547void QMessageLogger::info(
const QLoggingCategory &cat,
const char *msg, ...)
const
549 if (!cat.isInfoEnabled())
552 QInternalMessageLogContext ctxt(context, cat());
556 qt_message(QtInfoMsg, ctxt, msg, ap);
561
562
563
564
565
566
567void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
568 const char *msg, ...)
const
570 const QLoggingCategory &cat = (*catFunc)();
571 if (!cat.isInfoEnabled())
574 QInternalMessageLogContext ctxt(context, cat());
578 qt_message(QtInfoMsg, ctxt, msg, ap);
582#ifndef QT_NO_DEBUG_STREAM
585
586
587
588
589
590QDebug QMessageLogger::info()
const
592 QDebug dbg = QDebug(QtInfoMsg);
593 QMessageLogContext &ctxt = dbg.stream->context;
594 ctxt.copyContextFrom(context);
599
600
601
602
603
604QDebug QMessageLogger::info(
const QLoggingCategory &cat)
const
606 QDebug dbg = QDebug(QtInfoMsg);
607 if (!cat.isInfoEnabled())
608 dbg.stream->message_output =
false;
610 QMessageLogContext &ctxt = dbg.stream->context;
611 ctxt.copyContextFrom(context);
612 ctxt.category = cat.categoryName();
618
619
620
621
622
623QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc)
const
625 return info((*catFunc)());
631
632
633
634
635
636void QMessageLogger::warning(
const char *msg, ...)
const
638 QInternalMessageLogContext ctxt(context);
641 qt_message(QtWarningMsg, ctxt, msg, ap);
646
647
648
649
650
651
652void QMessageLogger::warning(
const QLoggingCategory &cat,
const char *msg, ...)
const
654 if (!cat.isWarningEnabled())
657 QInternalMessageLogContext ctxt(context, cat());
661 qt_message(QtWarningMsg, ctxt, msg, ap);
666
667
668
669
670
671
672void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
673 const char *msg, ...)
const
675 const QLoggingCategory &cat = (*catFunc)();
676 if (!cat.isWarningEnabled())
679 QInternalMessageLogContext ctxt(context, cat());
683 qt_message(QtWarningMsg, ctxt, msg, ap);
687#ifndef QT_NO_DEBUG_STREAM
689
690
691
692
693QDebug QMessageLogger::warning()
const
695 QDebug dbg = QDebug(QtWarningMsg);
696 QMessageLogContext &ctxt = dbg.stream->context;
697 ctxt.copyContextFrom(context);
702
703
704
705
706QDebug QMessageLogger::warning(
const QLoggingCategory &cat)
const
708 QDebug dbg = QDebug(QtWarningMsg);
709 if (!cat.isWarningEnabled())
710 dbg.stream->message_output =
false;
712 QMessageLogContext &ctxt = dbg.stream->context;
713 ctxt.copyContextFrom(context);
714 ctxt.category = cat.categoryName();
720
721
722
723
724
725QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc)
const
727 return warning((*catFunc)());
733
734
735
736
737
738void QMessageLogger::critical(
const char *msg, ...)
const
740 QInternalMessageLogContext ctxt(context);
743 qt_message(QtCriticalMsg, ctxt, msg, ap);
748
749
750
751
752
753
754void QMessageLogger::critical(
const QLoggingCategory &cat,
const char *msg, ...)
const
756 if (!cat.isCriticalEnabled())
759 QInternalMessageLogContext ctxt(context, cat());
763 qt_message(QtCriticalMsg, ctxt, msg, ap);
768
769
770
771
772
773
774void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
775 const char *msg, ...)
const
777 const QLoggingCategory &cat = (*catFunc)();
778 if (!cat.isCriticalEnabled())
781 QInternalMessageLogContext ctxt(context, cat());
785 qt_message(QtCriticalMsg, ctxt, msg, ap);
789#ifndef QT_NO_DEBUG_STREAM
791
792
793
794
795QDebug QMessageLogger::critical()
const
797 QDebug dbg = QDebug(QtCriticalMsg);
798 QMessageLogContext &ctxt = dbg.stream->context;
799 ctxt.copyContextFrom(context);
804
805
806
807
808
809QDebug QMessageLogger::critical(
const QLoggingCategory &cat)
const
811 QDebug dbg = QDebug(QtCriticalMsg);
812 if (!cat.isCriticalEnabled())
813 dbg.stream->message_output =
false;
815 QMessageLogContext &ctxt = dbg.stream->context;
816 ctxt.copyContextFrom(context);
817 ctxt.category = cat.categoryName();
823
824
825
826
827
828QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc)
const
830 return critical((*catFunc)());
836
837
838
839
840
841
842void QMessageLogger::fatal(
const QLoggingCategory &cat,
const char *msg, ...)
const noexcept
844 QInternalMessageLogContext ctxt(context, cat());
848 qt_message(QtFatalMsg, ctxt, msg, ap);
851#ifndef Q_CC_MSVC_ONLY
857
858
859
860
861
862
863void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
864 const char *msg, ...)
const noexcept
866 const QLoggingCategory &cat = (*catFunc)();
868 QInternalMessageLogContext ctxt(context, cat());
872 qt_message(QtFatalMsg, ctxt, msg, ap);
875#ifndef Q_CC_MSVC_ONLY
881
882
883
884
885
886void QMessageLogger::fatal(
const char *msg, ...)
const noexcept
888 QInternalMessageLogContext ctxt(context);
891 qt_message(QtFatalMsg, ctxt, msg, ap);
894#ifndef Q_CC_MSVC_ONLY
899#ifndef QT_NO_DEBUG_STREAM
901
902
903
904
905
906
907QDebug QMessageLogger::fatal()
const
909 QDebug dbg = QDebug(QtFatalMsg);
910 QMessageLogContext &ctxt = dbg.stream->context;
911 ctxt.copyContextFrom(context);
916
917
918
919
920
921QDebug QMessageLogger::fatal(
const QLoggingCategory &cat)
const
923 QDebug dbg = QDebug(QtFatalMsg);
925 QMessageLogContext &ctxt = dbg.stream->context;
926 ctxt.copyContextFrom(context);
927 ctxt.category = cat.categoryName();
933
934
935
936
937
938QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc)
const
940 return fatal((*catFunc)());
946 return !category || strcmp(category, QLoggingRegistry::defaultCategoryName) == 0;
950
951
965 pos = info.size() - 1;
966 if (info.endsWith(
']') && !(info.startsWith(
'+') || info.startsWith(
'-'))) {
968 if (info.at(pos) ==
'[') {
973 if (info.endsWith(
' ')) {
979 static const char operator_call[] =
"operator()";
980 static const char operator_lessThan[] =
"operator<";
981 static const char operator_greaterThan[] =
"operator>";
982 static const char operator_lessThanEqual[] =
"operator<=";
983 static const char operator_greaterThanEqual[] =
"operator>=";
986 info.replace(
"operator ",
"operator");
992 pos = info.lastIndexOf(
')', pos);
997 if (info.indexOf(
'>', pos) != -1
998 || info.indexOf(
':', pos) != -1) {
1007 while (pos && parencount) {
1008 if (info.at(pos) ==
')')
1010 else if (info.at(pos) ==
'(')
1014 if (parencount != 0)
1017 info.truncate(++pos);
1019 if (info.at(pos - 1) ==
')') {
1020 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
1026 info.remove(0, info.indexOf(
'('));
1036 int templatecount = 0;
1041 switch (info.at(pos)) {
1043 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
1047 if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
1051 if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
1055 auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
1056 if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
1058 else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
1068 if (parencount < 0 || templatecount < 0)
1071 char c = info.at(pos);
1080 else if (c ==
' ' && templatecount == 0 && parencount == 0)
1085 info = info.mid(pos + 1);
1088 while ((info.at(0) ==
'*')
1089 || (info.at(0) ==
'&'))
1094 while ((pos = info.lastIndexOf(
'>')) != -1) {
1095 if (!info.contains(
'<'))
1099 qsizetype end = pos;
1102 while (pos && templatecount) {
1103 char c = info.at(pos);
1111 info.remove(pos, end - pos + 1);
1148 const char *
const defaultTokens[] = {
1161 Q_ASSERT(!literals);
1163 auto ptr =
new const char *[
std::size(defaultTokens) + 1];
1164 auto end =
std::copy(
std::begin(defaultTokens),
std::end(defaultTokens), ptr);
1180#ifdef QLOGGING_HAVE_BACKTRACE
1202Q_CONSTINIT QBasicMutex QMessagePattern::mutex;
1206 const QString envPattern = qEnvironmentVariable(
"QT_MESSAGE_PATTERN");
1207 if (envPattern.isEmpty()) {
1221 QVarLengthArray<QStringView, 16> lexemes;
1222 qsizetype literalLexemeCount = 0;
1223 qsizetype lexemeStart = 0;
1224 bool inPlaceholder =
false;
1225 for (qsizetype i = 0; i < pattern.size(); ++i) {
1226 const QChar c = pattern.at(i);
1227 if (c == u'%' && !inPlaceholder) {
1228 if ((i + 1 < pattern.size())
1229 && pattern.at(i + 1) == u'{') {
1231 if (lexemeStart != i) {
1232 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1233 pattern.cbegin() + i));
1234 ++literalLexemeCount;
1237 inPlaceholder =
true;
1241 if (c == u'}' && inPlaceholder) {
1244 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1245 pattern.cbegin() + i + 1));
1246 lexemeStart = i + 1;
1247 inPlaceholder =
false;
1250 if (lexemeStart < pattern.size()) {
1251 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1253 ++literalLexemeCount;
1259 QList<QString> newTimeArgs;
1260#ifdef QLOGGING_HAVE_BACKTRACE
1261 QList<BacktraceParams> newBacktraceArgs;
1262 int newMaxBacktraceDepth = 0;
1265 auto newLiterals = std::make_unique<std::unique_ptr<
const char[]>[]>(literalLexemeCount + 1);
1266 auto newTokens =
std::make_unique<
const char *[]>(lexemes.size() + 1);
1267 newTokens[lexemes.size()] =
nullptr;
1269 bool nestedIfError =
false;
1272 qsizetype literalLexemeIndex = 0;
1274 for (qsizetype i = 0; i < lexemes.size(); ++i) {
1275 const QStringView lexeme = lexemes.at(i);
1276 if (lexeme.startsWith(
"%{"_L1) && lexeme.endsWith(u'}')) {
1278 if (lexeme == QLatin1StringView(
typeTokenC)) {
1284 else if (lexeme == QLatin1StringView(
fileTokenC))
1286 else if (lexeme == QLatin1StringView(
lineTokenC))
1290 else if (lexeme == QLatin1StringView(
pidTokenC))
1300 else if (lexeme.startsWith(QLatin1StringView(
timeTokenC))) {
1302 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(
' '));
1304 newTimeArgs.append(QString(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2)));
1306 newTimeArgs.append(QString());
1308#ifdef QLOGGING_HAVE_BACKTRACE
1309 newTokens[i] = backtraceTokenC;
1310 QString backtraceSeparator = QStringLiteral(
"|");
1311 int backtraceDepth = 5;
1312 static const QRegularExpression depthRx(QStringLiteral(
" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1313 static const QRegularExpression separatorRx(QStringLiteral(
" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1314 QRegularExpressionMatch m = depthRx.matchView(lexeme);
1316 int depth = m.capturedView(1).toInt();
1318 error +=
"QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1320 backtraceDepth = std::min(depth, QInternalMessageLogContext::MaxBacktraceDepth);
1322 m = separatorRx.matchView(lexeme);
1324 backtraceSeparator = m.captured(1);
1325 BacktraceParams backtraceParams;
1326 backtraceParams.backtraceDepth = backtraceDepth;
1327 backtraceParams.backtraceSeparator = backtraceSeparator;
1328 newBacktraceArgs.append(backtraceParams);
1329 newMaxBacktraceDepth = qMax(newMaxBacktraceDepth, backtraceDepth);
1331 error +=
"QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1336#define IF_TOKEN(LEVEL)
1337 else if (lexeme == QLatin1StringView(LEVEL)) {
1339 nestedIfError = true;
1340 newTokens[i] = LEVEL;
1350 else if (lexeme == QLatin1StringView(
endifTokenC)) {
1352 if (!inIf && !nestedIfError)
1353 error +=
"QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1357 error +=
"QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme +
'\n'_L1;
1360 Q_ASSERT(literalLexemeIndex < literalLexemeCount);
1361 using UP = std::unique_ptr<
char[]>;
1362 newLiterals[literalLexemeIndex] = UP(qstrdup(lexeme.toUtf8().constData()));
1363 newTokens[i] = newLiterals[literalLexemeIndex].get();
1364 ++literalLexemeIndex;
1368 error +=
"QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1370 error +=
"QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1372 if (!error.isEmpty()) {
1377 "QMessagePattern::setPattern", nullptr);
1378 preformattedMessageHandler(QtWarningMsg, ctx, error);
1381 literals = std::move(newLiterals);
1382 tokens = std::move(newTokens);
1383 timeArgs = std::move(newTimeArgs);
1384#ifdef QLOGGING_HAVE_BACKTRACE
1385 backtraceArgs = std::move(newBacktraceArgs);
1386 maxBacktraceDepth = newMaxBacktraceDepth;
1390#if defined(QLOGGING_HAVE_BACKTRACE)
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403static constexpr int TypicalBacktraceFrameCount = 3;
1404static constexpr const char *QtCoreLibraryName =
"Qt" QT_STRINGIFY(QT_VERSION_MAJOR)
"Core";
1406#if defined(QLOGGING_USE_STD_BACKTRACE)
1407Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1409 assert(frameCount >= 0);
1410 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1414backtraceFramesForLogMessage(
int frameCount,
1415 const QInternalMessageLogContext::BacktraceStorage &buffer)
1418 result.reserve(buffer.size());
1420 const auto shouldSkipFrame = [](QByteArrayView description)
1422#if defined(_MSVC_STL_VERSION)
1423 const auto libraryNameEnd = description.indexOf(
'!');
1424 if (libraryNameEnd != -1) {
1425 const auto libraryName = description.first(libraryNameEnd);
1426 if (!libraryName.contains(QtCoreLibraryName))
1430 if (description.contains(
"populateBacktrace"))
1432 if (description.contains(
"QInternalMessageLogContext"))
1434 if (description.contains(
"~QDebug"))
1439 for (
const auto &entry : buffer) {
1440 const std::string description = entry.description();
1441 if (result.isEmpty() && shouldSkipFrame(description))
1443 result.append(QString::fromStdString(description));
1449#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1451Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1453 assert(frameCount >= 0);
1454 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1455 Q_ASSERT(result.size() ==
int(result.size()));
1456 int n = ::backtrace(result.data(),
int(result.size()));
1464backtraceFramesForLogMessage(
int frameCount,
1465 const QInternalMessageLogContext::BacktraceStorage &buffer)
1467 struct DecodedFrame {
1473 if (frameCount == 0)
1476 auto shouldSkipFrame = [&result](
const auto &library,
const auto &function) {
1477 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1479 if (function.isEmpty())
1481 if (function.contains(
"6QDebug"_L1))
1483 if (function.contains(
"14QMessageLogger"_L1))
1485 if (function.contains(
"17qt_message_output"_L1))
1487 if (function.contains(
"26QInternalMessageLogContext"_L1))
1492 auto demangled = [](
auto &function) -> QString {
1493 if (!function.startsWith(
"_Z"_L1))
1498 if constexpr (
sizeof(function.at(0)) == 1)
1499 return function.data();
1501 return std::move(function).toUtf8();
1503 auto cleanup = [](
auto *p) { free(p); };
1504 using Ptr = std::unique_ptr<
char,
decltype(cleanup)>;
1505 auto demangled = Ptr(abi::__cxa_demangle(fn,
nullptr,
nullptr,
nullptr), cleanup);
1508 return QString::fromUtf8(qCleanupFuncinfo(demangled.get()));
1510 return QString::fromUtf8(fn);
1513# if QT_CONFIG(dladdr)
1515 QString cachedLibrary;
1516 const char *cachedFname =
nullptr;
1517 auto decodeFrame = [&](
void *addr) -> DecodedFrame {
1519 if (!dladdr(addr, &info))
1523 QLatin1StringView fn(info.dli_sname);
1524 QLatin1StringView lib;
1525 if (
const char *lastSlash = strrchr(info.dli_fname,
'/'))
1526 lib = QLatin1StringView(lastSlash + 1);
1528 lib = QLatin1StringView(info.dli_fname);
1530 if (shouldSkipFrame(lib, fn))
1533 QString function = demangled(fn);
1534 if (lib.data() != cachedFname) {
1535 cachedFname = lib.data();
1536 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1538 return { cachedLibrary, function };
1546 static const QRegularExpression rx(QStringLiteral(
"^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1548 auto decodeFrame = [&](
void *&addr) -> DecodedFrame {
1549 auto cleanup = [](
auto *p) { free(p); };
1551 std::unique_ptr<
char *,
decltype(cleanup)>(backtrace_symbols(&addr, 1), cleanup);
1552 QString trace = QString::fromUtf8(strings.get()[0]);
1553 QRegularExpressionMatch m = rx.match(trace);
1557 QString library = m.captured(1);
1558 QString function = m.captured(2);
1561 if (shouldSkipFrame(library, function))
1564 function = demangled(function);
1565 return { library, function };
1569 for (
void *
const &addr : buffer) {
1570 DecodedFrame frame = decodeFrame(addr);
1571 if (!frame.library.isEmpty()) {
1572 if (frame.function.isEmpty())
1573 result.append(u'?' + frame.library + u'?');
1575 result.append(frame.function);
1578 if (!result.isEmpty())
1579 result.append(QStringLiteral(
"???"));
1582 if (result.size() == frameCount)
1588#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1592
1593
1594
1595static QStringList generateBacktraceFrames(
int frameCount,
const QMessageLogContext &ctx)
1598 if (ctx.version <= QMessageLogContext::CurrentVersion)
1601 auto &fullctx =
static_cast<
const QInternalMessageLogContext &>(ctx);
1602 if (!fullctx.backtrace.has_value())
1605 QStringList frames = backtraceFramesForLogMessage(frameCount, *fullctx.backtrace);
1606 if (frames.isEmpty())
1610 if (ctx.function && frames.at(0).startsWith(u'?'))
1611 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1616static QString formatBacktraceForLogMessage(
const QMessagePattern::BacktraceParams backtraceParams,
1617 const QStringList &backtrace)
1619 if (backtrace.isEmpty() || backtraceParams.backtraceDepth <= 0)
1622 const qsizetype backtraceDepth = (std::min)(qsizetype(backtraceParams.backtraceDepth),
1627 for (
auto it = backtrace.cbegin(); it != backtrace.cbegin() + backtraceDepth; ++it) {
1628 if (it != backtrace.cbegin())
1629 result += backtraceParams.backtraceSeparator;
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1660 return formatLogMessage(type, context, str);
1675 message.append(str);
1681 qsizetype timeArgsIdx = 0;
1682#ifdef QLOGGING_HAVE_BACKTRACE
1683 qsizetype backtraceArgsIdx = 0;
1684 QStringList fullBacktrace;
1688 for (qsizetype i = 0; pattern->tokens[i]; ++i) {
1689 const char *token = pattern->tokens[i];
1695 if (token == timeTokenC)
1697#ifdef QLOGGING_HAVE_BACKTRACE
1698 else if (token == backtraceTokenC)
1702 message.append(str);
1704 message.append(QUtf8StringView(context
.category));
1707 case QtDebugMsg: message.append(
"debug"_L1);
break;
1708 case QtInfoMsg: message.append(
"info"_L1);
break;
1709 case QtWarningMsg: message.append(
"warning"_L1);
break;
1711 case QtFatalMsg: message.append(
"fatal"_L1);
break;
1715 message.append(QUtf8StringView(context
.file));
1717 message.append(
"unknown"_L1);
1719 message.append(QString::number(context.line));
1722 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1724 message.append(
"unknown"_L1);
1726 message.append(QString::number(QCoreApplication::applicationPid()));
1728 message.append(QCoreApplication::applicationName());
1731 message.append(QString::number(qt_gettid()));
1733 if (!qt_append_thread_name_to(message))
1734 message.append(QString::number(qt_gettid()));
1736 message.append(
"0x"_L1);
1737 message.append(QString::number(qlonglong(QThread::currentThread()), 16));
1738#ifdef QLOGGING_HAVE_BACKTRACE
1739 }
else if (token == backtraceTokenC) {
1740 if (fullBacktrace.isEmpty())
1741 fullBacktrace = generateBacktraceFrames(pattern->maxBacktraceDepth, context);
1742 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1744 message.append(formatBacktraceForLogMessage(backtraceParams, fullBacktrace));
1747 using namespace std::chrono;
1748 auto formatElapsedTime = [](steady_clock::duration time) {
1750 auto ms = duration_cast<milliseconds>(time);
1751 auto sec = duration_cast<seconds>(ms);
1753 return QString::asprintf(
"%6lld.%03u", qint64(sec.count()), uint(ms.count()));
1755 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1757 if (timeFormat ==
"process"_L1) {
1758 message += formatElapsedTime(steady_clock::now() - pattern->appStartTime);
1759 }
else if (timeFormat ==
"boot"_L1) {
1762 message += formatElapsedTime(steady_clock::now().time_since_epoch());
1763#if QT_CONFIG(datestring)
1764 }
else if (timeFormat.isEmpty()) {
1765 message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1767 message.append(QDateTime::currentDateTime().toString(timeFormat));
1773#define HANDLE_IF_TOKEN(LEVEL)
1774 } else if (token == if##LEVEL##TokenC) {
1775 skip = type != Qt##LEVEL##Msg;
1781#undef HANDLE_IF_TOKEN
1783 message.append(QUtf8StringView(token));
1792Q_CONSTINIT
static QBasicAtomicPointer<
void (QtMsgType,
const QMessageLogContext &,
const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(
nullptr);
1798#define QT_LOG_CODE 9000
1801static bool slog2_default_handler(QtMsgType type,
const QMessageLogContext &,
1802 const QString &message)
1804 if (shouldLogToStderr())
1807 QString formattedMessage = message;
1808 formattedMessage.append(u'\n');
1809 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1810 slog2_buffer_set_config_t buffer_config;
1811 slog2_buffer_t buffer_handle;
1813 buffer_config.buffer_set_name = __progname;
1814 buffer_config.num_buffers = 1;
1815 buffer_config.verbosity_level = SLOG2_DEBUG1;
1816 buffer_config.buffer_config[0].buffer_name =
"default";
1817 buffer_config.buffer_config[0].num_pages = 8;
1819 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1820 fprintf(stderr,
"Error registering slogger2 buffer!\n");
1825 slog2_set_default_buffer(buffer_handle);
1827 int severity = SLOG2_INFO;
1831 severity = SLOG2_DEBUG1;
1834 severity = SLOG2_INFO;
1837 severity = SLOG2_NOTICE;
1840 severity = SLOG2_WARNING;
1843 severity = SLOG2_ERROR;
1847 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1853#if QT_CONFIG(journald)
1854static bool systemd_default_message_handler(QtMsgType type,
1855 const QMessageLogContext &context,
1856 const QString &message)
1858 if (shouldLogToStderr())
1861 int priority = LOG_INFO;
1864 priority = LOG_DEBUG;
1867 priority = LOG_INFO;
1870 priority = LOG_WARNING;
1873 priority = LOG_CRIT;
1876 priority = LOG_ALERT;
1881 const QByteArray messageField =
"MESSAGE="_ba + message.toUtf8();
1882 const QByteArray priorityField =
"PRIORITY="_ba + QByteArray::number(priority);
1883 const QByteArray tidField =
"TID="_ba + QByteArray::number(qlonglong(qt_gettid()));
1884 const QByteArray fileField = context.file
1885 ?
"CODE_FILE="_ba + context.file : QByteArray();
1886 const QByteArray funcField = context.function
1887 ?
"CODE_FUNC="_ba + context.function : QByteArray();
1888 const QByteArray lineField = context.line
1889 ?
"CODE_LINE="_ba + QByteArray::number(context.line) : QByteArray();
1890 const QByteArray categoryField = context.category
1891 ?
"QT_CATEGORY="_ba + context.category : QByteArray();
1893 auto toIovec = [](
const QByteArray &ba) {
1894 return iovec{
const_cast<
char*>(ba.data()), size_t(ba.size()) };
1897 struct iovec fields[7] = {
1898 toIovec(messageField),
1899 toIovec(priorityField),
1904 fields[nFields++] = toIovec(fileField);
1905 if (context.function)
1906 fields[nFields++] = toIovec(funcField);
1908 fields[nFields++] = toIovec(lineField);
1909 if (context.category)
1910 fields[nFields++] = toIovec(categoryField);
1912 sd_journal_sendv(fields, nFields);
1918#if QT_CONFIG(syslog)
1919static bool syslog_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
1920 const QString &formattedMessage)
1922 if (shouldLogToStderr())
1925 int priority = LOG_INFO;
1928 priority = LOG_DEBUG;
1931 priority = LOG_INFO;
1934 priority = LOG_WARNING;
1937 priority = LOG_CRIT;
1940 priority = LOG_ALERT;
1944 syslog(priority,
"%s", formattedMessage.toUtf8().constData());
1951static bool android_default_message_handler(QtMsgType type,
1952 const QMessageLogContext &context,
1953 const QString &formattedMessage)
1955 if (shouldLogToStderr())
1958 android_LogPriority priority = ANDROID_LOG_DEBUG;
1961 priority = ANDROID_LOG_DEBUG;
1964 priority = ANDROID_LOG_INFO;
1967 priority = ANDROID_LOG_WARN;
1970 priority = ANDROID_LOG_ERROR;
1973 priority = ANDROID_LOG_FATAL;
1977 QMessagePattern *pattern = qMessagePattern();
1978 const QString tag = (pattern && pattern->containsToken(categoryTokenC))
1980 ? QCoreApplication::applicationName().replace(u' ', u'_')
1981 : QString::fromUtf8(context.category);
1982 __android_log_print(priority, qPrintable(tag),
"%s\n", qPrintable(formattedMessage));
1988#if defined(Q_OS_HARMONY)
1989static bool ohos_default_message_handler(QtMsgType type,
1990 const QMessageLogContext &context,
1991 const QString &message)
1993 QString formattedMessage = qFormatLogMessage(type, context, message);
1995 LogLevel priority = LOG_DEBUG;
1997 case QtDebugMsg: priority = LOG_DEBUG;
break;
1998 case QtInfoMsg: priority = LOG_INFO;
break;
1999 case QtWarningMsg: priority = LOG_WARN;
break;
2000 case QtCriticalMsg: priority = LOG_ERROR;
break;
2001 case QtFatalMsg: priority = LOG_FATAL;
break;
2004 qOhosLogMessage(priority, qPrintable(QCoreApplication::applicationName()), qPrintable(formattedMessage));
2011static void win_outputDebugString_helper(
const QString &message)
2013 const qsizetype maxOutputStringLength = 32766;
2014 Q_CONSTINIT
static QBasicMutex m;
2015 const auto locker = qt_scoped_lock(m);
2018 if (message.length() <= maxOutputStringLength) {
2019 OutputDebugString(
reinterpret_cast<
const wchar_t *>(message.utf16()));
2021 wchar_t *messagePart =
new wchar_t[maxOutputStringLength + 1];
2022 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
2023 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
2024 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
2025 Q_ASSERT(len == length);
2026 messagePart[len] = 0;
2027 OutputDebugString(messagePart);
2029 delete[] messagePart;
2033static bool win_message_handler(QtMsgType,
const QMessageLogContext &,
2034 const QString &formattedMessage)
2036 if (shouldLogToStderr())
2039 win_outputDebugString_helper(formattedMessage + u'\n');
2046static bool wasm_default_message_handler(QtMsgType type,
2047 const QMessageLogContext &,
2048 const QString &formattedMessage)
2050 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
2051 if (forceStderrLogging)
2054 int emOutputFlags = EM_LOG_CONSOLE;
2055 QByteArray localMsg = formattedMessage.toLocal8Bit();
2062 emOutputFlags |= EM_LOG_WARN;
2065 emOutputFlags |= EM_LOG_ERROR;
2068 emOutputFlags |= EM_LOG_ERROR;
2070 emscripten_log(emOutputFlags,
"%s\n", qPrintable(formattedMessage));
2079 const QString &formattedMessage)
2086 if (formattedMessage.isNull())
2088 const QByteArray msg = formattedMessage.toLocal8Bit() +
'\n';
2089 fwrite(msg.constData(), 1, msg.size(), stderr);
2098 bool messageIsUnformatted =
false;
2101#if defined(Q_OS_WIN)
2103#elif QT_CONFIG(slog2)
2104 slog2_default_handler
2105#elif QT_CONFIG(journald)
2106 systemd_default_message_handler,
true
2107#elif QT_CONFIG(syslog)
2108 syslog_default_message_handler
2109#elif defined(Q_OS_ANDROID)
2110 android_default_message_handler
2111# elif defined(Q_OS_HARMONY)
2112 ohos_default_message_handler
2113#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
2114 AppleUnifiedLogger::messageHandler,
true
2115#elif defined Q_OS_WASM
2116 wasm_default_message_handler
2124 const QString &formattedMessage)
2128QT_WARNING_DISABLE_GCC(
"-Waddress")
2129 if (systemMessageSink().sink && systemMessageSink().sink(type, context, formattedMessage))
2138
2139
2141 const QString &message)
2152 preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
2177 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2178 if (!defaultCategory->isEnabled(msgType))
2187 auto msgHandler = messageHandler.loadAcquire();
2194template <
typename String>
static void
2199#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2200 wchar_t contextFileL[256];
2204 convert_to_wchar_t_elided(contextFileL,
sizeof contextFileL /
sizeof *contextFileL,
2207 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2208 _CrtSetReportMode(_CRT_ERROR, reportMode);
2210 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2211 reinterpret_cast<
const wchar_t *>(message.utf16()));
2212 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2220 if constexpr (
std::is_class_v<String> && !
std::is_const_v<String>)
2228
2229
2233 qt_message_print(msgType, ctx, message);
2234 qt_maybe_message_fatal(msgType, ctx, message);
2241 QString error_string = qt_error_string(-1);
2245 QString buf = QString::vasprintf(msg, ap);
2248 buf +=
" ("_L1 + error_string + u')';
2250 qt_message_output(QtWarningMsg, context, buf);
2259 QString buf = QString::vasprintf(msg, ap);
2262 buf +=
" ("_L1 + qt_error_string(code) + u')';
2264 qt_message_output(QtWarningMsg, context, buf);
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2444 const auto old = messageHandler.fetchAndStoreOrdered(h);
2455 if (!qMessagePattern()->fromEnvironment)
2456 qMessagePattern()->setPattern(pattern);
2462 if (logContext.version == self->version) {
2463 auto other =
static_cast<
const QInternalMessageLogContext *>(&logContext);
2464 self->backtrace = other->backtrace;
2469
2470
2471
2472
2475 version = CurrentVersion + 1;
2476 copyContextFrom(logContext);
2478#ifdef QLOGGING_HAVE_BACKTRACE
2479 if (backtrace.has_value())
2483 if (
auto pattern = qMessagePattern())
2484 return pattern->maxBacktraceDepth;
2491
2492
2493
2494
2495
2496
2497
2504 if (Q_UNLIKELY(version == CurrentVersion + 1))
2505 copyInternalContext(
static_cast<QInternalMessageLogContext *>(
this), logContext);
2510
2511
2512
2513
2514
2517
2518
2519
2520
2521
2523
2524
2525
2526
2527
2528
2529
2532
2533
2534
2535
2536
2537
2538
2541
2542
2543
2544
2545
2548
2549
2550
2551
2552
2553
2554
2555
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
int initFrom(const QMessageLogContext &logContext)
void populateBacktrace(int frameCount)
constexpr QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName) noexcept
constexpr QMessageLogContext() noexcept=default
static const char ifCriticalTokenC[]
static bool grabMessageHandler()
void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
static const char emptyTokenC[]
static Q_NEVER_INLINE void qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
static void preformattedMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &formattedMessage)
static bool systemHasStderr()
Returns true if writing to stderr is supported.
static const char endifTokenC[]
static bool isDefaultCategory(const char *category)
static const char messageTokenC[]
static bool qt_append_thread_name_to(QString &message)
static void qt_maybe_message_fatal(QtMsgType, const QMessageLogContext &context, String &&message)
\inmodule QtCore \title Qt Logging Types
#define HANDLE_IF_TOKEN(LEVEL)
Q_DECLARE_TYPEINFO(QMessagePattern::BacktraceParams, Q_RELOCATABLE_TYPE)
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf)
static constexpr auto systemMessageSink()
static const char timeTokenC[]
static bool isFatalCountDown(const char *varname, QBasicAtomicInt &n)
void qErrnoWarning(int code, const char *msg,...)
static const char qthreadptrTokenC[]
static const char fileTokenC[]
static const char ifDebugTokenC[]
static const char ifFatalTokenC[]
static const char categoryTokenC[]
static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &formattedMessage)
static const char lineTokenC[]
static const char typeTokenC[]
static void ungrabMessageHandler()
static void copyInternalContext(QInternalMessageLogContext *self, const QMessageLogContext &logContext) noexcept
static const char ifCategoryTokenC[]
static int checked_var_value(const char *varname)
static const char threadnameTokenC[]
static const char pidTokenC[]
Q_TRACE_POINT(qtcore, qt_message_print, int type, const char *category, const char *function, const char *file, int line, const QString &message)
static const char threadidTokenC[]
static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
static Q_CONSTINIT bool msgHandlerGrabbed
static const char backtraceTokenC[]
void qErrnoWarning(const char *msg,...)
static const char functionTokenC[]
static const char ifWarningTokenC[]
static const char appnameTokenC[]
static bool isFatal(QtMsgType msgType)
static const char ifInfoTokenC[]
QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
static void qt_message_print(QtMsgType, const QMessageLogContext &context, const QString &message)
static bool stderrHasConsoleAttached()
Returns true if writing to stderr will end up in a console/terminal visible to the user.
void qSetMessagePattern(const QString &pattern)
Combined button and popup list for selecting options.
bool shouldLogToStderr()
Returns true if logging stderr should be ensured.
#define QT_MESSAGELOG_FILE
#define QT_MESSAGELOG_LINE
void(*) QtMessageHandler(QtMsgType, const QMessageLogContext &, const QString &)
QString backtraceSeparator
void setPattern(const QString &pattern)
std::unique_ptr< std::unique_ptr< const char[]>[]> literals
std::chrono::steady_clock::time_point appStartTime
std::unique_ptr< const char *[]> tokens
QList< QString > timeArgs