12#include "private/qcoreapplication_p.h"
16#include "private/qlocking_p.h"
18#include "private/qloggingregistry_p.h"
22#include "qtcore_tracepoints_p.h"
37#include <android/log.h>
41#include <QtCore/private/qcore_mac_p.h>
44#if QT_CONFIG(journald)
45# define SD_JOURNAL_SUPPRESS_LOCATION
46# include <systemd/sd-journal.h>
53# include <sys/types.h>
56# include "private/qcore_unix_p.h"
60#include <emscripten/emscripten.h>
67#ifdef QLOGGING_HAVE_BACKTRACE
68# include <qregularexpression.h>
71#ifdef QLOGGING_USE_EXECINFO_BACKTRACE
75# include BACKTRACE_HEADER
88#include <qt_windows.h>
89#include <processthreadsapi.h>
90#include "qfunctionpointer.h"
95using namespace Qt::StringLiterals;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
131template <
typename String>
135 const QString &formattedMessage);
148 int value = str.toInt(&ok, 0);
149 return (ok && value >= 0) ? value : 1;
154 static const int Uninitialized = 0;
155 static const int NeverFatal = 1;
156 static const int ImmediatelyFatal = 2;
158 int v = n.loadRelaxed();
159 if (v == Uninitialized) {
163 if (env == NeverFatal) {
165 n.storeRelaxed(NeverFatal);
167 }
else if (env == ImmediatelyFatal) {
169 }
else if (n.testAndSetRelaxed(Uninitialized, env - 1, v)) {
176 while (v > ImmediatelyFatal && !n.testAndSetRelaxed(v, v - 1, v))
181 return v == ImmediatelyFatal;
184Q_CONSTINIT
static QBasicAtomicInt fatalCriticalsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
185Q_CONSTINIT
static QBasicAtomicInt fatalWarningsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
193 return isFatalCountDown(
"QT_FATAL_CRITICALS", fatalCriticalsCount);
196 return isFatalCountDown(
"QT_FATAL_WARNINGS", fatalWarningsCount);
206#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
207static bool qt_append_thread_name_to(QString &message)
209 std::array<
char, 16> name{};
210 if (pthread_getname_np(pthread_self(), name.data(), name.size()) == 0) {
211 QUtf8StringView threadName(name.data());
212 if (!threadName.isEmpty()) {
213 message.append(threadName);
219#elif defined(Q_OS_WIN)
220typedef HRESULT (WINAPI *GetThreadDescriptionFunc)(HANDLE, PWSTR *);
221static bool qt_append_thread_name_to(QString &message)
225 static GetThreadDescriptionFunc pGetThreadDescription = []() -> GetThreadDescriptionFunc {
226 HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
229 auto funcPtr =
reinterpret_cast<QFunctionPointer>(GetProcAddress(hKernel,
"GetThreadDescription"));
230 return reinterpret_cast<GetThreadDescriptionFunc>(funcPtr);
232 if (!pGetThreadDescription)
234 PWSTR description =
nullptr;
235 HRESULT hr = pGetThreadDescription(GetCurrentThread(), &description);
236 std::unique_ptr<WCHAR,
decltype(&LocalFree)> descriptionOwner(description, &LocalFree);
238 QStringView threadName(description);
239 if (!threadName.isEmpty()) {
240 message.append(threadName);
257
258
259
260
261
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
289 static const bool stderrHasConsoleAttached = []() ->
bool {
293 if (qEnvironmentVariableIntValue(
"QT_LOGGING_TO_CONSOLE")) {
294 fprintf(stderr,
"warning: Environment variable QT_LOGGING_TO_CONSOLE is deprecated, use\n"
295 "QT_ASSUME_STDERR_HAS_CONSOLE and/or QT_FORCE_STDERR_LOGGING instead.\n");
299 if (qEnvironmentVariableIntValue(
"QT_ASSUME_STDERR_HAS_CONSOLE"))
303 return GetConsoleWindow();
304#elif defined(Q_OS_UNIX)
306# define _PATH_TTY "/dev/tty"
311 if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
312 qt_safe_close(ttyDevice);
314 }
else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
316 return isatty(STDERR_FILENO);
325 return stderrHasConsoleAttached;
332
333
334
335
336
337
338
339
342 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
354
355
356
357
358
359
360
361
362
363
364
365
366
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
387#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
388static inline void convert_to_wchar_t_elided(
wchar_t *d, size_t space,
const char *s)
noexcept
390 size_t len = qstrlen(s);
391 if (len + 1 > space) {
392 const size_t skip = len - space + 4;
395 for (
int i = 0; i < 3; ++i)
405
406
410 QString buf = QString::vasprintf(msg, ap);
411 qt_message_print(msgType, context, buf);
412 qt_maybe_message_fatal(msgType, context, buf);
416
417
418
419
420
421void QMessageLogger::debug(
const char *msg, ...)
const
423 QInternalMessageLogContext ctxt(context);
426 qt_message(QtDebugMsg, ctxt, msg, ap);
431
432
433
434
435
436
437void QMessageLogger::info(
const char *msg, ...)
const
439 QInternalMessageLogContext ctxt(context);
442 qt_message(QtInfoMsg, ctxt, msg, ap);
447
448
449
450
451
452
453
454
455
456
457
458
459
460
463
464
465
466
467
468
469void QMessageLogger::debug(
const QLoggingCategory &cat,
const char *msg, ...)
const
471 if (!cat.isDebugEnabled())
474 QInternalMessageLogContext ctxt(context, cat());
478 qt_message(QtDebugMsg, ctxt, msg, ap);
483
484
485
486
487
488
489void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
490 const char *msg, ...)
const
492 const QLoggingCategory &cat = (*catFunc)();
493 if (!cat.isDebugEnabled())
496 QInternalMessageLogContext ctxt(context, cat());
500 qt_message(QtDebugMsg, ctxt, msg, ap);
504#ifndef QT_NO_DEBUG_STREAM
507
508
509
510
511QDebug QMessageLogger::debug()
const
513 QDebug dbg = QDebug(QtDebugMsg);
514 QMessageLogContext &ctxt = dbg.stream->context;
515 ctxt.copyContextFrom(context);
520
521
522
523
524
525QDebug QMessageLogger::debug(
const QLoggingCategory &cat)
const
527 QDebug dbg = QDebug(QtDebugMsg);
528 if (!cat.isDebugEnabled())
529 dbg.stream->message_output =
false;
531 QMessageLogContext &ctxt = dbg.stream->context;
532 ctxt.copyContextFrom(context);
533 ctxt.category = cat.categoryName();
539
540
541
542
543
544QDebug QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc)
const
546 return debug((*catFunc)());
551
552
553
554
555
556
557void QMessageLogger::info(
const QLoggingCategory &cat,
const char *msg, ...)
const
559 if (!cat.isInfoEnabled())
562 QInternalMessageLogContext ctxt(context, cat());
566 qt_message(QtInfoMsg, ctxt, msg, ap);
571
572
573
574
575
576
577void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
578 const char *msg, ...)
const
580 const QLoggingCategory &cat = (*catFunc)();
581 if (!cat.isInfoEnabled())
584 QInternalMessageLogContext ctxt(context, cat());
588 qt_message(QtInfoMsg, ctxt, msg, ap);
592#ifndef QT_NO_DEBUG_STREAM
595
596
597
598
599
600QDebug QMessageLogger::info()
const
602 QDebug dbg = QDebug(QtInfoMsg);
603 QMessageLogContext &ctxt = dbg.stream->context;
604 ctxt.copyContextFrom(context);
609
610
611
612
613
614QDebug QMessageLogger::info(
const QLoggingCategory &cat)
const
616 QDebug dbg = QDebug(QtInfoMsg);
617 if (!cat.isInfoEnabled())
618 dbg.stream->message_output =
false;
620 QMessageLogContext &ctxt = dbg.stream->context;
621 ctxt.copyContextFrom(context);
622 ctxt.category = cat.categoryName();
628
629
630
631
632
633QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc)
const
635 return info((*catFunc)());
641
642
643
644
645
646void QMessageLogger::warning(
const char *msg, ...)
const
648 QInternalMessageLogContext ctxt(context);
651 qt_message(QtWarningMsg, ctxt, msg, ap);
656
657
658
659
660
661
662void QMessageLogger::warning(
const QLoggingCategory &cat,
const char *msg, ...)
const
664 if (!cat.isWarningEnabled())
667 QInternalMessageLogContext ctxt(context, cat());
671 qt_message(QtWarningMsg, ctxt, msg, ap);
676
677
678
679
680
681
682void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
683 const char *msg, ...)
const
685 const QLoggingCategory &cat = (*catFunc)();
686 if (!cat.isWarningEnabled())
689 QInternalMessageLogContext ctxt(context, cat());
693 qt_message(QtWarningMsg, ctxt, msg, ap);
697#ifndef QT_NO_DEBUG_STREAM
699
700
701
702
703QDebug QMessageLogger::warning()
const
705 QDebug dbg = QDebug(QtWarningMsg);
706 QMessageLogContext &ctxt = dbg.stream->context;
707 ctxt.copyContextFrom(context);
712
713
714
715
716QDebug QMessageLogger::warning(
const QLoggingCategory &cat)
const
718 QDebug dbg = QDebug(QtWarningMsg);
719 if (!cat.isWarningEnabled())
720 dbg.stream->message_output =
false;
722 QMessageLogContext &ctxt = dbg.stream->context;
723 ctxt.copyContextFrom(context);
724 ctxt.category = cat.categoryName();
730
731
732
733
734
735QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc)
const
737 return warning((*catFunc)());
743
744
745
746
747
748void QMessageLogger::critical(
const char *msg, ...)
const
750 QInternalMessageLogContext ctxt(context);
753 qt_message(QtCriticalMsg, ctxt, msg, ap);
758
759
760
761
762
763
764void QMessageLogger::critical(
const QLoggingCategory &cat,
const char *msg, ...)
const
766 if (!cat.isCriticalEnabled())
769 QInternalMessageLogContext ctxt(context, cat());
773 qt_message(QtCriticalMsg, ctxt, msg, ap);
778
779
780
781
782
783
784void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
785 const char *msg, ...)
const
787 const QLoggingCategory &cat = (*catFunc)();
788 if (!cat.isCriticalEnabled())
791 QInternalMessageLogContext ctxt(context, cat());
795 qt_message(QtCriticalMsg, ctxt, msg, ap);
799#ifndef QT_NO_DEBUG_STREAM
801
802
803
804
805QDebug QMessageLogger::critical()
const
807 QDebug dbg = QDebug(QtCriticalMsg);
808 QMessageLogContext &ctxt = dbg.stream->context;
809 ctxt.copyContextFrom(context);
814
815
816
817
818
819QDebug QMessageLogger::critical(
const QLoggingCategory &cat)
const
821 QDebug dbg = QDebug(QtCriticalMsg);
822 if (!cat.isCriticalEnabled())
823 dbg.stream->message_output =
false;
825 QMessageLogContext &ctxt = dbg.stream->context;
826 ctxt.copyContextFrom(context);
827 ctxt.category = cat.categoryName();
833
834
835
836
837
838QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc)
const
840 return critical((*catFunc)());
846
847
848
849
850
851
852void QMessageLogger::fatal(
const QLoggingCategory &cat,
const char *msg, ...)
const noexcept
854 QInternalMessageLogContext ctxt(context, cat());
858 qt_message(QtFatalMsg, ctxt, msg, ap);
861#ifndef Q_CC_MSVC_ONLY
867
868
869
870
871
872
873void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
874 const char *msg, ...)
const noexcept
876 const QLoggingCategory &cat = (*catFunc)();
878 QInternalMessageLogContext ctxt(context, cat());
882 qt_message(QtFatalMsg, ctxt, msg, ap);
885#ifndef Q_CC_MSVC_ONLY
891
892
893
894
895
896void QMessageLogger::fatal(
const char *msg, ...)
const noexcept
898 QInternalMessageLogContext ctxt(context);
901 qt_message(QtFatalMsg, ctxt, msg, ap);
904#ifndef Q_CC_MSVC_ONLY
909#ifndef QT_NO_DEBUG_STREAM
911
912
913
914
915
916
917QDebug QMessageLogger::fatal()
const
919 QDebug dbg = QDebug(QtFatalMsg);
920 QMessageLogContext &ctxt = dbg.stream->context;
921 ctxt.copyContextFrom(context);
926
927
928
929
930
931QDebug QMessageLogger::fatal(
const QLoggingCategory &cat)
const
933 QDebug dbg = QDebug(QtFatalMsg);
935 QMessageLogContext &ctxt = dbg.stream->context;
936 ctxt.copyContextFrom(context);
937 ctxt.category = cat.categoryName();
943
944
945
946
947
948QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc)
const
950 return fatal((*catFunc)());
956 return !category || strcmp(category, QLoggingRegistry::defaultCategoryName) == 0;
960
961
975 pos = info.size() - 1;
976 if (info.endsWith(
']') && !(info.startsWith(
'+') || info.startsWith(
'-'))) {
978 if (info.at(pos) ==
'[') {
983 if (info.endsWith(
' ')) {
989 static const char operator_call[] =
"operator()";
990 static const char operator_lessThan[] =
"operator<";
991 static const char operator_greaterThan[] =
"operator>";
992 static const char operator_lessThanEqual[] =
"operator<=";
993 static const char operator_greaterThanEqual[] =
"operator>=";
996 info.replace(
"operator ",
"operator");
1002 pos = info.lastIndexOf(
')', pos);
1007 if (info.indexOf(
'>', pos) != -1
1008 || info.indexOf(
':', pos) != -1) {
1017 while (pos && parencount) {
1018 if (info.at(pos) ==
')')
1020 else if (info.at(pos) ==
'(')
1024 if (parencount != 0)
1027 info.truncate(++pos);
1029 if (info.at(pos - 1) ==
')') {
1030 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
1036 info.remove(0, info.indexOf(
'('));
1046 int templatecount = 0;
1051 switch (info.at(pos)) {
1053 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
1057 if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
1061 if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
1065 auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
1066 if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
1068 else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
1078 if (parencount < 0 || templatecount < 0)
1081 char c = info.at(pos);
1090 else if (c ==
' ' && templatecount == 0 && parencount == 0)
1095 info = info.mid(pos + 1);
1098 while ((info.at(0) ==
'*')
1099 || (info.at(0) ==
'&'))
1104 while ((pos = info.lastIndexOf(
'>')) != -1) {
1105 if (!info.contains(
'<'))
1109 qsizetype end = pos;
1112 while (pos && templatecount) {
1113 char c = info.at(pos);
1121 info.remove(pos, end - pos + 1);
1158 const char *
const defaultTokens[] = {
1171 Q_ASSERT(!literals);
1173 auto ptr =
new const char *[
std::size(defaultTokens) + 1];
1174 auto end =
std::copy(
std::begin(defaultTokens),
std::end(defaultTokens), ptr);
1190#ifdef QLOGGING_HAVE_BACKTRACE
1212Q_CONSTINIT QBasicMutex QMessagePattern::mutex;
1216 const QString envPattern = qEnvironmentVariable(
"QT_MESSAGE_PATTERN");
1217 if (envPattern.isEmpty()) {
1231#ifdef QLOGGING_HAVE_BACKTRACE
1232 backtraceArgs.clear();
1233 maxBacktraceDepth = 0;
1237 QList<QString> lexemes;
1239 bool inPlaceholder =
false;
1240 for (
int i = 0; i < pattern.size(); ++i) {
1241 const QChar c = pattern.at(i);
1242 if (c == u'%' && !inPlaceholder) {
1243 if ((i + 1 < pattern.size())
1244 && pattern.at(i + 1) == u'{') {
1246 if (!lexeme.isEmpty()) {
1247 lexemes.append(lexeme);
1250 inPlaceholder =
true;
1256 if (c == u'}' && inPlaceholder) {
1258 lexemes.append(lexeme);
1260 inPlaceholder =
false;
1263 if (!lexeme.isEmpty())
1264 lexemes.append(lexeme);
1267 std::vector<std::unique_ptr<
const char[]>> literalsVar;
1268 tokens.reset(
new const char *[lexemes.size() + 1]);
1269 tokens[lexemes.size()] =
nullptr;
1271 bool nestedIfError =
false;
1275 for (
int i = 0; i < lexemes.size(); ++i) {
1276 const QString lexeme = lexemes.at(i);
1277 if (lexeme.startsWith(
"%{"_L1) && lexeme.endsWith(u'}')) {
1279 if (lexeme == QLatin1StringView(
typeTokenC)) {
1280 tokens[i] = typeTokenC;
1282 tokens[i] = categoryTokenC;
1284 tokens[i] = messageTokenC;
1285 else if (lexeme == QLatin1StringView(
fileTokenC))
1286 tokens[i] = fileTokenC;
1287 else if (lexeme == QLatin1StringView(
lineTokenC))
1288 tokens[i] = lineTokenC;
1290 tokens[i] = functionTokenC;
1291 else if (lexeme == QLatin1StringView(
pidTokenC))
1292 tokens[i] = pidTokenC;
1294 tokens[i] = appnameTokenC;
1296 tokens[i] = threadidTokenC;
1298 tokens[i] = threadnameTokenC;
1300 tokens[i] = qthreadptrTokenC;
1301 else if (lexeme.startsWith(QLatin1StringView(
timeTokenC))) {
1302 tokens[i] = timeTokenC;
1303 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(
' '));
1305 timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2));
1307 timeArgs.append(QString());
1309#ifdef QLOGGING_HAVE_BACKTRACE
1310 tokens[i] = backtraceTokenC;
1311 QString backtraceSeparator = QStringLiteral(
"|");
1312 int backtraceDepth = 5;
1313 static const QRegularExpression depthRx(QStringLiteral(
" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1314 static const QRegularExpression separatorRx(QStringLiteral(
" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1315 QRegularExpressionMatch m = depthRx.match(lexeme);
1317 int depth = m.capturedView(1).toInt();
1319 error +=
"QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1321 backtraceDepth = depth;
1323 m = separatorRx.match(lexeme);
1325 backtraceSeparator = m.captured(1);
1326 BacktraceParams backtraceParams;
1327 backtraceParams.backtraceDepth = backtraceDepth;
1328 backtraceParams.backtraceSeparator = backtraceSeparator;
1329 backtraceArgs.append(backtraceParams);
1330 maxBacktraceDepth = qMax(maxBacktraceDepth, backtraceDepth);
1332 error +=
"QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1337#define IF_TOKEN(LEVEL)
1338 else if (lexeme == QLatin1StringView(LEVEL)) {
1340 nestedIfError = true;
1351 else if (lexeme == QLatin1StringView(
endifTokenC)) {
1352 tokens[i] = endifTokenC;
1353 if (!inIf && !nestedIfError)
1354 error +=
"QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1357 tokens[i] = emptyTokenC;
1358 error +=
"QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme +
'\n'_L1;
1361 using UP = std::unique_ptr<
char[]>;
1362 tokens[i] = literalsVar.emplace_back(UP(qstrdup(lexeme.toLatin1().constData()))).get();
1366 error +=
"QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1368 error +=
"QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1370 if (!error.isEmpty()) {
1375 "QMessagePattern::setPattern", nullptr);
1376 preformattedMessageHandler(QtWarningMsg, ctx, error);
1379 literals.reset(
new std::unique_ptr<
const char[]>[literalsVar.size() + 1]);
1380 std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
1383#if defined(QLOGGING_HAVE_BACKTRACE)
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396static constexpr int TypicalBacktraceFrameCount = 3;
1397static constexpr const char *QtCoreLibraryName =
"Qt" QT_STRINGIFY(QT_VERSION_MAJOR)
"Core";
1399#if defined(QLOGGING_USE_STD_BACKTRACE)
1400Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1402 assert(frameCount >= 0);
1403 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1407backtraceFramesForLogMessage(
int frameCount,
1408 const QInternalMessageLogContext::BacktraceStorage &buffer)
1411 result.reserve(buffer.size());
1413 const auto shouldSkipFrame = [](QByteArrayView description)
1415#if defined(_MSVC_STL_VERSION)
1416 const auto libraryNameEnd = description.indexOf(
'!');
1417 if (libraryNameEnd != -1) {
1418 const auto libraryName = description.first(libraryNameEnd);
1419 if (!libraryName.contains(QtCoreLibraryName))
1423 if (description.contains(
"populateBacktrace"))
1425 if (description.contains(
"QInternalMessageLogContext"))
1427 if (description.contains(
"~QDebug"))
1432 for (
const auto &entry : buffer) {
1433 const std::string description = entry.description();
1434 if (result.isEmpty() && shouldSkipFrame(description))
1436 result.append(QString::fromStdString(description));
1442#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1444Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1446 assert(frameCount >= 0);
1447 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1448 Q_ASSERT(result.size() ==
int(result.size()));
1449 int n = ::backtrace(result.data(),
int(result.size()));
1457backtraceFramesForLogMessage(
int frameCount,
1458 const QInternalMessageLogContext::BacktraceStorage &buffer)
1460 struct DecodedFrame {
1466 if (frameCount == 0)
1469 auto shouldSkipFrame = [&result](
const auto &library,
const auto &function) {
1470 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1472 if (function.isEmpty())
1474 if (function.contains(
"6QDebug"_L1))
1476 if (function.contains(
"14QMessageLogger"_L1))
1478 if (function.contains(
"17qt_message_output"_L1))
1480 if (function.contains(
"26QInternalMessageLogContext"_L1))
1485 auto demangled = [](
auto &function) -> QString {
1486 if (!function.startsWith(
"_Z"_L1))
1491 if constexpr (
sizeof(function.at(0)) == 1)
1492 return function.data();
1494 return std::move(function).toUtf8();
1496 auto cleanup = [](
auto *p) { free(p); };
1497 using Ptr = std::unique_ptr<
char,
decltype(cleanup)>;
1498 auto demangled = Ptr(abi::__cxa_demangle(fn,
nullptr,
nullptr,
nullptr), cleanup);
1501 return QString::fromUtf8(qCleanupFuncinfo(demangled.get()));
1503 return QString::fromUtf8(fn);
1506# if QT_CONFIG(dladdr)
1508 QString cachedLibrary;
1509 const char *cachedFname =
nullptr;
1510 auto decodeFrame = [&](
void *addr) -> DecodedFrame {
1512 if (!dladdr(addr, &info))
1516 QLatin1StringView fn(info.dli_sname);
1517 QLatin1StringView lib;
1518 if (
const char *lastSlash = strrchr(info.dli_fname,
'/'))
1519 lib = QLatin1StringView(lastSlash + 1);
1521 lib = QLatin1StringView(info.dli_fname);
1523 if (shouldSkipFrame(lib, fn))
1526 QString function = demangled(fn);
1527 if (lib.data() != cachedFname) {
1528 cachedFname = lib.data();
1529 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1531 return { cachedLibrary, function };
1539 static const QRegularExpression rx(QStringLiteral(
"^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1541 auto decodeFrame = [&](
void *&addr) -> DecodedFrame {
1542 auto cleanup = [](
auto *p) { free(p); };
1544 std::unique_ptr<
char *,
decltype(cleanup)>(backtrace_symbols(&addr, 1), cleanup);
1545 QString trace = QString::fromUtf8(strings.get()[0]);
1546 QRegularExpressionMatch m = rx.match(trace);
1550 QString library = m.captured(1);
1551 QString function = m.captured(2);
1554 if (shouldSkipFrame(library, function))
1557 function = demangled(function);
1558 return { library, function };
1562 for (
void *
const &addr : buffer) {
1563 DecodedFrame frame = decodeFrame(addr);
1564 if (!frame.library.isEmpty()) {
1565 if (frame.function.isEmpty())
1566 result.append(u'?' + frame.library + u'?');
1568 result.append(frame.function);
1571 if (!result.isEmpty())
1572 result.append(QStringLiteral(
"???"));
1575 if (result.size() == frameCount)
1581#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1584static QString formatBacktraceForLogMessage(
const QMessagePattern::BacktraceParams backtraceParams,
1585 const QMessageLogContext &ctx)
1588 if (ctx.version <= QMessageLogContext::CurrentVersion)
1591 auto &fullctx =
static_cast<
const QInternalMessageLogContext &>(ctx);
1592 if (!fullctx.backtrace.has_value())
1595 QString backtraceSeparator = backtraceParams.backtraceSeparator;
1596 int backtraceDepth = backtraceParams.backtraceDepth;
1598 QStringList frames = backtraceFramesForLogMessage(backtraceDepth, *fullctx.backtrace);
1599 if (frames.isEmpty())
1603 if (ctx.function && frames.at(0).startsWith(u'?'))
1604 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1606 return frames.join(backtraceSeparator);
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1634 return formatLogMessage(type, context, str);
1649 message.append(str);
1655 int timeArgsIdx = 0;
1656#ifdef QLOGGING_HAVE_BACKTRACE
1657 int backtraceArgsIdx = 0;
1661 for (
int i = 0; pattern->tokens[i]; ++i) {
1662 const char *token = pattern->tokens[i];
1670#ifdef QLOGGING_HAVE_BACKTRACE
1671 else if (token == backtraceTokenC)
1675 message.append(str);
1677 message.append(QLatin1StringView(context
.category));
1680 case QtDebugMsg: message.append(
"debug"_L1);
break;
1681 case QtInfoMsg: message.append(
"info"_L1);
break;
1682 case QtWarningMsg: message.append(
"warning"_L1);
break;
1683 case QtCriticalMsg:message.append(
"critical"_L1);
break;
1684 case QtFatalMsg: message.append(
"fatal"_L1);
break;
1688 message.append(QLatin1StringView(context
.file));
1690 message.append(
"unknown"_L1);
1692 message.append(QString::number(context.line));
1694 if (context.function)
1695 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1697 message.append(
"unknown"_L1);
1699 message.append(QString::number(QCoreApplication::applicationPid()));
1701 message.append(QCoreApplication::applicationName());
1704 message.append(QString::number(qt_gettid()));
1706 if (!qt_append_thread_name_to(message))
1707 message.append(QString::number(qt_gettid()));
1709 message.append(
"0x"_L1);
1710 message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1711#ifdef QLOGGING_HAVE_BACKTRACE
1712 }
else if (token == backtraceTokenC) {
1713 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1715 message.append(formatBacktraceForLogMessage(backtraceParams, context));
1718 using namespace std::chrono;
1719 auto formatElapsedTime = [](steady_clock::duration time) {
1721 auto ms = duration_cast<milliseconds>(time);
1722 auto sec = duration_cast<seconds>(ms);
1724 return QString::asprintf(
"%6lld.%03u", qint64(sec.count()), uint(ms.count()));
1726 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1728 if (timeFormat ==
"process"_L1) {
1729 message += formatElapsedTime(steady_clock::now() - pattern->appStartTime);
1730 }
else if (timeFormat ==
"boot"_L1) {
1733 message += formatElapsedTime(steady_clock::now().time_since_epoch());
1734#if QT_CONFIG(datestring)
1735 }
else if (timeFormat.isEmpty()) {
1736 message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1738 message.append(QDateTime::currentDateTime().toString(timeFormat));
1744#define HANDLE_IF_TOKEN(LEVEL)
1745 } else if (token == if##LEVEL##TokenC) {
1746 skip = type != Qt##LEVEL##Msg;
1752#undef HANDLE_IF_TOKEN
1754 message.append(QLatin1StringView(token));
1763Q_CONSTINIT
static QBasicAtomicPointer<
void (QtMsgType,
const QMessageLogContext &,
const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(
nullptr);
1769#define QT_LOG_CODE 9000
1772static bool slog2_default_handler(QtMsgType type,
const QMessageLogContext &,
1773 const QString &message)
1775 if (shouldLogToStderr())
1778 QString formattedMessage = message;
1779 formattedMessage.append(u'\n');
1780 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1781 slog2_buffer_set_config_t buffer_config;
1782 slog2_buffer_t buffer_handle;
1784 buffer_config.buffer_set_name = __progname;
1785 buffer_config.num_buffers = 1;
1786 buffer_config.verbosity_level = SLOG2_DEBUG1;
1787 buffer_config.buffer_config[0].buffer_name =
"default";
1788 buffer_config.buffer_config[0].num_pages = 8;
1790 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1791 fprintf(stderr,
"Error registering slogger2 buffer!\n");
1792 fprintf(stderr,
"%s", formattedMessage.toLocal8Bit().constData());
1798 slog2_set_default_buffer(buffer_handle);
1800 int severity = SLOG2_INFO;
1804 severity = SLOG2_DEBUG1;
1807 severity = SLOG2_INFO;
1810 severity = SLOG2_NOTICE;
1813 severity = SLOG2_WARNING;
1816 severity = SLOG2_ERROR;
1820 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1826#if QT_CONFIG(journald)
1827static bool systemd_default_message_handler(QtMsgType type,
1828 const QMessageLogContext &context,
1829 const QString &message)
1831 if (shouldLogToStderr())
1834 int priority = LOG_INFO;
1837 priority = LOG_DEBUG;
1840 priority = LOG_INFO;
1843 priority = LOG_WARNING;
1846 priority = LOG_CRIT;
1849 priority = LOG_ALERT;
1854 const QByteArray messageField =
"MESSAGE="_ba + message.toUtf8().constData();
1855 const QByteArray priorityField =
"PRIORITY="_ba + QByteArray::number(priority);
1856 const QByteArray tidField =
"TID="_ba + QByteArray::number(qlonglong(qt_gettid()));
1857 const QByteArray fileField = context.file
1858 ?
"CODE_FILE="_ba + context.file : QByteArray();
1859 const QByteArray funcField = context.function
1860 ?
"CODE_FUNC="_ba + context.function : QByteArray();
1861 const QByteArray lineField = context.line
1862 ?
"CODE_LINE="_ba + QByteArray::number(context.line) : QByteArray();
1863 const QByteArray categoryField = context.category
1864 ?
"QT_CATEGORY="_ba + context.category : QByteArray();
1866 auto toIovec = [](
const QByteArray &ba) {
1867 return iovec{
const_cast<
char*>(ba.data()), size_t(ba.size()) };
1870 struct iovec fields[7] = {
1871 toIovec(messageField),
1872 toIovec(priorityField),
1877 fields[nFields++] = toIovec(fileField);
1878 if (context.function)
1879 fields[nFields++] = toIovec(funcField);
1881 fields[nFields++] = toIovec(lineField);
1882 if (context.category)
1883 fields[nFields++] = toIovec(categoryField);
1885 sd_journal_sendv(fields, nFields);
1891#if QT_CONFIG(syslog)
1892static bool syslog_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
1893 const QString &formattedMessage)
1895 if (shouldLogToStderr())
1898 int priority = LOG_INFO;
1901 priority = LOG_DEBUG;
1904 priority = LOG_INFO;
1907 priority = LOG_WARNING;
1910 priority = LOG_CRIT;
1913 priority = LOG_ALERT;
1917 syslog(priority,
"%s", formattedMessage.toUtf8().constData());
1924static bool android_default_message_handler(QtMsgType type,
1925 const QMessageLogContext &context,
1926 const QString &formattedMessage)
1928 if (shouldLogToStderr())
1931 android_LogPriority priority = ANDROID_LOG_DEBUG;
1934 priority = ANDROID_LOG_DEBUG;
1937 priority = ANDROID_LOG_INFO;
1940 priority = ANDROID_LOG_WARN;
1943 priority = ANDROID_LOG_ERROR;
1946 priority = ANDROID_LOG_FATAL;
1950 QMessagePattern *pattern = qMessagePattern();
1951 const QString tag = (pattern && pattern->containsToken(categoryTokenC))
1953 ? QCoreApplication::applicationName().replace(u' ', u'_')
1954 : QString::fromUtf8(context.category);
1955 __android_log_print(priority, qPrintable(tag),
"%s\n", qPrintable(formattedMessage));
1962static void win_outputDebugString_helper(
const QString &message)
1964 const qsizetype maxOutputStringLength = 32766;
1965 Q_CONSTINIT
static QBasicMutex m;
1966 auto locker = qt_unique_lock(m);
1968 if (message.length() <= maxOutputStringLength) {
1969 OutputDebugString(
reinterpret_cast<
const wchar_t *>(message.utf16()));
1971 wchar_t messagePart[maxOutputStringLength + 1];
1972 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
1973 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
1974 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
1975 Q_ASSERT(len == length);
1976 messagePart[len] = 0;
1977 OutputDebugString(messagePart);
1982static bool win_message_handler(QtMsgType,
const QMessageLogContext &,
1983 const QString &formattedMessage)
1985 if (shouldLogToStderr())
1988 win_outputDebugString_helper(formattedMessage + u'\n');
1995static bool wasm_default_message_handler(QtMsgType type,
1996 const QMessageLogContext &,
1997 const QString &formattedMessage)
1999 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
2000 if (forceStderrLogging)
2003 int emOutputFlags = EM_LOG_CONSOLE;
2004 QByteArray localMsg = formattedMessage.toLocal8Bit();
2011 emOutputFlags |= EM_LOG_WARN;
2014 emOutputFlags |= EM_LOG_ERROR;
2017 emOutputFlags |= EM_LOG_ERROR;
2019 emscripten_log(emOutputFlags,
"%s\n", qPrintable(formattedMessage));
2028 const QString &formattedMessage)
2035 if (formattedMessage.isNull())
2037 fprintf(stderr,
"%s\n", formattedMessage.toLocal8Bit().constData());
2042struct SystemMessageSink
2046 bool messageIsUnformatted =
false;
2051#if defined(Q_OS_WIN)
2053#elif QT_CONFIG(slog2)
2054 slog2_default_handler
2055#elif QT_CONFIG(journald)
2056 systemd_default_message_handler,
true
2057#elif QT_CONFIG(syslog)
2058 syslog_default_message_handler
2059#elif defined(Q_OS_ANDROID)
2060 android_default_message_handler
2061#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
2062 AppleUnifiedLogger::messageHandler,
true
2063#elif defined Q_OS_WASM
2064 wasm_default_message_handler
2071 const QString &formattedMessage)
2074QT_WARNING_DISABLE_GCC(
"-Waddress")
2075 if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
2079 stderr_message_handler(type, context, formattedMessage);
2083
2084
2086 const QString &message)
2097 preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
2122 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2123 if (!defaultCategory->isEnabled(msgType))
2132 auto msgHandler = messageHandler.loadAcquire();
2139template <
typename String>
static void
2144#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2145 wchar_t contextFileL[256];
2149 convert_to_wchar_t_elided(contextFileL,
sizeof contextFileL /
sizeof *contextFileL,
2152 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2153 _CrtSetReportMode(_CRT_ERROR, reportMode);
2155 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2156 reinterpret_cast<
const wchar_t *>(message.utf16()));
2157 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2165 if constexpr (
std::is_class_v<String> && !
std::is_const_v<String>)
2173
2174
2178 qt_message_print(msgType, ctx, message);
2179 qt_maybe_message_fatal(msgType, ctx, message);
2186 QString error_string = qt_error_string(-1);
2190 QString buf = QString::vasprintf(msg, ap);
2193 buf +=
" ("_L1 + error_string + u')';
2195 qt_message_output(QtWarningMsg, context, buf);
2204 QString buf = QString::vasprintf(msg, ap);
2207 buf +=
" ("_L1 + qt_error_string(code) + u')';
2209 qt_message_output(QtWarningMsg, context, buf);
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
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
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
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
2379 const auto old = messageHandler.fetchAndStoreOrdered(h);
2390 if (!qMessagePattern()->fromEnvironment)
2391 qMessagePattern()->setPattern(pattern);
2397 if (logContext.version == self->version) {
2399 self->backtrace = other->backtrace;
2404
2405
2406
2407
2410 version = CurrentVersion + 1;
2411 copyContextFrom(logContext);
2413#ifdef QLOGGING_HAVE_BACKTRACE
2414 if (backtrace.has_value())
2418 if (
auto pattern = qMessagePattern())
2419 return pattern->maxBacktraceDepth;
2426
2427
2428
2429
2430
2431
2432
2439 if (Q_UNLIKELY(version == CurrentVersion + 1))
2445
2446
2447
2448
2449
2452
2453
2454
2455
2456
2458
2459
2460
2461
2462
2463
2464
2467
2468
2469
2470
2471
2472
2473
2476
2477
2478
2479
2480
2483
2484
2485
2486
2487
2488
2489
2490
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2523
2524
2525
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
2554
2555
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
2585
2586
2587
2588
2589
2590
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
2624
2625
2626
2627
2628
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
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 Q_CONSTINIT thread_local bool msgHandlerGrabbed
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 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)
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