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_HARMONY)
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_ASSUME_STDERR_HAS_CONSOLE"))
306 return GetConsoleWindow();
307#elif defined(Q_OS_UNIX)
309# define _PATH_TTY "/dev/tty"
314 if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
315 qt_safe_close(ttyDevice);
317 }
else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
319 return isatty(STDERR_FILENO);
328 return stderrHasConsoleAttached;
335
336
337
338
339
340
341
342
345 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
357
358
359
360
361
362
363
364
365
366
367
368
369
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
390#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
391static inline void convert_to_wchar_t_elided(
wchar_t *d, size_t space,
const char *s)
noexcept
393 size_t len = qstrlen(s);
394 if (len + 1 > space) {
395 const size_t skip = len - space + 4;
398 for (
int i = 0; i < 3; ++i)
408
409
413 QString buf = QString::vasprintf(msg, ap);
414 qt_message_print(msgType, context, buf);
415 qt_maybe_message_fatal(msgType, context, buf);
419
420
421
422
423
424void QMessageLogger::debug(
const char *msg, ...)
const
426 QInternalMessageLogContext ctxt(context);
429 qt_message(QtDebugMsg, ctxt, msg, ap);
434
435
436
437
438
439
440void QMessageLogger::info(
const char *msg, ...)
const
442 QInternalMessageLogContext ctxt(context);
445 qt_message(QtInfoMsg, ctxt, msg, ap);
450
451
452
453
454
455
456
457
458
459
460
461
462
463
466
467
468
469
470
471
472void QMessageLogger::debug(
const QLoggingCategory &cat,
const char *msg, ...)
const
474 if (!cat.isDebugEnabled())
477 QInternalMessageLogContext ctxt(context, cat());
481 qt_message(QtDebugMsg, ctxt, msg, ap);
486
487
488
489
490
491
492void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
493 const char *msg, ...)
const
495 const QLoggingCategory &cat = (*catFunc)();
496 if (!cat.isDebugEnabled())
499 QInternalMessageLogContext ctxt(context, cat());
503 qt_message(QtDebugMsg, ctxt, msg, ap);
507#ifndef QT_NO_DEBUG_STREAM
510
511
512
513
514QDebug QMessageLogger::debug()
const
516 QDebug dbg = QDebug(QtDebugMsg);
517 QMessageLogContext &ctxt = dbg.stream->context;
518 ctxt.copyContextFrom(context);
523
524
525
526
527
528QDebug QMessageLogger::debug(
const QLoggingCategory &cat)
const
530 QDebug dbg = QDebug(QtDebugMsg);
531 if (!cat.isDebugEnabled())
532 dbg.stream->message_output =
false;
534 QMessageLogContext &ctxt = dbg.stream->context;
535 ctxt.copyContextFrom(context);
536 ctxt.category = cat.categoryName();
542
543
544
545
546
547QDebug QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc)
const
549 return debug((*catFunc)());
554
555
556
557
558
559
560void QMessageLogger::info(
const QLoggingCategory &cat,
const char *msg, ...)
const
562 if (!cat.isInfoEnabled())
565 QInternalMessageLogContext ctxt(context, cat());
569 qt_message(QtInfoMsg, ctxt, msg, ap);
574
575
576
577
578
579
580void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
581 const char *msg, ...)
const
583 const QLoggingCategory &cat = (*catFunc)();
584 if (!cat.isInfoEnabled())
587 QInternalMessageLogContext ctxt(context, cat());
591 qt_message(QtInfoMsg, ctxt, msg, ap);
595#ifndef QT_NO_DEBUG_STREAM
598
599
600
601
602
603QDebug QMessageLogger::info()
const
605 QDebug dbg = QDebug(QtInfoMsg);
606 QMessageLogContext &ctxt = dbg.stream->context;
607 ctxt.copyContextFrom(context);
612
613
614
615
616
617QDebug QMessageLogger::info(
const QLoggingCategory &cat)
const
619 QDebug dbg = QDebug(QtInfoMsg);
620 if (!cat.isInfoEnabled())
621 dbg.stream->message_output =
false;
623 QMessageLogContext &ctxt = dbg.stream->context;
624 ctxt.copyContextFrom(context);
625 ctxt.category = cat.categoryName();
631
632
633
634
635
636QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc)
const
638 return info((*catFunc)());
644
645
646
647
648
649void QMessageLogger::warning(
const char *msg, ...)
const
651 QInternalMessageLogContext ctxt(context);
654 qt_message(QtWarningMsg, ctxt, msg, ap);
659
660
661
662
663
664
665void QMessageLogger::warning(
const QLoggingCategory &cat,
const char *msg, ...)
const
667 if (!cat.isWarningEnabled())
670 QInternalMessageLogContext ctxt(context, cat());
674 qt_message(QtWarningMsg, ctxt, msg, ap);
679
680
681
682
683
684
685void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
686 const char *msg, ...)
const
688 const QLoggingCategory &cat = (*catFunc)();
689 if (!cat.isWarningEnabled())
692 QInternalMessageLogContext ctxt(context, cat());
696 qt_message(QtWarningMsg, ctxt, msg, ap);
700#ifndef QT_NO_DEBUG_STREAM
702
703
704
705
706QDebug QMessageLogger::warning()
const
708 QDebug dbg = QDebug(QtWarningMsg);
709 QMessageLogContext &ctxt = dbg.stream->context;
710 ctxt.copyContextFrom(context);
715
716
717
718
719QDebug QMessageLogger::warning(
const QLoggingCategory &cat)
const
721 QDebug dbg = QDebug(QtWarningMsg);
722 if (!cat.isWarningEnabled())
723 dbg.stream->message_output =
false;
725 QMessageLogContext &ctxt = dbg.stream->context;
726 ctxt.copyContextFrom(context);
727 ctxt.category = cat.categoryName();
733
734
735
736
737
738QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc)
const
740 return warning((*catFunc)());
746
747
748
749
750
751void QMessageLogger::critical(
const char *msg, ...)
const
753 QInternalMessageLogContext ctxt(context);
756 qt_message(QtCriticalMsg, ctxt, msg, ap);
761
762
763
764
765
766
767void QMessageLogger::critical(
const QLoggingCategory &cat,
const char *msg, ...)
const
769 if (!cat.isCriticalEnabled())
772 QInternalMessageLogContext ctxt(context, cat());
776 qt_message(QtCriticalMsg, ctxt, msg, ap);
781
782
783
784
785
786
787void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
788 const char *msg, ...)
const
790 const QLoggingCategory &cat = (*catFunc)();
791 if (!cat.isCriticalEnabled())
794 QInternalMessageLogContext ctxt(context, cat());
798 qt_message(QtCriticalMsg, ctxt, msg, ap);
802#ifndef QT_NO_DEBUG_STREAM
804
805
806
807
808QDebug QMessageLogger::critical()
const
810 QDebug dbg = QDebug(QtCriticalMsg);
811 QMessageLogContext &ctxt = dbg.stream->context;
812 ctxt.copyContextFrom(context);
817
818
819
820
821
822QDebug QMessageLogger::critical(
const QLoggingCategory &cat)
const
824 QDebug dbg = QDebug(QtCriticalMsg);
825 if (!cat.isCriticalEnabled())
826 dbg.stream->message_output =
false;
828 QMessageLogContext &ctxt = dbg.stream->context;
829 ctxt.copyContextFrom(context);
830 ctxt.category = cat.categoryName();
836
837
838
839
840
841QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc)
const
843 return critical((*catFunc)());
849
850
851
852
853
854
855void QMessageLogger::fatal(
const QLoggingCategory &cat,
const char *msg, ...)
const noexcept
857 QInternalMessageLogContext ctxt(context, cat());
861 qt_message(QtFatalMsg, ctxt, msg, ap);
864#ifndef Q_CC_MSVC_ONLY
870
871
872
873
874
875
876void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
877 const char *msg, ...)
const noexcept
879 const QLoggingCategory &cat = (*catFunc)();
881 QInternalMessageLogContext ctxt(context, cat());
885 qt_message(QtFatalMsg, ctxt, msg, ap);
888#ifndef Q_CC_MSVC_ONLY
894
895
896
897
898
899void QMessageLogger::fatal(
const char *msg, ...)
const noexcept
901 QInternalMessageLogContext ctxt(context);
904 qt_message(QtFatalMsg, ctxt, msg, ap);
907#ifndef Q_CC_MSVC_ONLY
912#ifndef QT_NO_DEBUG_STREAM
914
915
916
917
918
919
920QDebug QMessageLogger::fatal()
const
922 QDebug dbg = QDebug(QtFatalMsg);
923 QMessageLogContext &ctxt = dbg.stream->context;
924 ctxt.copyContextFrom(context);
929
930
931
932
933
934QDebug QMessageLogger::fatal(
const QLoggingCategory &cat)
const
936 QDebug dbg = QDebug(QtFatalMsg);
938 QMessageLogContext &ctxt = dbg.stream->context;
939 ctxt.copyContextFrom(context);
940 ctxt.category = cat.categoryName();
946
947
948
949
950
951QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc)
const
953 return fatal((*catFunc)());
959 return !category || strcmp(category, QLoggingRegistry::defaultCategoryName) == 0;
963
964
978 pos = info.size() - 1;
979 if (info.endsWith(
']') && !(info.startsWith(
'+') || info.startsWith(
'-'))) {
981 if (info.at(pos) ==
'[') {
986 if (info.endsWith(
' ')) {
992 static const char operator_call[] =
"operator()";
993 static const char operator_lessThan[] =
"operator<";
994 static const char operator_greaterThan[] =
"operator>";
995 static const char operator_lessThanEqual[] =
"operator<=";
996 static const char operator_greaterThanEqual[] =
"operator>=";
999 info.replace(
"operator ",
"operator");
1005 pos = info.lastIndexOf(
')', pos);
1010 if (info.indexOf(
'>', pos) != -1
1011 || info.indexOf(
':', pos) != -1) {
1020 while (pos && parencount) {
1021 if (info.at(pos) ==
')')
1023 else if (info.at(pos) ==
'(')
1027 if (parencount != 0)
1030 info.truncate(++pos);
1032 if (info.at(pos - 1) ==
')') {
1033 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
1039 info.remove(0, info.indexOf(
'('));
1049 int templatecount = 0;
1054 switch (info.at(pos)) {
1056 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
1060 if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
1064 if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
1068 auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
1069 if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
1071 else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
1081 if (parencount < 0 || templatecount < 0)
1084 char c = info.at(pos);
1093 else if (c ==
' ' && templatecount == 0 && parencount == 0)
1098 info = info.mid(pos + 1);
1101 while ((info.at(0) ==
'*')
1102 || (info.at(0) ==
'&'))
1107 while ((pos = info.lastIndexOf(
'>')) != -1) {
1108 if (!info.contains(
'<'))
1112 qsizetype end = pos;
1115 while (pos && templatecount) {
1116 char c = info.at(pos);
1124 info.remove(pos, end - pos + 1);
1161 const char *
const defaultTokens[] = {
1174 Q_ASSERT(!literals);
1176 auto ptr =
new const char *[
std::size(defaultTokens) + 1];
1177 auto end =
std::copy(
std::begin(defaultTokens),
std::end(defaultTokens), ptr);
1193#ifdef QLOGGING_HAVE_BACKTRACE
1215Q_CONSTINIT QBasicMutex QMessagePattern::mutex;
1219 const QString envPattern = qEnvironmentVariable(
"QT_MESSAGE_PATTERN");
1220 if (envPattern.isEmpty()) {
1234 QVarLengthArray<QStringView, 16> lexemes;
1235 qsizetype literalLexemeCount = 0;
1236 qsizetype lexemeStart = 0;
1237 bool inPlaceholder =
false;
1238 for (qsizetype i = 0; i < pattern.size(); ++i) {
1239 const QChar c = pattern.at(i);
1240 if (c == u'%' && !inPlaceholder) {
1241 if ((i + 1 < pattern.size())
1242 && pattern.at(i + 1) == u'{') {
1244 if (lexemeStart != i) {
1245 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1246 pattern.cbegin() + i));
1247 ++literalLexemeCount;
1250 inPlaceholder =
true;
1254 if (c == u'}' && inPlaceholder) {
1257 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1258 pattern.cbegin() + i + 1));
1259 lexemeStart = i + 1;
1260 inPlaceholder =
false;
1263 if (lexemeStart < pattern.size()) {
1264 lexemes.append(QStringView(pattern.cbegin() + lexemeStart,
1266 ++literalLexemeCount;
1272 QList<QString> newTimeArgs;
1273#ifdef QLOGGING_HAVE_BACKTRACE
1274 QList<BacktraceParams> newBacktraceArgs;
1275 int newMaxBacktraceDepth = 0;
1278 auto newLiterals = std::make_unique<std::unique_ptr<
const char[]>[]>(literalLexemeCount + 1);
1279 auto newTokens =
std::make_unique<
const char *[]>(lexemes.size() + 1);
1280 newTokens[lexemes.size()] =
nullptr;
1282 bool nestedIfError =
false;
1285 qsizetype literalLexemeIndex = 0;
1287 for (qsizetype i = 0; i < lexemes.size(); ++i) {
1288 const QStringView lexeme = lexemes.at(i);
1289 if (lexeme.startsWith(
"%{"_L1) && lexeme.endsWith(u'}')) {
1291 if (lexeme == QLatin1StringView(
typeTokenC)) {
1297 else if (lexeme == QLatin1StringView(
fileTokenC))
1299 else if (lexeme == QLatin1StringView(
lineTokenC))
1303 else if (lexeme == QLatin1StringView(
pidTokenC))
1313 else if (lexeme.startsWith(QLatin1StringView(
timeTokenC))) {
1315 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(
' '));
1317 newTimeArgs.append(QString(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2)));
1319 newTimeArgs.append(QString());
1321#ifdef QLOGGING_HAVE_BACKTRACE
1322 newTokens[i] = backtraceTokenC;
1323 QString backtraceSeparator = QStringLiteral(
"|");
1324 int backtraceDepth = 5;
1325 static const QRegularExpression depthRx(QStringLiteral(
" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1326 static const QRegularExpression separatorRx(QStringLiteral(
" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1327 QRegularExpressionMatch m = depthRx.matchView(lexeme);
1329 int depth = m.capturedView(1).toInt();
1331 error +=
"QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1333 backtraceDepth = std::min(depth, QInternalMessageLogContext::MaxBacktraceDepth);
1335 m = separatorRx.matchView(lexeme);
1337 backtraceSeparator = m.captured(1);
1338 BacktraceParams backtraceParams;
1339 backtraceParams.backtraceDepth = backtraceDepth;
1340 backtraceParams.backtraceSeparator = backtraceSeparator;
1341 newBacktraceArgs.append(backtraceParams);
1342 newMaxBacktraceDepth = qMax(newMaxBacktraceDepth, backtraceDepth);
1344 error +=
"QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1349#define IF_TOKEN(LEVEL)
1350 else if (lexeme == QLatin1StringView(LEVEL)) {
1352 nestedIfError = true;
1353 newTokens[i] = LEVEL;
1363 else if (lexeme == QLatin1StringView(
endifTokenC)) {
1365 if (!inIf && !nestedIfError)
1366 error +=
"QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1370 error +=
"QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme +
'\n'_L1;
1373 Q_ASSERT(literalLexemeIndex < literalLexemeCount);
1374 using UP = std::unique_ptr<
char[]>;
1375 newLiterals[literalLexemeIndex] = UP(qstrdup(lexeme.toUtf8().constData()));
1376 newTokens[i] = newLiterals[literalLexemeIndex].get();
1377 ++literalLexemeIndex;
1381 error +=
"QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1383 error +=
"QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1385 if (!error.isEmpty()) {
1390 "QMessagePattern::setPattern", nullptr);
1391 preformattedMessageHandler(QtWarningMsg, ctx, error);
1394 literals = std::move(newLiterals);
1395 tokens = std::move(newTokens);
1396 timeArgs = std::move(newTimeArgs);
1397#ifdef QLOGGING_HAVE_BACKTRACE
1398 backtraceArgs = std::move(newBacktraceArgs);
1399 maxBacktraceDepth = newMaxBacktraceDepth;
1403#if defined(QLOGGING_HAVE_BACKTRACE)
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416static constexpr int TypicalBacktraceFrameCount = 3;
1417static constexpr const char *QtCoreLibraryName =
"Qt" QT_STRINGIFY(QT_VERSION_MAJOR)
"Core";
1419#if defined(QLOGGING_USE_STD_BACKTRACE)
1420Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1422 assert(frameCount >= 0);
1423 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1427backtraceFramesForLogMessage(
int frameCount,
1428 const QInternalMessageLogContext::BacktraceStorage &buffer)
1431 result.reserve(buffer.size());
1433 const auto shouldSkipFrame = [](QByteArrayView description)
1435#if defined(_MSVC_STL_VERSION)
1436 const auto libraryNameEnd = description.indexOf(
'!');
1437 if (libraryNameEnd != -1) {
1438 const auto libraryName = description.first(libraryNameEnd);
1439 if (!libraryName.contains(QtCoreLibraryName))
1443 if (description.contains(
"populateBacktrace"))
1445 if (description.contains(
"QInternalMessageLogContext"))
1447 if (description.contains(
"~QDebug"))
1452 for (
const auto &entry : buffer) {
1453 const std::string description = entry.description();
1454 if (result.isEmpty() && shouldSkipFrame(description))
1456 result.append(QString::fromStdString(description));
1462#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1464Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1466 assert(frameCount >= 0);
1467 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1468 Q_ASSERT(result.size() ==
int(result.size()));
1469 int n = ::backtrace(result.data(),
int(result.size()));
1477backtraceFramesForLogMessage(
int frameCount,
1478 const QInternalMessageLogContext::BacktraceStorage &buffer)
1480 struct DecodedFrame {
1486 if (frameCount == 0)
1489 auto shouldSkipFrame = [&result](
const auto &library,
const auto &function) {
1490 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1492 if (function.isEmpty())
1494 if (function.contains(
"6QDebug"_L1))
1496 if (function.contains(
"14QMessageLogger"_L1))
1498 if (function.contains(
"17qt_message_output"_L1))
1500 if (function.contains(
"26QInternalMessageLogContext"_L1))
1505 auto demangled = [](
auto &function) -> QString {
1506 if (!function.startsWith(
"_Z"_L1))
1511 if constexpr (
sizeof(function.at(0)) == 1)
1512 return function.data();
1514 return std::move(function).toUtf8();
1516 auto cleanup = [](
auto *p) { free(p); };
1517 using Ptr = std::unique_ptr<
char,
decltype(cleanup)>;
1518 auto demangled = Ptr(abi::__cxa_demangle(fn,
nullptr,
nullptr,
nullptr), cleanup);
1521 return QString::fromUtf8(qCleanupFuncinfo(demangled.get()));
1523 return QString::fromUtf8(fn);
1526# if QT_CONFIG(dladdr)
1528 QString cachedLibrary;
1529 const char *cachedFname =
nullptr;
1530 auto decodeFrame = [&](
void *addr) -> DecodedFrame {
1532 if (!dladdr(addr, &info))
1536 QLatin1StringView fn(info.dli_sname);
1537 QLatin1StringView lib;
1538 if (
const char *lastSlash = strrchr(info.dli_fname,
'/'))
1539 lib = QLatin1StringView(lastSlash + 1);
1541 lib = QLatin1StringView(info.dli_fname);
1543 if (shouldSkipFrame(lib, fn))
1546 QString function = demangled(fn);
1547 if (lib.data() != cachedFname) {
1548 cachedFname = lib.data();
1549 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1551 return { cachedLibrary, function };
1559 static const QRegularExpression rx(QStringLiteral(
"^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1561 auto decodeFrame = [&](
void *&addr) -> DecodedFrame {
1562 auto cleanup = [](
auto *p) { free(p); };
1564 std::unique_ptr<
char *,
decltype(cleanup)>(backtrace_symbols(&addr, 1), cleanup);
1565 QString trace = QString::fromUtf8(strings.get()[0]);
1566 QRegularExpressionMatch m = rx.match(trace);
1570 QString library = m.captured(1);
1571 QString function = m.captured(2);
1574 if (shouldSkipFrame(library, function))
1577 function = demangled(function);
1578 return { library, function };
1582 for (
void *
const &addr : buffer) {
1583 DecodedFrame frame = decodeFrame(addr);
1584 if (!frame.library.isEmpty()) {
1585 if (frame.function.isEmpty())
1586 result.append(u'?' + frame.library + u'?');
1588 result.append(frame.function);
1591 if (!result.isEmpty())
1592 result.append(QStringLiteral(
"???"));
1595 if (result.size() == frameCount)
1601#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1605
1606
1607
1608static QStringList generateBacktraceFrames(
int frameCount,
const QMessageLogContext &ctx)
1611 if (ctx.version <= QMessageLogContext::CurrentVersion)
1614 auto &fullctx =
static_cast<
const QInternalMessageLogContext &>(ctx);
1615 if (!fullctx.backtrace.has_value())
1618 QStringList frames = backtraceFramesForLogMessage(frameCount, *fullctx.backtrace);
1619 if (frames.isEmpty())
1623 if (ctx.function && frames.at(0).startsWith(u'?'))
1624 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1629static QString formatBacktraceForLogMessage(
const QMessagePattern::BacktraceParams backtraceParams,
1630 const QStringList &backtrace)
1632 if (backtrace.isEmpty() || backtraceParams.backtraceDepth <= 0)
1635 const qsizetype backtraceDepth = (std::min)(qsizetype(backtraceParams.backtraceDepth),
1640 for (
auto it = backtrace.cbegin(); it != backtrace.cbegin() + backtraceDepth; ++it) {
1641 if (it != backtrace.cbegin())
1642 result += backtraceParams.backtraceSeparator;
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1673 return formatLogMessage(type, context, str);
1688 message.append(str);
1694 qsizetype timeArgsIdx = 0;
1695#ifdef QLOGGING_HAVE_BACKTRACE
1696 qsizetype backtraceArgsIdx = 0;
1697 QStringList fullBacktrace;
1701 for (qsizetype i = 0; pattern->tokens[i]; ++i) {
1702 const char *token = pattern->tokens[i];
1708 if (token == timeTokenC)
1710#ifdef QLOGGING_HAVE_BACKTRACE
1711 else if (token == backtraceTokenC)
1715 message.append(str);
1717 message.append(QUtf8StringView(context
.category));
1720 case QtDebugMsg: message.append(
"debug"_L1);
break;
1721 case QtInfoMsg: message.append(
"info"_L1);
break;
1722 case QtWarningMsg: message.append(
"warning"_L1);
break;
1724 case QtFatalMsg: message.append(
"fatal"_L1);
break;
1728 message.append(QUtf8StringView(context
.file));
1730 message.append(
"unknown"_L1);
1732 message.append(QString::number(context.line));
1735 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1737 message.append(
"unknown"_L1);
1739 message.append(QString::number(QCoreApplication::applicationPid()));
1741 message.append(QCoreApplication::applicationName());
1744 message.append(QString::number(qt_gettid()));
1746 if (!qt_append_thread_name_to(message))
1747 message.append(QString::number(qt_gettid()));
1749 message.append(
"0x"_L1);
1750 message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1751#ifdef QLOGGING_HAVE_BACKTRACE
1752 }
else if (token == backtraceTokenC) {
1753 if (fullBacktrace.isEmpty())
1754 fullBacktrace = generateBacktraceFrames(pattern->maxBacktraceDepth, context);
1755 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1757 message.append(formatBacktraceForLogMessage(backtraceParams, fullBacktrace));
1760 using namespace std::chrono;
1761 auto formatElapsedTime = [](steady_clock::duration time) {
1763 auto ms = duration_cast<milliseconds>(time);
1764 auto sec = duration_cast<seconds>(ms);
1766 return QString::asprintf(
"%6lld.%03u", qint64(sec.count()), uint(ms.count()));
1768 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1770 if (timeFormat ==
"process"_L1) {
1771 message += formatElapsedTime(steady_clock::now() - pattern->appStartTime);
1772 }
else if (timeFormat ==
"boot"_L1) {
1775 message += formatElapsedTime(steady_clock::now().time_since_epoch());
1776#if QT_CONFIG(datestring)
1777 }
else if (timeFormat.isEmpty()) {
1778 message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1780 message.append(QDateTime::currentDateTime().toString(timeFormat));
1786#define HANDLE_IF_TOKEN(LEVEL)
1787 } else if (token == if##LEVEL##TokenC) {
1788 skip = type != Qt##LEVEL##Msg;
1794#undef HANDLE_IF_TOKEN
1796 message.append(QUtf8StringView(token));
1805Q_CONSTINIT
static QBasicAtomicPointer<
void (QtMsgType,
const QMessageLogContext &,
const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(
nullptr);
1811#define QT_LOG_CODE 9000
1814static bool slog2_default_handler(QtMsgType type,
const QMessageLogContext &,
1815 const QString &message)
1817 if (shouldLogToStderr())
1820 QString formattedMessage = message;
1821 formattedMessage.append(u'\n');
1822 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1823 slog2_buffer_set_config_t buffer_config;
1824 slog2_buffer_t buffer_handle;
1826 buffer_config.buffer_set_name = __progname;
1827 buffer_config.num_buffers = 1;
1828 buffer_config.verbosity_level = SLOG2_DEBUG1;
1829 buffer_config.buffer_config[0].buffer_name =
"default";
1830 buffer_config.buffer_config[0].num_pages = 8;
1832 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1833 fprintf(stderr,
"Error registering slogger2 buffer!\n");
1838 slog2_set_default_buffer(buffer_handle);
1840 int severity = SLOG2_INFO;
1844 severity = SLOG2_DEBUG1;
1847 severity = SLOG2_INFO;
1850 severity = SLOG2_NOTICE;
1853 severity = SLOG2_WARNING;
1856 severity = SLOG2_ERROR;
1860 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1866#if QT_CONFIG(journald)
1867static bool systemd_default_message_handler(QtMsgType type,
1868 const QMessageLogContext &context,
1869 const QString &message)
1871 if (shouldLogToStderr())
1874 int priority = LOG_INFO;
1877 priority = LOG_DEBUG;
1880 priority = LOG_INFO;
1883 priority = LOG_WARNING;
1886 priority = LOG_CRIT;
1889 priority = LOG_ALERT;
1894 const QByteArray messageField =
"MESSAGE="_ba + message.toUtf8();
1895 const QByteArray priorityField =
"PRIORITY="_ba + QByteArray::number(priority);
1896 const QByteArray tidField =
"TID="_ba + QByteArray::number(qlonglong(qt_gettid()));
1897 const QByteArray fileField = context.file
1898 ?
"CODE_FILE="_ba + context.file : QByteArray();
1899 const QByteArray funcField = context.function
1900 ?
"CODE_FUNC="_ba + context.function : QByteArray();
1901 const QByteArray lineField = context.line
1902 ?
"CODE_LINE="_ba + QByteArray::number(context.line) : QByteArray();
1903 const QByteArray categoryField = context.category
1904 ?
"QT_CATEGORY="_ba + context.category : QByteArray();
1906 auto toIovec = [](
const QByteArray &ba) {
1907 return iovec{
const_cast<
char*>(ba.data()), size_t(ba.size()) };
1910 struct iovec fields[7] = {
1911 toIovec(messageField),
1912 toIovec(priorityField),
1917 fields[nFields++] = toIovec(fileField);
1918 if (context.function)
1919 fields[nFields++] = toIovec(funcField);
1921 fields[nFields++] = toIovec(lineField);
1922 if (context.category)
1923 fields[nFields++] = toIovec(categoryField);
1925 sd_journal_sendv(fields, nFields);
1931#if QT_CONFIG(syslog)
1932static bool syslog_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
1933 const QString &formattedMessage)
1935 if (shouldLogToStderr())
1938 int priority = LOG_INFO;
1941 priority = LOG_DEBUG;
1944 priority = LOG_INFO;
1947 priority = LOG_WARNING;
1950 priority = LOG_CRIT;
1953 priority = LOG_ALERT;
1957 syslog(priority,
"%s", formattedMessage.toUtf8().constData());
1964static bool android_default_message_handler(QtMsgType type,
1965 const QMessageLogContext &context,
1966 const QString &formattedMessage)
1968 if (shouldLogToStderr())
1971 android_LogPriority priority = ANDROID_LOG_DEBUG;
1974 priority = ANDROID_LOG_DEBUG;
1977 priority = ANDROID_LOG_INFO;
1980 priority = ANDROID_LOG_WARN;
1983 priority = ANDROID_LOG_ERROR;
1986 priority = ANDROID_LOG_FATAL;
1990 QMessagePattern *pattern = qMessagePattern();
1991 const QString tag = (pattern && pattern->containsToken(categoryTokenC))
1993 ? QCoreApplication::applicationName().replace(u' ', u'_')
1994 : QString::fromUtf8(context.category);
1995 __android_log_print(priority, qPrintable(tag),
"%s\n", qPrintable(formattedMessage));
2001#if defined(Q_OS_HARMONY)
2002static bool ohos_default_message_handler(QtMsgType type,
2003 const QMessageLogContext &context,
2004 const QString &message)
2006 QString formattedMessage = qFormatLogMessage(type, context, message);
2008 LogLevel priority = LOG_DEBUG;
2010 case QtDebugMsg: priority = LOG_DEBUG;
break;
2011 case QtInfoMsg: priority = LOG_INFO;
break;
2012 case QtWarningMsg: priority = LOG_WARN;
break;
2013 case QtCriticalMsg: priority = LOG_ERROR;
break;
2014 case QtFatalMsg: priority = LOG_FATAL;
break;
2017 qOhosLogMessage(priority, qPrintable(QCoreApplication::applicationName()), qPrintable(formattedMessage));
2024static void win_outputDebugString_helper(
const QString &message)
2026 const qsizetype maxOutputStringLength = 32766;
2027 Q_CONSTINIT
static QBasicMutex m;
2028 const auto locker = qt_scoped_lock(m);
2031 if (message.length() <= maxOutputStringLength) {
2032 OutputDebugString(
reinterpret_cast<
const wchar_t *>(message.utf16()));
2034 wchar_t *messagePart =
new wchar_t[maxOutputStringLength + 1];
2035 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
2036 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
2037 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
2038 Q_ASSERT(len == length);
2039 messagePart[len] = 0;
2040 OutputDebugString(messagePart);
2042 delete[] messagePart;
2046static bool win_message_handler(QtMsgType,
const QMessageLogContext &,
2047 const QString &formattedMessage)
2049 if (shouldLogToStderr())
2052 win_outputDebugString_helper(formattedMessage + u'\n');
2059static bool wasm_default_message_handler(QtMsgType type,
2060 const QMessageLogContext &,
2061 const QString &formattedMessage)
2063 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
2064 if (forceStderrLogging)
2067 int emOutputFlags = EM_LOG_CONSOLE;
2068 QByteArray localMsg = formattedMessage.toLocal8Bit();
2075 emOutputFlags |= EM_LOG_WARN;
2078 emOutputFlags |= EM_LOG_ERROR;
2081 emOutputFlags |= EM_LOG_ERROR;
2083 emscripten_log(emOutputFlags,
"%s\n", qPrintable(formattedMessage));
2092 const QString &formattedMessage)
2099 if (formattedMessage.isNull())
2101 const QByteArray msg = formattedMessage.toLocal8Bit() +
'\n';
2102 fwrite(msg.constData(), 1, msg.size(), stderr);
2107struct SystemMessageSink
2111 bool messageIsUnformatted =
false;
2116#if defined(Q_OS_WIN)
2118#elif QT_CONFIG(slog2)
2119 slog2_default_handler
2120#elif QT_CONFIG(journald)
2121 systemd_default_message_handler,
true
2122#elif QT_CONFIG(syslog)
2123 syslog_default_message_handler
2124#elif defined(Q_OS_ANDROID)
2125 android_default_message_handler
2126# elif defined(Q_OS_HARMONY)
2127 ohos_default_message_handler
2128#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
2129 AppleUnifiedLogger::messageHandler,
true
2130#elif defined Q_OS_WASM
2131 wasm_default_message_handler
2138 const QString &formattedMessage)
2142QT_WARNING_DISABLE_GCC(
"-Waddress")
2143 if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
2152
2153
2155 const QString &message)
2166 preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
2191 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2192 if (!defaultCategory->isEnabled(msgType))
2201 auto msgHandler = messageHandler.loadAcquire();
2208template <
typename String>
static void
2213#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2214 wchar_t contextFileL[256];
2218 convert_to_wchar_t_elided(contextFileL,
sizeof contextFileL /
sizeof *contextFileL,
2221 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2222 _CrtSetReportMode(_CRT_ERROR, reportMode);
2224 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2225 reinterpret_cast<
const wchar_t *>(message.utf16()));
2226 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2234 if constexpr (
std::is_class_v<String> && !
std::is_const_v<String>)
2242
2243
2247 qt_message_print(msgType, ctx, message);
2248 qt_maybe_message_fatal(msgType, ctx, message);
2255 QString error_string = qt_error_string(-1);
2259 QString buf = QString::vasprintf(msg, ap);
2262 buf +=
" ("_L1 + error_string + u')';
2264 qt_message_output(QtWarningMsg, context, buf);
2273 QString buf = QString::vasprintf(msg, ap);
2276 buf +=
" ("_L1 + qt_error_string(code) + u')';
2278 qt_message_output(QtWarningMsg, context, buf);
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
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
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
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
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2458 const auto old = messageHandler.fetchAndStoreOrdered(h);
2469 if (!qMessagePattern()->fromEnvironment)
2470 qMessagePattern()->setPattern(pattern);
2476 if (logContext.version == self->version) {
2477 auto other =
static_cast<
const QInternalMessageLogContext *>(&logContext);
2478 self->backtrace = other->backtrace;
2483
2484
2485
2486
2489 version = CurrentVersion + 1;
2490 copyContextFrom(logContext);
2492#ifdef QLOGGING_HAVE_BACKTRACE
2493 if (backtrace.has_value())
2497 if (
auto pattern = qMessagePattern())
2498 return pattern->maxBacktraceDepth;
2505
2506
2507
2508
2509
2510
2511
2518 if (Q_UNLIKELY(version == CurrentVersion + 1))
2519 copyInternalContext(
static_cast<QInternalMessageLogContext *>(
this), logContext);
2524
2525
2526
2527
2528
2531
2532
2533
2534
2535
2537
2538
2539
2540
2541
2542
2543
2546
2547
2548
2549
2550
2551
2552
2555
2556
2557
2558
2559
2562
2563
2564
2565
2566
2567
2568
2569
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2633
2634
2635
2636
2637
2638
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
2672
2673
2674
2675
2676
2677
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
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
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