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#ifdef QLOGGING_HAVE_BACKTRACE
1241 backtraceArgs.clear();
1242 maxBacktraceDepth = 0;
1246 QList<QString> lexemes;
1248 bool inPlaceholder =
false;
1249 for (
int i = 0; i < pattern.size(); ++i) {
1250 const QChar c = pattern.at(i);
1251 if (c == u'%' && !inPlaceholder) {
1252 if ((i + 1 < pattern.size())
1253 && pattern.at(i + 1) == u'{') {
1255 if (!lexeme.isEmpty()) {
1256 lexemes.append(lexeme);
1259 inPlaceholder =
true;
1265 if (c == u'}' && inPlaceholder) {
1267 lexemes.append(lexeme);
1269 inPlaceholder =
false;
1272 if (!lexeme.isEmpty())
1273 lexemes.append(lexeme);
1276 std::vector<std::unique_ptr<
const char[]>> literalsVar;
1277 tokens.reset(
new const char *[lexemes.size() + 1]);
1278 tokens[lexemes.size()] =
nullptr;
1280 bool nestedIfError =
false;
1284 for (
int i = 0; i < lexemes.size(); ++i) {
1285 const QString lexeme = lexemes.at(i);
1286 if (lexeme.startsWith(
"%{"_L1) && lexeme.endsWith(u'}')) {
1288 if (lexeme == QLatin1StringView(
typeTokenC)) {
1289 tokens[i] = typeTokenC;
1291 tokens[i] = categoryTokenC;
1293 tokens[i] = messageTokenC;
1294 else if (lexeme == QLatin1StringView(
fileTokenC))
1295 tokens[i] = fileTokenC;
1296 else if (lexeme == QLatin1StringView(
lineTokenC))
1297 tokens[i] = lineTokenC;
1299 tokens[i] = functionTokenC;
1300 else if (lexeme == QLatin1StringView(
pidTokenC))
1301 tokens[i] = pidTokenC;
1303 tokens[i] = appnameTokenC;
1305 tokens[i] = threadidTokenC;
1307 tokens[i] = threadnameTokenC;
1309 tokens[i] = qthreadptrTokenC;
1310 else if (lexeme.startsWith(QLatin1StringView(
timeTokenC))) {
1311 tokens[i] = timeTokenC;
1312 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(
' '));
1314 timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2));
1316 timeArgs.append(QString());
1318#ifdef QLOGGING_HAVE_BACKTRACE
1319 tokens[i] = backtraceTokenC;
1320 QString backtraceSeparator = QStringLiteral(
"|");
1321 int backtraceDepth = 5;
1322 static const QRegularExpression depthRx(QStringLiteral(
" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1323 static const QRegularExpression separatorRx(QStringLiteral(
" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1324 QRegularExpressionMatch m = depthRx.match(lexeme);
1326 int depth = m.capturedView(1).toInt();
1328 error +=
"QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1330 backtraceDepth = depth;
1332 m = separatorRx.match(lexeme);
1334 backtraceSeparator = m.captured(1);
1335 BacktraceParams backtraceParams;
1336 backtraceParams.backtraceDepth = backtraceDepth;
1337 backtraceParams.backtraceSeparator = backtraceSeparator;
1338 backtraceArgs.append(backtraceParams);
1339 maxBacktraceDepth = qMax(maxBacktraceDepth, backtraceDepth);
1341 error +=
"QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1346#define IF_TOKEN(LEVEL)
1347 else if (lexeme == QLatin1StringView(LEVEL)) {
1349 nestedIfError = true;
1360 else if (lexeme == QLatin1StringView(
endifTokenC)) {
1361 tokens[i] = endifTokenC;
1362 if (!inIf && !nestedIfError)
1363 error +=
"QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1366 tokens[i] = emptyTokenC;
1367 error +=
"QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme +
'\n'_L1;
1370 using UP = std::unique_ptr<
char[]>;
1371 tokens[i] = literalsVar.emplace_back(UP(qstrdup(lexeme.toLatin1().constData()))).get();
1375 error +=
"QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1377 error +=
"QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1379 if (!error.isEmpty()) {
1384 "QMessagePattern::setPattern", nullptr);
1385 preformattedMessageHandler(QtWarningMsg, ctx, error);
1388 literals.reset(
new std::unique_ptr<
const char[]>[literalsVar.size() + 1]);
1389 std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
1392#if defined(QLOGGING_HAVE_BACKTRACE)
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405static constexpr int TypicalBacktraceFrameCount = 3;
1406static constexpr const char *QtCoreLibraryName =
"Qt" QT_STRINGIFY(QT_VERSION_MAJOR)
"Core";
1408#if defined(QLOGGING_USE_STD_BACKTRACE)
1409Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1411 assert(frameCount >= 0);
1412 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1416backtraceFramesForLogMessage(
int frameCount,
1417 const QInternalMessageLogContext::BacktraceStorage &buffer)
1420 result.reserve(buffer.size());
1422 const auto shouldSkipFrame = [](QByteArrayView description)
1424#if defined(_MSVC_STL_VERSION)
1425 const auto libraryNameEnd = description.indexOf(
'!');
1426 if (libraryNameEnd != -1) {
1427 const auto libraryName = description.first(libraryNameEnd);
1428 if (!libraryName.contains(QtCoreLibraryName))
1432 if (description.contains(
"populateBacktrace"))
1434 if (description.contains(
"QInternalMessageLogContext"))
1436 if (description.contains(
"~QDebug"))
1441 for (
const auto &entry : buffer) {
1442 const std::string description = entry.description();
1443 if (result.isEmpty() && shouldSkipFrame(description))
1445 result.append(QString::fromStdString(description));
1451#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1453Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1455 assert(frameCount >= 0);
1456 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1457 Q_ASSERT(result.size() ==
int(result.size()));
1458 int n = ::backtrace(result.data(),
int(result.size()));
1466backtraceFramesForLogMessage(
int frameCount,
1467 const QInternalMessageLogContext::BacktraceStorage &buffer)
1469 struct DecodedFrame {
1475 if (frameCount == 0)
1478 auto shouldSkipFrame = [&result](
const auto &library,
const auto &function) {
1479 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1481 if (function.isEmpty())
1483 if (function.contains(
"6QDebug"_L1))
1485 if (function.contains(
"14QMessageLogger"_L1))
1487 if (function.contains(
"17qt_message_output"_L1))
1489 if (function.contains(
"26QInternalMessageLogContext"_L1))
1494 auto demangled = [](
auto &function) -> QString {
1495 if (!function.startsWith(
"_Z"_L1))
1500 if constexpr (
sizeof(function.at(0)) == 1)
1501 return function.data();
1503 return std::move(function).toUtf8();
1505 auto cleanup = [](
auto *p) { free(p); };
1506 using Ptr = std::unique_ptr<
char,
decltype(cleanup)>;
1507 auto demangled = Ptr(abi::__cxa_demangle(fn,
nullptr,
nullptr,
nullptr), cleanup);
1510 return QString::fromUtf8(qCleanupFuncinfo(demangled.get()));
1512 return QString::fromUtf8(fn);
1515# if QT_CONFIG(dladdr)
1517 QString cachedLibrary;
1518 const char *cachedFname =
nullptr;
1519 auto decodeFrame = [&](
void *addr) -> DecodedFrame {
1521 if (!dladdr(addr, &info))
1525 QLatin1StringView fn(info.dli_sname);
1526 QLatin1StringView lib;
1527 if (
const char *lastSlash = strrchr(info.dli_fname,
'/'))
1528 lib = QLatin1StringView(lastSlash + 1);
1530 lib = QLatin1StringView(info.dli_fname);
1532 if (shouldSkipFrame(lib, fn))
1535 QString function = demangled(fn);
1536 if (lib.data() != cachedFname) {
1537 cachedFname = lib.data();
1538 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1540 return { cachedLibrary, function };
1548 static const QRegularExpression rx(QStringLiteral(
"^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1550 auto decodeFrame = [&](
void *&addr) -> DecodedFrame {
1551 auto cleanup = [](
auto *p) { free(p); };
1553 std::unique_ptr<
char *,
decltype(cleanup)>(backtrace_symbols(&addr, 1), cleanup);
1554 QString trace = QString::fromUtf8(strings.get()[0]);
1555 QRegularExpressionMatch m = rx.match(trace);
1559 QString library = m.captured(1);
1560 QString function = m.captured(2);
1563 if (shouldSkipFrame(library, function))
1566 function = demangled(function);
1567 return { library, function };
1571 for (
void *
const &addr : buffer) {
1572 DecodedFrame frame = decodeFrame(addr);
1573 if (!frame.library.isEmpty()) {
1574 if (frame.function.isEmpty())
1575 result.append(u'?' + frame.library + u'?');
1577 result.append(frame.function);
1580 if (!result.isEmpty())
1581 result.append(QStringLiteral(
"???"));
1584 if (result.size() == frameCount)
1590#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1593static QString formatBacktraceForLogMessage(
const QMessagePattern::BacktraceParams backtraceParams,
1594 const QMessageLogContext &ctx)
1597 if (ctx.version <= QMessageLogContext::CurrentVersion)
1600 auto &fullctx =
static_cast<
const QInternalMessageLogContext &>(ctx);
1601 if (!fullctx.backtrace.has_value())
1604 QString backtraceSeparator = backtraceParams.backtraceSeparator;
1605 int backtraceDepth = backtraceParams.backtraceDepth;
1607 QStringList frames = backtraceFramesForLogMessage(backtraceDepth, *fullctx.backtrace);
1608 if (frames.isEmpty())
1612 if (ctx.function && frames.at(0).startsWith(u'?'))
1613 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1615 return frames.join(backtraceSeparator);
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1643 return formatLogMessage(type, context, str);
1658 message.append(str);
1664 int timeArgsIdx = 0;
1665#ifdef QLOGGING_HAVE_BACKTRACE
1666 int backtraceArgsIdx = 0;
1670 for (
int i = 0; pattern->tokens[i]; ++i) {
1671 const char *token = pattern->tokens[i];
1679#ifdef QLOGGING_HAVE_BACKTRACE
1680 else if (token == backtraceTokenC)
1684 message.append(str);
1686 message.append(QLatin1StringView(context
.category));
1689 case QtDebugMsg: message.append(
"debug"_L1);
break;
1690 case QtInfoMsg: message.append(
"info"_L1);
break;
1691 case QtWarningMsg: message.append(
"warning"_L1);
break;
1693 case QtFatalMsg: message.append(
"fatal"_L1);
break;
1697 message.append(QLatin1StringView(context
.file));
1699 message.append(
"unknown"_L1);
1701 message.append(QString::number(context.line));
1704 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1706 message.append(
"unknown"_L1);
1708 message.append(QString::number(QCoreApplication::applicationPid()));
1710 message.append(QCoreApplication::applicationName());
1713 message.append(QString::number(qt_gettid()));
1715 if (!qt_append_thread_name_to(message))
1716 message.append(QString::number(qt_gettid()));
1718 message.append(
"0x"_L1);
1719 message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1720#ifdef QLOGGING_HAVE_BACKTRACE
1721 }
else if (token == backtraceTokenC) {
1722 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1724 message.append(formatBacktraceForLogMessage(backtraceParams, context));
1727 using namespace std::chrono;
1728 auto formatElapsedTime = [](steady_clock::duration time) {
1730 auto ms = duration_cast<milliseconds>(time);
1731 auto sec = duration_cast<seconds>(ms);
1733 return QString::asprintf(
"%6lld.%03u", qint64(sec.count()), uint(ms.count()));
1735 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1737 if (timeFormat ==
"process"_L1) {
1738 message += formatElapsedTime(steady_clock::now() - pattern->appStartTime);
1739 }
else if (timeFormat ==
"boot"_L1) {
1742 message += formatElapsedTime(steady_clock::now().time_since_epoch());
1743#if QT_CONFIG(datestring)
1744 }
else if (timeFormat.isEmpty()) {
1745 message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1747 message.append(QDateTime::currentDateTime().toString(timeFormat));
1753#define HANDLE_IF_TOKEN(LEVEL)
1754 } else if (token == if##LEVEL##TokenC) {
1755 skip = type != Qt##LEVEL##Msg;
1761#undef HANDLE_IF_TOKEN
1763 message.append(QLatin1StringView(token));
1772Q_CONSTINIT
static QBasicAtomicPointer<
void (QtMsgType,
const QMessageLogContext &,
const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(
nullptr);
1778#define QT_LOG_CODE 9000
1781static bool slog2_default_handler(QtMsgType type,
const QMessageLogContext &,
1782 const QString &message)
1784 if (shouldLogToStderr())
1787 QString formattedMessage = message;
1788 formattedMessage.append(u'\n');
1789 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1790 slog2_buffer_set_config_t buffer_config;
1791 slog2_buffer_t buffer_handle;
1793 buffer_config.buffer_set_name = __progname;
1794 buffer_config.num_buffers = 1;
1795 buffer_config.verbosity_level = SLOG2_DEBUG1;
1796 buffer_config.buffer_config[0].buffer_name =
"default";
1797 buffer_config.buffer_config[0].num_pages = 8;
1799 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1800 fprintf(stderr,
"Error registering slogger2 buffer!\n");
1801 fprintf(stderr,
"%s", formattedMessage.toLocal8Bit().constData());
1807 slog2_set_default_buffer(buffer_handle);
1809 int severity = SLOG2_INFO;
1813 severity = SLOG2_DEBUG1;
1816 severity = SLOG2_INFO;
1819 severity = SLOG2_NOTICE;
1822 severity = SLOG2_WARNING;
1825 severity = SLOG2_ERROR;
1829 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1835#if QT_CONFIG(journald)
1836static bool systemd_default_message_handler(QtMsgType type,
1837 const QMessageLogContext &context,
1838 const QString &message)
1840 if (shouldLogToStderr())
1843 int priority = LOG_INFO;
1846 priority = LOG_DEBUG;
1849 priority = LOG_INFO;
1852 priority = LOG_WARNING;
1855 priority = LOG_CRIT;
1858 priority = LOG_ALERT;
1863 const QByteArray messageField =
"MESSAGE="_ba + message.toUtf8().constData();
1864 const QByteArray priorityField =
"PRIORITY="_ba + QByteArray::number(priority);
1865 const QByteArray tidField =
"TID="_ba + QByteArray::number(qlonglong(qt_gettid()));
1866 const QByteArray fileField = context.file
1867 ?
"CODE_FILE="_ba + context.file : QByteArray();
1868 const QByteArray funcField = context.function
1869 ?
"CODE_FUNC="_ba + context.function : QByteArray();
1870 const QByteArray lineField = context.line
1871 ?
"CODE_LINE="_ba + QByteArray::number(context.line) : QByteArray();
1872 const QByteArray categoryField = context.category
1873 ?
"QT_CATEGORY="_ba + context.category : QByteArray();
1875 auto toIovec = [](
const QByteArray &ba) {
1876 return iovec{
const_cast<
char*>(ba.data()), size_t(ba.size()) };
1879 struct iovec fields[7] = {
1880 toIovec(messageField),
1881 toIovec(priorityField),
1886 fields[nFields++] = toIovec(fileField);
1887 if (context.function)
1888 fields[nFields++] = toIovec(funcField);
1890 fields[nFields++] = toIovec(lineField);
1891 if (context.category)
1892 fields[nFields++] = toIovec(categoryField);
1894 sd_journal_sendv(fields, nFields);
1900#if QT_CONFIG(syslog)
1901static bool syslog_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
1902 const QString &formattedMessage)
1904 if (shouldLogToStderr())
1907 int priority = LOG_INFO;
1910 priority = LOG_DEBUG;
1913 priority = LOG_INFO;
1916 priority = LOG_WARNING;
1919 priority = LOG_CRIT;
1922 priority = LOG_ALERT;
1926 syslog(priority,
"%s", formattedMessage.toUtf8().constData());
1933static bool android_default_message_handler(QtMsgType type,
1934 const QMessageLogContext &context,
1935 const QString &formattedMessage)
1937 if (shouldLogToStderr())
1940 android_LogPriority priority = ANDROID_LOG_DEBUG;
1943 priority = ANDROID_LOG_DEBUG;
1946 priority = ANDROID_LOG_INFO;
1949 priority = ANDROID_LOG_WARN;
1952 priority = ANDROID_LOG_ERROR;
1955 priority = ANDROID_LOG_FATAL;
1959 QMessagePattern *pattern = qMessagePattern();
1960 const QString tag = (pattern && pattern->containsToken(categoryTokenC))
1962 ? QCoreApplication::applicationName().replace(u' ', u'_')
1963 : QString::fromUtf8(context.category);
1964 __android_log_print(priority, qPrintable(tag),
"%s\n", qPrintable(formattedMessage));
1970#if defined(Q_OS_OHOS)
1971static bool ohos_default_message_handler(QtMsgType type,
1972 const QMessageLogContext &context,
1973 const QString &message)
1975 QString formattedMessage = qFormatLogMessage(type, context, message);
1977 LogLevel priority = LOG_DEBUG;
1979 case QtDebugMsg: priority = LOG_DEBUG;
break;
1980 case QtInfoMsg: priority = LOG_INFO;
break;
1981 case QtWarningMsg: priority = LOG_WARN;
break;
1982 case QtCriticalMsg: priority = LOG_ERROR;
break;
1983 case QtFatalMsg: priority = LOG_FATAL;
break;
1986 qOhosLogMessage(priority, qPrintable(QCoreApplication::applicationName()), qPrintable(formattedMessage));
1993static void win_outputDebugString_helper(
const QString &message)
1995 const qsizetype maxOutputStringLength = 32766;
1996 Q_CONSTINIT
static QBasicMutex m;
1997 auto locker = qt_unique_lock(m);
1999 if (message.length() <= maxOutputStringLength) {
2000 OutputDebugString(
reinterpret_cast<
const wchar_t *>(message.utf16()));
2002 wchar_t messagePart[maxOutputStringLength + 1];
2003 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
2004 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
2005 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
2006 Q_ASSERT(len == length);
2007 messagePart[len] = 0;
2008 OutputDebugString(messagePart);
2013static bool win_message_handler(QtMsgType,
const QMessageLogContext &,
2014 const QString &formattedMessage)
2016 if (shouldLogToStderr())
2019 win_outputDebugString_helper(formattedMessage + u'\n');
2026static bool wasm_default_message_handler(QtMsgType type,
2027 const QMessageLogContext &,
2028 const QString &formattedMessage)
2030 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
2031 if (forceStderrLogging)
2034 int emOutputFlags = EM_LOG_CONSOLE;
2035 QByteArray localMsg = formattedMessage.toLocal8Bit();
2042 emOutputFlags |= EM_LOG_WARN;
2045 emOutputFlags |= EM_LOG_ERROR;
2048 emOutputFlags |= EM_LOG_ERROR;
2050 emscripten_log(emOutputFlags,
"%s\n", qPrintable(formattedMessage));
2059 const QString &formattedMessage)
2066 if (formattedMessage.isNull())
2068 fprintf(stderr,
"%s\n", formattedMessage.toLocal8Bit().constData());
2073struct SystemMessageSink
2077 bool messageIsUnformatted =
false;
2082#if defined(Q_OS_WIN)
2084#elif QT_CONFIG(slog2)
2085 slog2_default_handler
2086#elif QT_CONFIG(journald)
2087 systemd_default_message_handler,
true
2088#elif QT_CONFIG(syslog)
2089 syslog_default_message_handler
2090#elif defined(Q_OS_ANDROID)
2091 android_default_message_handler
2092# elif defined(Q_OS_OHOS)
2093 ohos_default_message_handler
2094#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
2095 AppleUnifiedLogger::messageHandler,
true
2096#elif defined Q_OS_WASM
2097 wasm_default_message_handler
2104 const QString &formattedMessage)
2107QT_WARNING_DISABLE_GCC(
"-Waddress")
2108 if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
2112 stderr_message_handler(type, context, formattedMessage);
2116
2117
2119 const QString &message)
2130 preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
2155 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2156 if (!defaultCategory->isEnabled(msgType))
2165 auto msgHandler = messageHandler.loadAcquire();
2172template <
typename String>
static void
2177#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2178 wchar_t contextFileL[256];
2182 convert_to_wchar_t_elided(contextFileL,
sizeof contextFileL /
sizeof *contextFileL,
2185 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2186 _CrtSetReportMode(_CRT_ERROR, reportMode);
2188 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2189 reinterpret_cast<
const wchar_t *>(message.utf16()));
2190 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2198 if constexpr (
std::is_class_v<String> && !
std::is_const_v<String>)
2206
2207
2211 qt_message_print(msgType, ctx, message);
2212 qt_maybe_message_fatal(msgType, ctx, message);
2219 QString error_string = qt_error_string(-1);
2223 QString buf = QString::vasprintf(msg, ap);
2226 buf +=
" ("_L1 + error_string + u')';
2228 qt_message_output(QtWarningMsg, context, buf);
2237 QString buf = QString::vasprintf(msg, ap);
2240 buf +=
" ("_L1 + qt_error_string(code) + u')';
2242 qt_message_output(QtWarningMsg, context, buf);
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
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
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
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
2412 const auto old = messageHandler.fetchAndStoreOrdered(h);
2423 if (!qMessagePattern()->fromEnvironment)
2424 qMessagePattern()->setPattern(pattern);
2430 if (logContext.version == self->version) {
2431 auto other =
static_cast<
const QInternalMessageLogContext *>(&logContext);
2432 self->backtrace = other->backtrace;
2437
2438
2439
2440
2443 version = CurrentVersion + 1;
2444 copyContextFrom(logContext);
2446#ifdef QLOGGING_HAVE_BACKTRACE
2447 if (backtrace.has_value())
2451 if (
auto pattern = qMessagePattern())
2452 return pattern->maxBacktraceDepth;
2459
2460
2461
2462
2463
2464
2465
2472 if (Q_UNLIKELY(version == CurrentVersion + 1))
2473 copyInternalContext(
static_cast<QInternalMessageLogContext *>(
this), logContext);
2478
2479
2480
2481
2482
2485
2486
2487
2488
2489
2491
2492
2493
2494
2495
2496
2497
2500
2501
2502
2503
2504
2505
2506
2509
2510
2511
2512
2513
2516
2517
2518
2519
2520
2521
2522
2523
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2556
2557
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
2587
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
2617
2618
2619
2620
2621
2622
2623
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
2656
2657
2658
2659
2660
2661
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
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