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>
95#include "qfunctionpointer.h"
100using namespace Qt::StringLiterals;
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
134
136template <
typename String>
140 const QString &formattedMessage);
153 int value = str.toInt(&ok, 0);
154 return (ok && value >= 0) ? value : 1;
159 static const int Uninitialized = 0;
160 static const int NeverFatal = 1;
161 static const int ImmediatelyFatal = 2;
163 int v = n.loadRelaxed();
164 if (v == Uninitialized) {
168 if (env == NeverFatal) {
170 n.storeRelaxed(NeverFatal);
172 }
else if (env == ImmediatelyFatal) {
174 }
else if (n.testAndSetRelaxed(Uninitialized, env - 1, v)) {
181 while (v > ImmediatelyFatal && !n.testAndSetRelaxed(v, v - 1, v))
186 return v == ImmediatelyFatal;
189Q_CONSTINIT
static QBasicAtomicInt fatalCriticalsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
190Q_CONSTINIT
static QBasicAtomicInt fatalWarningsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
198 return isFatalCountDown(
"QT_FATAL_CRITICALS", fatalCriticalsCount);
201 return isFatalCountDown(
"QT_FATAL_WARNINGS", fatalWarningsCount);
211#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
212static bool qt_append_thread_name_to(QString &message)
214 std::array<
char, 16> name{};
215 if (pthread_getname_np(pthread_self(), name.data(), name.size()) == 0) {
216 QUtf8StringView threadName(name.data());
217 if (!threadName.isEmpty()) {
218 message.append(threadName);
224#elif defined(Q_OS_WIN)
225typedef HRESULT (WINAPI *GetThreadDescriptionFunc)(HANDLE, PWSTR *);
226static bool qt_append_thread_name_to(QString &message)
230 static GetThreadDescriptionFunc pGetThreadDescription = []() -> GetThreadDescriptionFunc {
231 HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
234 auto funcPtr =
reinterpret_cast<QFunctionPointer>(GetProcAddress(hKernel,
"GetThreadDescription"));
235 return reinterpret_cast<GetThreadDescriptionFunc>(funcPtr);
237 if (!pGetThreadDescription)
239 PWSTR description =
nullptr;
240 HRESULT hr = pGetThreadDescription(GetCurrentThread(), &description);
241 std::unique_ptr<WCHAR,
decltype(&LocalFree)> descriptionOwner(description, &LocalFree);
243 QStringView threadName(description);
244 if (!threadName.isEmpty()) {
245 message.append(threadName);
262
263
264
265
266
269#if defined(Q_OS_OHOS)
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
298 static const bool stderrHasConsoleAttached = []() ->
bool {
302 if (qEnvironmentVariableIntValue(
"QT_LOGGING_TO_CONSOLE")) {
303 fprintf(stderr,
"warning: Environment variable QT_LOGGING_TO_CONSOLE is deprecated, use\n"
304 "QT_ASSUME_STDERR_HAS_CONSOLE and/or QT_FORCE_STDERR_LOGGING instead.\n");
308 if (qEnvironmentVariableIntValue(
"QT_ASSUME_STDERR_HAS_CONSOLE"))
312 return GetConsoleWindow();
313#elif defined(Q_OS_UNIX)
315# define _PATH_TTY "/dev/tty"
320 if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
321 qt_safe_close(ttyDevice);
323 }
else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
325 return isatty(STDERR_FILENO);
334 return stderrHasConsoleAttached;
341
342
343
344
345
346
347
348
351 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
363
364
365
366
367
368
369
370
371
372
373
374
375
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
396#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
397static inline void convert_to_wchar_t_elided(
wchar_t *d, size_t space,
const char *s)
noexcept
399 size_t len = qstrlen(s);
400 if (len + 1 > space) {
401 const size_t skip = len - space + 4;
404 for (
int i = 0; i < 3; ++i)
414
415
419 QString buf = QString::vasprintf(msg, ap);
420 qt_message_print(msgType, context, buf);
421 qt_maybe_message_fatal(msgType, context, buf);
425
426
427
428
429
430void QMessageLogger::debug(
const char *msg, ...)
const
432 QInternalMessageLogContext ctxt(context);
435 qt_message(QtDebugMsg, ctxt, msg, ap);
440
441
442
443
444
445
446void QMessageLogger::info(
const char *msg, ...)
const
448 QInternalMessageLogContext ctxt(context);
451 qt_message(QtInfoMsg, ctxt, msg, ap);
456
457
458
459
460
461
462
463
464
465
466
467
468
469
472
473
474
475
476
477
478void QMessageLogger::debug(
const QLoggingCategory &cat,
const char *msg, ...)
const
480 if (!cat.isDebugEnabled())
483 QInternalMessageLogContext ctxt(context, cat());
487 qt_message(QtDebugMsg, ctxt, msg, ap);
492
493
494
495
496
497
498void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
499 const char *msg, ...)
const
501 const QLoggingCategory &cat = (*catFunc)();
502 if (!cat.isDebugEnabled())
505 QInternalMessageLogContext ctxt(context, cat());
509 qt_message(QtDebugMsg, ctxt, msg, ap);
513#ifndef QT_NO_DEBUG_STREAM
516
517
518
519
520QDebug QMessageLogger::debug()
const
522 QDebug dbg = QDebug(QtDebugMsg);
523 QMessageLogContext &ctxt = dbg.stream->context;
524 ctxt.copyContextFrom(context);
529
530
531
532
533
534QDebug QMessageLogger::debug(
const QLoggingCategory &cat)
const
536 QDebug dbg = QDebug(QtDebugMsg);
537 if (!cat.isDebugEnabled())
538 dbg.stream->message_output =
false;
540 QMessageLogContext &ctxt = dbg.stream->context;
541 ctxt.copyContextFrom(context);
542 ctxt.category = cat.categoryName();
548
549
550
551
552
553QDebug QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc)
const
555 return debug((*catFunc)());
560
561
562
563
564
565
566void QMessageLogger::info(
const QLoggingCategory &cat,
const char *msg, ...)
const
568 if (!cat.isInfoEnabled())
571 QInternalMessageLogContext ctxt(context, cat());
575 qt_message(QtInfoMsg, ctxt, msg, ap);
580
581
582
583
584
585
586void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
587 const char *msg, ...)
const
589 const QLoggingCategory &cat = (*catFunc)();
590 if (!cat.isInfoEnabled())
593 QInternalMessageLogContext ctxt(context, cat());
597 qt_message(QtInfoMsg, ctxt, msg, ap);
601#ifndef QT_NO_DEBUG_STREAM
604
605
606
607
608
609QDebug QMessageLogger::info()
const
611 QDebug dbg = QDebug(QtInfoMsg);
612 QMessageLogContext &ctxt = dbg.stream->context;
613 ctxt.copyContextFrom(context);
618
619
620
621
622
623QDebug QMessageLogger::info(
const QLoggingCategory &cat)
const
625 QDebug dbg = QDebug(QtInfoMsg);
626 if (!cat.isInfoEnabled())
627 dbg.stream->message_output =
false;
629 QMessageLogContext &ctxt = dbg.stream->context;
630 ctxt.copyContextFrom(context);
631 ctxt.category = cat.categoryName();
637
638
639
640
641
642QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc)
const
644 return info((*catFunc)());
650
651
652
653
654
655void QMessageLogger::warning(
const char *msg, ...)
const
657 QInternalMessageLogContext ctxt(context);
660 qt_message(QtWarningMsg, ctxt, msg, ap);
665
666
667
668
669
670
671void QMessageLogger::warning(
const QLoggingCategory &cat,
const char *msg, ...)
const
673 if (!cat.isWarningEnabled())
676 QInternalMessageLogContext ctxt(context, cat());
680 qt_message(QtWarningMsg, ctxt, msg, ap);
685
686
687
688
689
690
691void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
692 const char *msg, ...)
const
694 const QLoggingCategory &cat = (*catFunc)();
695 if (!cat.isWarningEnabled())
698 QInternalMessageLogContext ctxt(context, cat());
702 qt_message(QtWarningMsg, ctxt, msg, ap);
706#ifndef QT_NO_DEBUG_STREAM
708
709
710
711
712QDebug QMessageLogger::warning()
const
714 QDebug dbg = QDebug(QtWarningMsg);
715 QMessageLogContext &ctxt = dbg.stream->context;
716 ctxt.copyContextFrom(context);
721
722
723
724
725QDebug QMessageLogger::warning(
const QLoggingCategory &cat)
const
727 QDebug dbg = QDebug(QtWarningMsg);
728 if (!cat.isWarningEnabled())
729 dbg.stream->message_output =
false;
731 QMessageLogContext &ctxt = dbg.stream->context;
732 ctxt.copyContextFrom(context);
733 ctxt.category = cat.categoryName();
739
740
741
742
743
744QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc)
const
746 return warning((*catFunc)());
752
753
754
755
756
757void QMessageLogger::critical(
const char *msg, ...)
const
759 QInternalMessageLogContext ctxt(context);
762 qt_message(QtCriticalMsg, ctxt, msg, ap);
767
768
769
770
771
772
773void QMessageLogger::critical(
const QLoggingCategory &cat,
const char *msg, ...)
const
775 if (!cat.isCriticalEnabled())
778 QInternalMessageLogContext ctxt(context, cat());
782 qt_message(QtCriticalMsg, ctxt, msg, ap);
787
788
789
790
791
792
793void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
794 const char *msg, ...)
const
796 const QLoggingCategory &cat = (*catFunc)();
797 if (!cat.isCriticalEnabled())
800 QInternalMessageLogContext ctxt(context, cat());
804 qt_message(QtCriticalMsg, ctxt, msg, ap);
808#ifndef QT_NO_DEBUG_STREAM
810
811
812
813
814QDebug QMessageLogger::critical()
const
816 QDebug dbg = QDebug(QtCriticalMsg);
817 QMessageLogContext &ctxt = dbg.stream->context;
818 ctxt.copyContextFrom(context);
823
824
825
826
827
828QDebug QMessageLogger::critical(
const QLoggingCategory &cat)
const
830 QDebug dbg = QDebug(QtCriticalMsg);
831 if (!cat.isCriticalEnabled())
832 dbg.stream->message_output =
false;
834 QMessageLogContext &ctxt = dbg.stream->context;
835 ctxt.copyContextFrom(context);
836 ctxt.category = cat.categoryName();
842
843
844
845
846
847QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc)
const
849 return critical((*catFunc)());
855
856
857
858
859
860
861void QMessageLogger::fatal(
const QLoggingCategory &cat,
const char *msg, ...)
const noexcept
863 QInternalMessageLogContext ctxt(context, cat());
867 qt_message(QtFatalMsg, ctxt, msg, ap);
870#ifndef Q_CC_MSVC_ONLY
876
877
878
879
880
881
882void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
883 const char *msg, ...)
const noexcept
885 const QLoggingCategory &cat = (*catFunc)();
887 QInternalMessageLogContext ctxt(context, cat());
891 qt_message(QtFatalMsg, ctxt, msg, ap);
894#ifndef Q_CC_MSVC_ONLY
900
901
902
903
904
905void QMessageLogger::fatal(
const char *msg, ...)
const noexcept
907 QInternalMessageLogContext ctxt(context);
910 qt_message(QtFatalMsg, ctxt, msg, ap);
913#ifndef Q_CC_MSVC_ONLY
918#ifndef QT_NO_DEBUG_STREAM
920
921
922
923
924
925
926QDebug QMessageLogger::fatal()
const
928 QDebug dbg = QDebug(QtFatalMsg);
929 QMessageLogContext &ctxt = dbg.stream->context;
930 ctxt.copyContextFrom(context);
935
936
937
938
939
940QDebug QMessageLogger::fatal(
const QLoggingCategory &cat)
const
942 QDebug dbg = QDebug(QtFatalMsg);
944 QMessageLogContext &ctxt = dbg.stream->context;
945 ctxt.copyContextFrom(context);
946 ctxt.category = cat.categoryName();
952
953
954
955
956
957QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc)
const
959 return fatal((*catFunc)());
965 return !category || strcmp(category, QLoggingRegistry::defaultCategoryName) == 0;
969
970
984 pos = info.size() - 1;
985 if (info.endsWith(
']') && !(info.startsWith(
'+') || info.startsWith(
'-'))) {
987 if (info.at(pos) ==
'[') {
992 if (info.endsWith(
' ')) {
998 static const char operator_call[] =
"operator()";
999 static const char operator_lessThan[] =
"operator<";
1000 static const char operator_greaterThan[] =
"operator>";
1001 static const char operator_lessThanEqual[] =
"operator<=";
1002 static const char operator_greaterThanEqual[] =
"operator>=";
1005 info.replace(
"operator ",
"operator");
1011 pos = info.lastIndexOf(
')', pos);
1016 if (info.indexOf(
'>', pos) != -1
1017 || info.indexOf(
':', pos) != -1) {
1026 while (pos && parencount) {
1027 if (info.at(pos) ==
')')
1029 else if (info.at(pos) ==
'(')
1033 if (parencount != 0)
1036 info.truncate(++pos);
1038 if (info.at(pos - 1) ==
')') {
1039 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
1045 info.remove(0, info.indexOf(
'('));
1055 int templatecount = 0;
1060 switch (info.at(pos)) {
1062 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
1066 if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
1070 if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
1074 auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
1075 if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
1077 else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
1087 if (parencount < 0 || templatecount < 0)
1090 char c = info.at(pos);
1099 else if (c ==
' ' && templatecount == 0 && parencount == 0)
1104 info = info.mid(pos + 1);
1107 while ((info.at(0) ==
'*')
1108 || (info.at(0) ==
'&'))
1113 while ((pos = info.lastIndexOf(
'>')) != -1) {
1114 if (!info.contains(
'<'))
1118 qsizetype end = pos;
1121 while (pos && templatecount) {
1122 char c = info.at(pos);
1130 info.remove(pos, end - pos + 1);
1167 const char *
const defaultTokens[] = {
1180 Q_ASSERT(!literals);
1182 auto ptr =
new const char *[
std::size(defaultTokens) + 1];
1183 auto end =
std::copy(
std::begin(defaultTokens),
std::end(defaultTokens), ptr);
1199#ifdef QLOGGING_HAVE_BACKTRACE
1221Q_CONSTINIT QBasicMutex QMessagePattern::mutex;
1225 const QString envPattern = qEnvironmentVariable(
"QT_MESSAGE_PATTERN");
1226 if (envPattern.isEmpty()) {
1240 QVarLengthArray<QStringView, 16> lexemes;
1241 qsizetype literalLexemeCount = 0;
1242 qsizetype lexemeStart = 0;
1243 bool inPlaceholder =
false;
1244 for (qsizetype i = 0; i < pattern.size(); ++i) {
1245 const QChar c = pattern.at(i);
1246 if (c == u'%' && !inPlaceholder) {
1247 if ((i + 1 < pattern.size())
1248 && pattern.at(i + 1) == u'{') {
1250 if (lexemeStart != i) {
1251 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1252 pattern.cbegin() + i));
1253 ++literalLexemeCount;
1256 inPlaceholder =
true;
1260 if (c == u'}' && inPlaceholder) {
1263 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1264 pattern.cbegin() + i + 1));
1265 lexemeStart = i + 1;
1266 inPlaceholder =
false;
1269 if (lexemeStart < pattern.size()) {
1270 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1272 ++literalLexemeCount;
1278 QList<QString> newTimeArgs;
1279#ifdef QLOGGING_HAVE_BACKTRACE
1280 QList<BacktraceParams> newBacktraceArgs;
1281 int newMaxBacktraceDepth = 0;
1284 auto newLiterals = std::make_unique<std::unique_ptr<
const char[]>[]>(literalLexemeCount + 1);
1285 auto newTokens =
std::make_unique<
const char *[]>(lexemes.size() + 1);
1286 newTokens[lexemes.size()] =
nullptr;
1288 bool nestedIfError =
false;
1291 qsizetype literalLexemeIndex = 0;
1293 for (qsizetype i = 0; i < lexemes.size(); ++i) {
1294 const QStringView lexeme = lexemes.at(i);
1295 if (lexeme.startsWith(
"%{"_L1) && lexeme.endsWith(u'}')) {
1297 if (lexeme == QLatin1StringView(
typeTokenC)) {
1303 else if (lexeme == QLatin1StringView(
fileTokenC))
1305 else if (lexeme == QLatin1StringView(
lineTokenC))
1309 else if (lexeme == QLatin1StringView(
pidTokenC))
1319 else if (lexeme.startsWith(QLatin1StringView(
timeTokenC))) {
1321 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(
' '));
1323 newTimeArgs.append(QString(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2)));
1325 newTimeArgs.append(QString());
1327#ifdef QLOGGING_HAVE_BACKTRACE
1328 newTokens[i] = backtraceTokenC;
1329 QString backtraceSeparator = QStringLiteral(
"|");
1330 int backtraceDepth = 5;
1331 static const QRegularExpression depthRx(QStringLiteral(
" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1332 static const QRegularExpression separatorRx(QStringLiteral(
" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1333 QRegularExpressionMatch m = depthRx.matchView(lexeme);
1335 int depth = m.capturedView(1).toInt();
1337 error +=
"QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1339 backtraceDepth = std::min(depth, QInternalMessageLogContext::MaxBacktraceDepth);
1341 m = separatorRx.matchView(lexeme);
1343 backtraceSeparator = m.captured(1);
1344 BacktraceParams backtraceParams;
1345 backtraceParams.backtraceDepth = backtraceDepth;
1346 backtraceParams.backtraceSeparator = backtraceSeparator;
1347 newBacktraceArgs.append(backtraceParams);
1348 newMaxBacktraceDepth = qMax(newMaxBacktraceDepth, backtraceDepth);
1350 error +=
"QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1355#define IF_TOKEN(LEVEL)
1356 else if (lexeme == QLatin1StringView(LEVEL)) {
1358 nestedIfError = true;
1359 newTokens[i] = LEVEL;
1369 else if (lexeme == QLatin1StringView(
endifTokenC)) {
1371 if (!inIf && !nestedIfError)
1372 error +=
"QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1376 error +=
"QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme +
'\n'_L1;
1379 Q_ASSERT(literalLexemeIndex < literalLexemeCount);
1380 using UP = std::unique_ptr<
char[]>;
1381 newLiterals[literalLexemeIndex] = UP(qstrdup(lexeme.toUtf8().constData()));
1382 newTokens[i] = newLiterals[literalLexemeIndex].get();
1383 ++literalLexemeIndex;
1387 error +=
"QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1389 error +=
"QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1391 if (!error.isEmpty()) {
1396 "QMessagePattern::setPattern", nullptr);
1397 preformattedMessageHandler(QtWarningMsg, ctx, error);
1400 literals = std::move(newLiterals);
1401 tokens = std::move(newTokens);
1402 timeArgs = std::move(newTimeArgs);
1403#ifdef QLOGGING_HAVE_BACKTRACE
1404 backtraceArgs = std::move(newBacktraceArgs);
1405 maxBacktraceDepth = newMaxBacktraceDepth;
1409#if defined(QLOGGING_HAVE_BACKTRACE)
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422static constexpr int TypicalBacktraceFrameCount = 3;
1423static constexpr const char *QtCoreLibraryName =
"Qt" QT_STRINGIFY(QT_VERSION_MAJOR)
"Core";
1425#if defined(QLOGGING_USE_STD_BACKTRACE)
1426Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1428 assert(frameCount >= 0);
1429 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1433backtraceFramesForLogMessage(
int frameCount,
1434 const QInternalMessageLogContext::BacktraceStorage &buffer)
1437 result.reserve(buffer.size());
1439 const auto shouldSkipFrame = [](QByteArrayView description)
1441#if defined(_MSVC_STL_VERSION)
1442 const auto libraryNameEnd = description.indexOf(
'!');
1443 if (libraryNameEnd != -1) {
1444 const auto libraryName = description.first(libraryNameEnd);
1445 if (!libraryName.contains(QtCoreLibraryName))
1449 if (description.contains(
"populateBacktrace"))
1451 if (description.contains(
"QInternalMessageLogContext"))
1453 if (description.contains(
"~QDebug"))
1458 for (
const auto &entry : buffer) {
1459 const std::string description = entry.description();
1460 if (result.isEmpty() && shouldSkipFrame(description))
1462 result.append(QString::fromStdString(description));
1468#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1470Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1472 assert(frameCount >= 0);
1473 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1474 Q_ASSERT(result.size() ==
int(result.size()));
1475 int n = ::backtrace(result.data(),
int(result.size()));
1483backtraceFramesForLogMessage(
int frameCount,
1484 const QInternalMessageLogContext::BacktraceStorage &buffer)
1486 struct DecodedFrame {
1492 if (frameCount == 0)
1495 auto shouldSkipFrame = [&result](
const auto &library,
const auto &function) {
1496 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1498 if (function.isEmpty())
1500 if (function.contains(
"6QDebug"_L1))
1502 if (function.contains(
"14QMessageLogger"_L1))
1504 if (function.contains(
"17qt_message_output"_L1))
1506 if (function.contains(
"26QInternalMessageLogContext"_L1))
1511 auto demangled = [](
auto &function) -> QString {
1512 if (!function.startsWith(
"_Z"_L1))
1517 if constexpr (
sizeof(function.at(0)) == 1)
1518 return function.data();
1520 return std::move(function).toUtf8();
1522 auto cleanup = [](
auto *p) { free(p); };
1523 using Ptr = std::unique_ptr<
char,
decltype(cleanup)>;
1524 auto demangled = Ptr(abi::__cxa_demangle(fn,
nullptr,
nullptr,
nullptr), cleanup);
1527 return QString::fromUtf8(qCleanupFuncinfo(demangled.get()));
1529 return QString::fromUtf8(fn);
1532# if QT_CONFIG(dladdr)
1534 QString cachedLibrary;
1535 const char *cachedFname =
nullptr;
1536 auto decodeFrame = [&](
void *addr) -> DecodedFrame {
1538 if (!dladdr(addr, &info))
1542 QLatin1StringView fn(info.dli_sname);
1543 QLatin1StringView lib;
1544 if (
const char *lastSlash = strrchr(info.dli_fname,
'/'))
1545 lib = QLatin1StringView(lastSlash + 1);
1547 lib = QLatin1StringView(info.dli_fname);
1549 if (shouldSkipFrame(lib, fn))
1552 QString function = demangled(fn);
1553 if (lib.data() != cachedFname) {
1554 cachedFname = lib.data();
1555 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1557 return { cachedLibrary, function };
1565 static const QRegularExpression rx(QStringLiteral(
"^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1567 auto decodeFrame = [&](
void *&addr) -> DecodedFrame {
1568 auto cleanup = [](
auto *p) { free(p); };
1570 std::unique_ptr<
char *,
decltype(cleanup)>(backtrace_symbols(&addr, 1), cleanup);
1571 QString trace = QString::fromUtf8(strings.get()[0]);
1572 QRegularExpressionMatch m = rx.match(trace);
1576 QString library = m.captured(1);
1577 QString function = m.captured(2);
1580 if (shouldSkipFrame(library, function))
1583 function = demangled(function);
1584 return { library, function };
1588 for (
void *
const &addr : buffer) {
1589 DecodedFrame frame = decodeFrame(addr);
1590 if (!frame.library.isEmpty()) {
1591 if (frame.function.isEmpty())
1592 result.append(u'?' + frame.library + u'?');
1594 result.append(frame.function);
1597 if (!result.isEmpty())
1598 result.append(QStringLiteral(
"???"));
1601 if (result.size() == frameCount)
1607#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1611
1612
1613
1614static QStringList generateBacktraceFrames(
int frameCount,
const QMessageLogContext &ctx)
1617 if (ctx.version <= QMessageLogContext::CurrentVersion)
1620 auto &fullctx =
static_cast<
const QInternalMessageLogContext &>(ctx);
1621 if (!fullctx.backtrace.has_value())
1624 QStringList frames = backtraceFramesForLogMessage(frameCount, *fullctx.backtrace);
1625 if (frames.isEmpty())
1629 if (ctx.function && frames.at(0).startsWith(u'?'))
1630 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1635static QString formatBacktraceForLogMessage(
const QMessagePattern::BacktraceParams backtraceParams,
1636 const QStringList &backtrace)
1638 if (backtrace.isEmpty() || backtraceParams.backtraceDepth <= 0)
1641 const qsizetype backtraceDepth = (std::min)(qsizetype(backtraceParams.backtraceDepth),
1646 for (
auto it = backtrace.cbegin(); it != backtrace.cbegin() + backtraceDepth; ++it) {
1647 if (it != backtrace.cbegin())
1648 result += backtraceParams.backtraceSeparator;
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1679 return formatLogMessage(type, context, str);
1694 message.append(str);
1700 qsizetype timeArgsIdx = 0;
1701#ifdef QLOGGING_HAVE_BACKTRACE
1702 qsizetype backtraceArgsIdx = 0;
1703 QStringList fullBacktrace;
1707 for (qsizetype i = 0; pattern->tokens[i]; ++i) {
1708 const char *token = pattern->tokens[i];
1714 if (token == timeTokenC)
1716#ifdef QLOGGING_HAVE_BACKTRACE
1717 else if (token == backtraceTokenC)
1721 message.append(str);
1723 message.append(QUtf8StringView(context
.category));
1726 case QtDebugMsg: message.append(
"debug"_L1);
break;
1727 case QtInfoMsg: message.append(
"info"_L1);
break;
1728 case QtWarningMsg: message.append(
"warning"_L1);
break;
1730 case QtFatalMsg: message.append(
"fatal"_L1);
break;
1734 message.append(QUtf8StringView(context
.file));
1736 message.append(
"unknown"_L1);
1738 message.append(QString::number(context.line));
1741 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1743 message.append(
"unknown"_L1);
1745 message.append(QString::number(QCoreApplication::applicationPid()));
1747 message.append(QCoreApplication::applicationName());
1750 message.append(QString::number(qt_gettid()));
1752 if (!qt_append_thread_name_to(message))
1753 message.append(QString::number(qt_gettid()));
1755 message.append(
"0x"_L1);
1756 message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1757#ifdef QLOGGING_HAVE_BACKTRACE
1758 }
else if (token == backtraceTokenC) {
1759 if (fullBacktrace.isEmpty())
1760 fullBacktrace = generateBacktraceFrames(pattern->maxBacktraceDepth, context);
1761 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1763 message.append(formatBacktraceForLogMessage(backtraceParams, fullBacktrace));
1766 using namespace std::chrono;
1767 auto formatElapsedTime = [](steady_clock::duration time) {
1769 auto ms = duration_cast<milliseconds>(time);
1770 auto sec = duration_cast<seconds>(ms);
1772 return QString::asprintf(
"%6lld.%03u", qint64(sec.count()), uint(ms.count()));
1774 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1776 if (timeFormat ==
"process"_L1) {
1777 message += formatElapsedTime(steady_clock::now() - pattern->appStartTime);
1778 }
else if (timeFormat ==
"boot"_L1) {
1781 message += formatElapsedTime(steady_clock::now().time_since_epoch());
1782#if QT_CONFIG(datestring)
1783 }
else if (timeFormat.isEmpty()) {
1784 message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1786 message.append(QDateTime::currentDateTime().toString(timeFormat));
1792#define HANDLE_IF_TOKEN(LEVEL)
1793 } else if (token == if##LEVEL##TokenC) {
1794 skip = type != Qt##LEVEL##Msg;
1800#undef HANDLE_IF_TOKEN
1802 message.append(QUtf8StringView(token));
1811Q_CONSTINIT
static QBasicAtomicPointer<
void (QtMsgType,
const QMessageLogContext &,
const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(
nullptr);
1817#define QT_LOG_CODE 9000
1820static bool slog2_default_handler(QtMsgType type,
const QMessageLogContext &,
1821 const QString &message)
1823 if (shouldLogToStderr())
1826 QString formattedMessage = message;
1827 formattedMessage.append(u'\n');
1828 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1829 slog2_buffer_set_config_t buffer_config;
1830 slog2_buffer_t buffer_handle;
1832 buffer_config.buffer_set_name = __progname;
1833 buffer_config.num_buffers = 1;
1834 buffer_config.verbosity_level = SLOG2_DEBUG1;
1835 buffer_config.buffer_config[0].buffer_name =
"default";
1836 buffer_config.buffer_config[0].num_pages = 8;
1838 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1839 fprintf(stderr,
"Error registering slogger2 buffer!\n");
1844 slog2_set_default_buffer(buffer_handle);
1846 int severity = SLOG2_INFO;
1850 severity = SLOG2_DEBUG1;
1853 severity = SLOG2_INFO;
1856 severity = SLOG2_NOTICE;
1859 severity = SLOG2_WARNING;
1862 severity = SLOG2_ERROR;
1866 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1872#if QT_CONFIG(journald)
1873static bool systemd_default_message_handler(QtMsgType type,
1874 const QMessageLogContext &context,
1875 const QString &message)
1877 if (shouldLogToStderr())
1880 int priority = LOG_INFO;
1883 priority = LOG_DEBUG;
1886 priority = LOG_INFO;
1889 priority = LOG_WARNING;
1892 priority = LOG_CRIT;
1895 priority = LOG_ALERT;
1900 const QByteArray messageField =
"MESSAGE="_ba + message.toUtf8();
1901 const QByteArray priorityField =
"PRIORITY="_ba + QByteArray::number(priority);
1902 const QByteArray tidField =
"TID="_ba + QByteArray::number(qlonglong(qt_gettid()));
1903 const QByteArray fileField = context.file
1904 ?
"CODE_FILE="_ba + context.file : QByteArray();
1905 const QByteArray funcField = context.function
1906 ?
"CODE_FUNC="_ba + context.function : QByteArray();
1907 const QByteArray lineField = context.line
1908 ?
"CODE_LINE="_ba + QByteArray::number(context.line) : QByteArray();
1909 const QByteArray categoryField = context.category
1910 ?
"QT_CATEGORY="_ba + context.category : QByteArray();
1912 auto toIovec = [](
const QByteArray &ba) {
1913 return iovec{
const_cast<
char*>(ba.data()), size_t(ba.size()) };
1916 struct iovec fields[7] = {
1917 toIovec(messageField),
1918 toIovec(priorityField),
1923 fields[nFields++] = toIovec(fileField);
1924 if (context.function)
1925 fields[nFields++] = toIovec(funcField);
1927 fields[nFields++] = toIovec(lineField);
1928 if (context.category)
1929 fields[nFields++] = toIovec(categoryField);
1931 sd_journal_sendv(fields, nFields);
1937#if QT_CONFIG(syslog)
1938static bool syslog_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
1939 const QString &formattedMessage)
1941 if (shouldLogToStderr())
1944 int priority = LOG_INFO;
1947 priority = LOG_DEBUG;
1950 priority = LOG_INFO;
1953 priority = LOG_WARNING;
1956 priority = LOG_CRIT;
1959 priority = LOG_ALERT;
1963 syslog(priority,
"%s", formattedMessage.toUtf8().constData());
1970static bool android_default_message_handler(QtMsgType type,
1971 const QMessageLogContext &context,
1972 const QString &formattedMessage)
1974 if (shouldLogToStderr())
1977 android_LogPriority priority = ANDROID_LOG_DEBUG;
1980 priority = ANDROID_LOG_DEBUG;
1983 priority = ANDROID_LOG_INFO;
1986 priority = ANDROID_LOG_WARN;
1989 priority = ANDROID_LOG_ERROR;
1992 priority = ANDROID_LOG_FATAL;
1996 QMessagePattern *pattern = qMessagePattern();
1997 const QString tag = (pattern && pattern->containsToken(categoryTokenC))
1999 ? QCoreApplication::applicationName().replace(u' ', u'_')
2000 : QString::fromUtf8(context.category);
2001 __android_log_print(priority, qPrintable(tag),
"%s\n", qPrintable(formattedMessage));
2007#if defined(Q_OS_OHOS)
2008static bool ohos_default_message_handler(QtMsgType type,
2009 const QMessageLogContext &context,
2010 const QString &message)
2012 QString formattedMessage = qFormatLogMessage(type, context, message);
2014 LogLevel priority = LOG_DEBUG;
2016 case QtDebugMsg: priority = LOG_DEBUG;
break;
2017 case QtInfoMsg: priority = LOG_INFO;
break;
2018 case QtWarningMsg: priority = LOG_WARN;
break;
2019 case QtCriticalMsg: priority = LOG_ERROR;
break;
2020 case QtFatalMsg: priority = LOG_FATAL;
break;
2023 qOhosLogMessage(priority, qPrintable(QCoreApplication::applicationName()), qPrintable(formattedMessage));
2030static void win_outputDebugString_helper(
const QString &message)
2032 const qsizetype maxOutputStringLength = 32766;
2033 Q_CONSTINIT
static QBasicMutex m;
2034 const auto locker = qt_scoped_lock(m);
2037 if (message.length() <= maxOutputStringLength) {
2038 OutputDebugString(
reinterpret_cast<
const wchar_t *>(message.utf16()));
2040 wchar_t *messagePart =
new wchar_t[maxOutputStringLength + 1];
2041 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
2042 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
2043 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
2044 Q_ASSERT(len == length);
2045 messagePart[len] = 0;
2046 OutputDebugString(messagePart);
2048 delete[] messagePart;
2052static bool win_message_handler(QtMsgType,
const QMessageLogContext &,
2053 const QString &formattedMessage)
2055 if (shouldLogToStderr())
2058 win_outputDebugString_helper(formattedMessage + u'\n');
2065static bool wasm_default_message_handler(QtMsgType type,
2066 const QMessageLogContext &,
2067 const QString &formattedMessage)
2069 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
2070 if (forceStderrLogging)
2073 int emOutputFlags = EM_LOG_CONSOLE;
2074 QByteArray localMsg = formattedMessage.toLocal8Bit();
2081 emOutputFlags |= EM_LOG_WARN;
2084 emOutputFlags |= EM_LOG_ERROR;
2087 emOutputFlags |= EM_LOG_ERROR;
2089 emscripten_log(emOutputFlags,
"%s\n", qPrintable(formattedMessage));
2098 const QString &formattedMessage)
2105 if (formattedMessage.isNull())
2107 const QByteArray msg = formattedMessage.toLocal8Bit() +
'\n';
2108 fwrite(msg.constData(), 1, msg.size(), stderr);
2113struct SystemMessageSink
2117 bool messageIsUnformatted =
false;
2122#if defined(Q_OS_WIN)
2124#elif QT_CONFIG(slog2)
2125 slog2_default_handler
2126#elif QT_CONFIG(journald)
2127 systemd_default_message_handler,
true
2128#elif QT_CONFIG(syslog)
2129 syslog_default_message_handler
2130#elif defined(Q_OS_ANDROID)
2131 android_default_message_handler
2132# elif defined(Q_OS_OHOS)
2133 ohos_default_message_handler
2134#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
2135 AppleUnifiedLogger::messageHandler,
true
2136#elif defined Q_OS_WASM
2137 wasm_default_message_handler
2144 const QString &formattedMessage)
2148QT_WARNING_DISABLE_GCC(
"-Waddress")
2149 if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
2158
2159
2161 const QString &message)
2172 preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
2197 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2198 if (!defaultCategory->isEnabled(msgType))
2207 auto msgHandler = messageHandler.loadAcquire();
2214template <
typename String>
static void
2219#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2220 wchar_t contextFileL[256];
2224 convert_to_wchar_t_elided(contextFileL,
sizeof contextFileL /
sizeof *contextFileL,
2227 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2228 _CrtSetReportMode(_CRT_ERROR, reportMode);
2230 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2231 reinterpret_cast<
const wchar_t *>(message.utf16()));
2232 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2240 if constexpr (
std::is_class_v<String> && !
std::is_const_v<String>)
2248
2249
2253 qt_message_print(msgType, ctx, message);
2254 qt_maybe_message_fatal(msgType, ctx, message);
2261 QString error_string = qt_error_string(-1);
2265 QString buf = QString::vasprintf(msg, ap);
2268 buf +=
" ("_L1 + error_string + u')';
2270 qt_message_output(QtWarningMsg, context, buf);
2279 QString buf = QString::vasprintf(msg, ap);
2282 buf +=
" ("_L1 + qt_error_string(code) + u')';
2284 qt_message_output(QtWarningMsg, context, buf);
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
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
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
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
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2464 const auto old = messageHandler.fetchAndStoreOrdered(h);
2475 if (!qMessagePattern()->fromEnvironment)
2476 qMessagePattern()->setPattern(pattern);
2482 if (logContext.version == self->version) {
2483 auto other =
static_cast<
const QInternalMessageLogContext *>(&logContext);
2484 self->backtrace = other->backtrace;
2489
2490
2491
2492
2495 version = CurrentVersion + 1;
2496 copyContextFrom(logContext);
2498#ifdef QLOGGING_HAVE_BACKTRACE
2499 if (backtrace.has_value())
2503 if (
auto pattern = qMessagePattern())
2504 return pattern->maxBacktraceDepth;
2511
2512
2513
2514
2515
2516
2517
2524 if (Q_UNLIKELY(version == CurrentVersion + 1))
2525 copyInternalContext(
static_cast<QInternalMessageLogContext *>(
this), logContext);
2530
2531
2532
2533
2534
2537
2538
2539
2540
2541
2543
2544
2545
2546
2547
2548
2549
2552
2553
2554
2555
2556
2557
2558
2561
2562
2563
2564
2565
2568
2569
2570
2571
2572
2573
2574
2575
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
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 constexpr SystemMessageSink systemMessageSink
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 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