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/qcore_mac_p.h>
45#if QT_CONFIG(journald)
46# define SD_JOURNAL_SUPPRESS_LOCATION
47# include <systemd/sd-journal.h>
54# include <sys/types.h>
57# include "private/qcore_unix_p.h"
61#include <emscripten/emscripten.h>
68#ifdef QLOGGING_HAVE_BACKTRACE
69# include <qregularexpression.h>
72#ifdef QLOGGING_USE_EXECINFO_BACKTRACE
76# include BACKTRACE_HEADER
89#include <qt_windows.h>
90#include <processthreadsapi.h>
91#include "qfunctionpointer.h"
96using namespace Qt::StringLiterals;
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
130
132template <
typename String>
136 const QString &formattedMessage);
149 int value = str.toInt(&ok, 0);
150 return (ok && value >= 0) ? value : 1;
155 static const int Uninitialized = 0;
156 static const int NeverFatal = 1;
157 static const int ImmediatelyFatal = 2;
159 int v = n.loadRelaxed();
160 if (v == Uninitialized) {
164 if (env == NeverFatal) {
166 n.storeRelaxed(NeverFatal);
168 }
else if (env == ImmediatelyFatal) {
170 }
else if (n.testAndSetRelaxed(Uninitialized, env - 1, v)) {
177 while (v > ImmediatelyFatal && !n.testAndSetRelaxed(v, v - 1, v))
182 return v == ImmediatelyFatal;
185Q_CONSTINIT
static QBasicAtomicInt fatalCriticalsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
186Q_CONSTINIT
static QBasicAtomicInt fatalWarningsCount = Q_BASIC_ATOMIC_INITIALIZER(0);
194 return isFatalCountDown(
"QT_FATAL_CRITICALS", fatalCriticalsCount);
197 return isFatalCountDown(
"QT_FATAL_WARNINGS", fatalWarningsCount);
207#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
208static bool qt_append_thread_name_to(QString &message)
210 std::array<
char, 16> name{};
211 if (pthread_getname_np(pthread_self(), name.data(), name.size()) == 0) {
212 QUtf8StringView threadName(name.data());
213 if (!threadName.isEmpty()) {
214 message.append(threadName);
220#elif defined(Q_OS_WIN)
221typedef HRESULT (WINAPI *GetThreadDescriptionFunc)(HANDLE, PWSTR *);
222static bool qt_append_thread_name_to(QString &message)
226 static GetThreadDescriptionFunc pGetThreadDescription = []() -> GetThreadDescriptionFunc {
227 HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
230 auto funcPtr =
reinterpret_cast<QFunctionPointer>(GetProcAddress(hKernel,
"GetThreadDescription"));
231 return reinterpret_cast<GetThreadDescriptionFunc>(funcPtr);
233 if (!pGetThreadDescription)
235 PWSTR description =
nullptr;
236 HRESULT hr = pGetThreadDescription(GetCurrentThread(), &description);
237 std::unique_ptr<WCHAR,
decltype(&LocalFree)> descriptionOwner(description, &LocalFree);
239 QStringView threadName(description);
240 if (!threadName.isEmpty()) {
241 message.append(threadName);
258
259
260
261
262
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
290 static const bool stderrHasConsoleAttached = []() ->
bool {
294 if (qEnvironmentVariableIntValue(
"QT_LOGGING_TO_CONSOLE")) {
295 fprintf(stderr,
"warning: Environment variable QT_LOGGING_TO_CONSOLE is deprecated, use\n"
296 "QT_ASSUME_STDERR_HAS_CONSOLE and/or QT_FORCE_STDERR_LOGGING instead.\n");
300 if (qEnvironmentVariableIntValue(
"QT_ASSUME_STDERR_HAS_CONSOLE"))
304 return GetConsoleWindow();
305#elif defined(Q_OS_UNIX)
307# define _PATH_TTY "/dev/tty"
312 if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
313 qt_safe_close(ttyDevice);
315 }
else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
317 return isatty(STDERR_FILENO);
326 return stderrHasConsoleAttached;
333
334
335
336
337
338
339
340
343 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
355
356
357
358
359
360
361
362
363
364
365
366
367
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
388#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
389static inline void convert_to_wchar_t_elided(
wchar_t *d, size_t space,
const char *s)
noexcept
391 size_t len = qstrlen(s);
392 if (len + 1 > space) {
393 const size_t skip = len - space + 4;
396 for (
int i = 0; i < 3; ++i)
406
407
411 QString buf = QString::vasprintf(msg, ap);
412 qt_message_print(msgType, context, buf);
413 qt_maybe_message_fatal(msgType, context, buf);
417
418
419
420
421
422void QMessageLogger::debug(
const char *msg, ...)
const
424 QInternalMessageLogContext ctxt(context);
427 qt_message(QtDebugMsg, ctxt, msg, ap);
432
433
434
435
436
437
438void QMessageLogger::info(
const char *msg, ...)
const
440 QInternalMessageLogContext ctxt(context);
443 qt_message(QtInfoMsg, ctxt, msg, ap);
448
449
450
451
452
453
454
455
456
457
458
459
460
461
464
465
466
467
468
469
470void QMessageLogger::debug(
const QLoggingCategory &cat,
const char *msg, ...)
const
472 if (!cat.isDebugEnabled())
475 QInternalMessageLogContext ctxt(context, cat());
479 qt_message(QtDebugMsg, ctxt, msg, ap);
484
485
486
487
488
489
490void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
491 const char *msg, ...)
const
493 const QLoggingCategory &cat = (*catFunc)();
494 if (!cat.isDebugEnabled())
497 QInternalMessageLogContext ctxt(context, cat());
501 qt_message(QtDebugMsg, ctxt, msg, ap);
505#ifndef QT_NO_DEBUG_STREAM
508
509
510
511
512QDebug QMessageLogger::debug()
const
514 QDebug dbg = QDebug(QtDebugMsg);
515 QMessageLogContext &ctxt = dbg.stream->context;
516 ctxt.copyContextFrom(context);
521
522
523
524
525
526QDebug QMessageLogger::debug(
const QLoggingCategory &cat)
const
528 QDebug dbg = QDebug(QtDebugMsg);
529 if (!cat.isDebugEnabled())
530 dbg.stream->message_output =
false;
532 QMessageLogContext &ctxt = dbg.stream->context;
533 ctxt.copyContextFrom(context);
534 ctxt.category = cat.categoryName();
540
541
542
543
544
545QDebug QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc)
const
547 return debug((*catFunc)());
552
553
554
555
556
557
558void QMessageLogger::info(
const QLoggingCategory &cat,
const char *msg, ...)
const
560 if (!cat.isInfoEnabled())
563 QInternalMessageLogContext ctxt(context, cat());
567 qt_message(QtInfoMsg, ctxt, msg, ap);
572
573
574
575
576
577
578void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
579 const char *msg, ...)
const
581 const QLoggingCategory &cat = (*catFunc)();
582 if (!cat.isInfoEnabled())
585 QInternalMessageLogContext ctxt(context, cat());
589 qt_message(QtInfoMsg, ctxt, msg, ap);
593#ifndef QT_NO_DEBUG_STREAM
596
597
598
599
600
601QDebug QMessageLogger::info()
const
603 QDebug dbg = QDebug(QtInfoMsg);
604 QMessageLogContext &ctxt = dbg.stream->context;
605 ctxt.copyContextFrom(context);
610
611
612
613
614
615QDebug QMessageLogger::info(
const QLoggingCategory &cat)
const
617 QDebug dbg = QDebug(QtInfoMsg);
618 if (!cat.isInfoEnabled())
619 dbg.stream->message_output =
false;
621 QMessageLogContext &ctxt = dbg.stream->context;
622 ctxt.copyContextFrom(context);
623 ctxt.category = cat.categoryName();
629
630
631
632
633
634QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc)
const
636 return info((*catFunc)());
642
643
644
645
646
647void QMessageLogger::warning(
const char *msg, ...)
const
649 QInternalMessageLogContext ctxt(context);
652 qt_message(QtWarningMsg, ctxt, msg, ap);
657
658
659
660
661
662
663void QMessageLogger::warning(
const QLoggingCategory &cat,
const char *msg, ...)
const
665 if (!cat.isWarningEnabled())
668 QInternalMessageLogContext ctxt(context, cat());
672 qt_message(QtWarningMsg, ctxt, msg, ap);
677
678
679
680
681
682
683void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
684 const char *msg, ...)
const
686 const QLoggingCategory &cat = (*catFunc)();
687 if (!cat.isWarningEnabled())
690 QInternalMessageLogContext ctxt(context, cat());
694 qt_message(QtWarningMsg, ctxt, msg, ap);
698#ifndef QT_NO_DEBUG_STREAM
700
701
702
703
704QDebug QMessageLogger::warning()
const
706 QDebug dbg = QDebug(QtWarningMsg);
707 QMessageLogContext &ctxt = dbg.stream->context;
708 ctxt.copyContextFrom(context);
713
714
715
716
717QDebug QMessageLogger::warning(
const QLoggingCategory &cat)
const
719 QDebug dbg = QDebug(QtWarningMsg);
720 if (!cat.isWarningEnabled())
721 dbg.stream->message_output =
false;
723 QMessageLogContext &ctxt = dbg.stream->context;
724 ctxt.copyContextFrom(context);
725 ctxt.category = cat.categoryName();
731
732
733
734
735
736QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc)
const
738 return warning((*catFunc)());
744
745
746
747
748
749void QMessageLogger::critical(
const char *msg, ...)
const
751 QInternalMessageLogContext ctxt(context);
754 qt_message(QtCriticalMsg, ctxt, msg, ap);
759
760
761
762
763
764
765void QMessageLogger::critical(
const QLoggingCategory &cat,
const char *msg, ...)
const
767 if (!cat.isCriticalEnabled())
770 QInternalMessageLogContext ctxt(context, cat());
774 qt_message(QtCriticalMsg, ctxt, msg, ap);
779
780
781
782
783
784
785void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
786 const char *msg, ...)
const
788 const QLoggingCategory &cat = (*catFunc)();
789 if (!cat.isCriticalEnabled())
792 QInternalMessageLogContext ctxt(context, cat());
796 qt_message(QtCriticalMsg, ctxt, msg, ap);
800#ifndef QT_NO_DEBUG_STREAM
802
803
804
805
806QDebug QMessageLogger::critical()
const
808 QDebug dbg = QDebug(QtCriticalMsg);
809 QMessageLogContext &ctxt = dbg.stream->context;
810 ctxt.copyContextFrom(context);
815
816
817
818
819
820QDebug QMessageLogger::critical(
const QLoggingCategory &cat)
const
822 QDebug dbg = QDebug(QtCriticalMsg);
823 if (!cat.isCriticalEnabled())
824 dbg.stream->message_output =
false;
826 QMessageLogContext &ctxt = dbg.stream->context;
827 ctxt.copyContextFrom(context);
828 ctxt.category = cat.categoryName();
834
835
836
837
838
839QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc)
const
841 return critical((*catFunc)());
847
848
849
850
851
852
853void QMessageLogger::fatal(
const QLoggingCategory &cat,
const char *msg, ...)
const noexcept
855 QInternalMessageLogContext ctxt(context, cat());
859 qt_message(QtFatalMsg, ctxt, msg, ap);
862#ifndef Q_CC_MSVC_ONLY
868
869
870
871
872
873
874void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
875 const char *msg, ...)
const noexcept
877 const QLoggingCategory &cat = (*catFunc)();
879 QInternalMessageLogContext ctxt(context, cat());
883 qt_message(QtFatalMsg, ctxt, msg, ap);
886#ifndef Q_CC_MSVC_ONLY
892
893
894
895
896
897void QMessageLogger::fatal(
const char *msg, ...)
const noexcept
899 QInternalMessageLogContext ctxt(context);
902 qt_message(QtFatalMsg, ctxt, msg, ap);
905#ifndef Q_CC_MSVC_ONLY
910#ifndef QT_NO_DEBUG_STREAM
912
913
914
915
916
917
918QDebug QMessageLogger::fatal()
const
920 QDebug dbg = QDebug(QtFatalMsg);
921 QMessageLogContext &ctxt = dbg.stream->context;
922 ctxt.copyContextFrom(context);
927
928
929
930
931
932QDebug QMessageLogger::fatal(
const QLoggingCategory &cat)
const
934 QDebug dbg = QDebug(QtFatalMsg);
936 QMessageLogContext &ctxt = dbg.stream->context;
937 ctxt.copyContextFrom(context);
938 ctxt.category = cat.categoryName();
944
945
946
947
948
949QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc)
const
951 return fatal((*catFunc)());
957 return !category || strcmp(category, QLoggingRegistry::defaultCategoryName) == 0;
961
962
976 pos = info.size() - 1;
977 if (info.endsWith(
']') && !(info.startsWith(
'+') || info.startsWith(
'-'))) {
979 if (info.at(pos) ==
'[') {
984 if (info.endsWith(
' ')) {
990 static const char operator_call[] =
"operator()";
991 static const char operator_lessThan[] =
"operator<";
992 static const char operator_greaterThan[] =
"operator>";
993 static const char operator_lessThanEqual[] =
"operator<=";
994 static const char operator_greaterThanEqual[] =
"operator>=";
997 info.replace(
"operator ",
"operator");
1003 pos = info.lastIndexOf(
')', pos);
1008 if (info.indexOf(
'>', pos) != -1
1009 || info.indexOf(
':', pos) != -1) {
1018 while (pos && parencount) {
1019 if (info.at(pos) ==
')')
1021 else if (info.at(pos) ==
'(')
1025 if (parencount != 0)
1028 info.truncate(++pos);
1030 if (info.at(pos - 1) ==
')') {
1031 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
1037 info.remove(0, info.indexOf(
'('));
1047 int templatecount = 0;
1052 switch (info.at(pos)) {
1054 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
1058 if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
1062 if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
1066 auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
1067 if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
1069 else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
1079 if (parencount < 0 || templatecount < 0)
1082 char c = info.at(pos);
1091 else if (c ==
' ' && templatecount == 0 && parencount == 0)
1096 info = info.mid(pos + 1);
1099 while ((info.at(0) ==
'*')
1100 || (info.at(0) ==
'&'))
1105 while ((pos = info.lastIndexOf(
'>')) != -1) {
1106 if (!info.contains(
'<'))
1110 qsizetype end = pos;
1113 while (pos && templatecount) {
1114 char c = info.at(pos);
1122 info.remove(pos, end - pos + 1);
1159 const char *
const defaultTokens[] = {
1172 Q_ASSERT(!literals);
1174 auto ptr =
new const char *[
std::size(defaultTokens) + 1];
1175 auto end =
std::copy(
std::begin(defaultTokens),
std::end(defaultTokens), ptr);
1191#ifdef QLOGGING_HAVE_BACKTRACE
1213Q_CONSTINIT QBasicMutex QMessagePattern::mutex;
1217 const QString envPattern = qEnvironmentVariable(
"QT_MESSAGE_PATTERN");
1218 if (envPattern.isEmpty()) {
1232#ifdef QLOGGING_HAVE_BACKTRACE
1233 backtraceArgs.clear();
1234 maxBacktraceDepth = 0;
1238 QList<QString> lexemes;
1240 bool inPlaceholder =
false;
1241 for (
int i = 0; i < pattern.size(); ++i) {
1242 const QChar c = pattern.at(i);
1243 if (c == u'%' && !inPlaceholder) {
1244 if ((i + 1 < pattern.size())
1245 && pattern.at(i + 1) == u'{') {
1247 if (!lexeme.isEmpty()) {
1248 lexemes.append(lexeme);
1251 inPlaceholder =
true;
1257 if (c == u'}' && inPlaceholder) {
1259 lexemes.append(lexeme);
1261 inPlaceholder =
false;
1264 if (!lexeme.isEmpty())
1265 lexemes.append(lexeme);
1268 std::vector<std::unique_ptr<
const char[]>> literalsVar;
1269 tokens.reset(
new const char *[lexemes.size() + 1]);
1270 tokens[lexemes.size()] =
nullptr;
1272 bool nestedIfError =
false;
1276 for (
int i = 0; i < lexemes.size(); ++i) {
1277 const QString lexeme = lexemes.at(i);
1278 if (lexeme.startsWith(
"%{"_L1) && lexeme.endsWith(u'}')) {
1280 if (lexeme == QLatin1StringView(
typeTokenC)) {
1281 tokens[i] = typeTokenC;
1283 tokens[i] = categoryTokenC;
1285 tokens[i] = messageTokenC;
1286 else if (lexeme == QLatin1StringView(
fileTokenC))
1287 tokens[i] = fileTokenC;
1288 else if (lexeme == QLatin1StringView(
lineTokenC))
1289 tokens[i] = lineTokenC;
1291 tokens[i] = functionTokenC;
1292 else if (lexeme == QLatin1StringView(
pidTokenC))
1293 tokens[i] = pidTokenC;
1295 tokens[i] = appnameTokenC;
1297 tokens[i] = threadidTokenC;
1299 tokens[i] = threadnameTokenC;
1301 tokens[i] = qthreadptrTokenC;
1302 else if (lexeme.startsWith(QLatin1StringView(
timeTokenC))) {
1303 tokens[i] = timeTokenC;
1304 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(
' '));
1306 timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2));
1308 timeArgs.append(QString());
1310#ifdef QLOGGING_HAVE_BACKTRACE
1311 tokens[i] = backtraceTokenC;
1312 QString backtraceSeparator = QStringLiteral(
"|");
1313 int backtraceDepth = 5;
1314 static const QRegularExpression depthRx(QStringLiteral(
" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1315 static const QRegularExpression separatorRx(QStringLiteral(
" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1316 QRegularExpressionMatch m = depthRx.match(lexeme);
1318 int depth = m.capturedView(1).toInt();
1320 error +=
"QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1322 backtraceDepth = depth;
1324 m = separatorRx.match(lexeme);
1326 backtraceSeparator = m.captured(1);
1327 BacktraceParams backtraceParams;
1328 backtraceParams.backtraceDepth = backtraceDepth;
1329 backtraceParams.backtraceSeparator = backtraceSeparator;
1330 backtraceArgs.append(backtraceParams);
1331 maxBacktraceDepth = qMax(maxBacktraceDepth, backtraceDepth);
1333 error +=
"QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1338#define IF_TOKEN(LEVEL)
1339 else if (lexeme == QLatin1StringView(LEVEL)) {
1341 nestedIfError = true;
1352 else if (lexeme == QLatin1StringView(
endifTokenC)) {
1353 tokens[i] = endifTokenC;
1354 if (!inIf && !nestedIfError)
1355 error +=
"QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1358 tokens[i] = emptyTokenC;
1359 error +=
"QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme +
'\n'_L1;
1362 using UP = std::unique_ptr<
char[]>;
1363 tokens[i] = literalsVar.emplace_back(UP(qstrdup(lexeme.toLatin1().constData()))).get();
1367 error +=
"QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1369 error +=
"QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1371 if (!error.isEmpty()) {
1376 "QMessagePattern::setPattern", nullptr);
1377 preformattedMessageHandler(QtWarningMsg, ctx, error);
1380 literals.reset(
new std::unique_ptr<
const char[]>[literalsVar.size() + 1]);
1381 std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
1384#if defined(QLOGGING_HAVE_BACKTRACE)
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397static constexpr int TypicalBacktraceFrameCount = 3;
1398static constexpr const char *QtCoreLibraryName =
"Qt" QT_STRINGIFY(QT_VERSION_MAJOR)
"Core";
1400#if defined(QLOGGING_USE_STD_BACKTRACE)
1401Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1403 assert(frameCount >= 0);
1404 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1408backtraceFramesForLogMessage(
int frameCount,
1409 const QInternalMessageLogContext::BacktraceStorage &buffer)
1412 result.reserve(buffer.size());
1414 const auto shouldSkipFrame = [](QByteArrayView description)
1416#if defined(_MSVC_STL_VERSION)
1417 const auto libraryNameEnd = description.indexOf(
'!');
1418 if (libraryNameEnd != -1) {
1419 const auto libraryName = description.first(libraryNameEnd);
1420 if (!libraryName.contains(QtCoreLibraryName))
1424 if (description.contains(
"populateBacktrace"))
1426 if (description.contains(
"QInternalMessageLogContext"))
1428 if (description.contains(
"~QDebug"))
1433 for (
const auto &entry : buffer) {
1434 const std::string description = entry.description();
1435 if (result.isEmpty() && shouldSkipFrame(description))
1437 result.append(QString::fromStdString(description));
1443#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1445Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1447 assert(frameCount >= 0);
1448 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1449 Q_ASSERT(result.size() ==
int(result.size()));
1450 int n = ::backtrace(result.data(),
int(result.size()));
1458backtraceFramesForLogMessage(
int frameCount,
1459 const QInternalMessageLogContext::BacktraceStorage &buffer)
1461 struct DecodedFrame {
1467 if (frameCount == 0)
1470 auto shouldSkipFrame = [&result](
const auto &library,
const auto &function) {
1471 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1473 if (function.isEmpty())
1475 if (function.contains(
"6QDebug"_L1))
1477 if (function.contains(
"14QMessageLogger"_L1))
1479 if (function.contains(
"17qt_message_output"_L1))
1481 if (function.contains(
"26QInternalMessageLogContext"_L1))
1486 auto demangled = [](
auto &function) -> QString {
1487 if (!function.startsWith(
"_Z"_L1))
1492 if constexpr (
sizeof(function.at(0)) == 1)
1493 return function.data();
1495 return std::move(function).toUtf8();
1497 auto cleanup = [](
auto *p) { free(p); };
1498 using Ptr = std::unique_ptr<
char,
decltype(cleanup)>;
1499 auto demangled = Ptr(abi::__cxa_demangle(fn,
nullptr,
nullptr,
nullptr), cleanup);
1502 return QString::fromUtf8(qCleanupFuncinfo(demangled.get()));
1504 return QString::fromUtf8(fn);
1507# if QT_CONFIG(dladdr)
1509 QString cachedLibrary;
1510 const char *cachedFname =
nullptr;
1511 auto decodeFrame = [&](
void *addr) -> DecodedFrame {
1513 if (!dladdr(addr, &info))
1517 QLatin1StringView fn(info.dli_sname);
1518 QLatin1StringView lib;
1519 if (
const char *lastSlash = strrchr(info.dli_fname,
'/'))
1520 lib = QLatin1StringView(lastSlash + 1);
1522 lib = QLatin1StringView(info.dli_fname);
1524 if (shouldSkipFrame(lib, fn))
1527 QString function = demangled(fn);
1528 if (lib.data() != cachedFname) {
1529 cachedFname = lib.data();
1530 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1532 return { cachedLibrary, function };
1540 static const QRegularExpression rx(QStringLiteral(
"^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1542 auto decodeFrame = [&](
void *&addr) -> DecodedFrame {
1543 auto cleanup = [](
auto *p) { free(p); };
1545 std::unique_ptr<
char *,
decltype(cleanup)>(backtrace_symbols(&addr, 1), cleanup);
1546 QString trace = QString::fromUtf8(strings.get()[0]);
1547 QRegularExpressionMatch m = rx.match(trace);
1551 QString library = m.captured(1);
1552 QString function = m.captured(2);
1555 if (shouldSkipFrame(library, function))
1558 function = demangled(function);
1559 return { library, function };
1563 for (
void *
const &addr : buffer) {
1564 DecodedFrame frame = decodeFrame(addr);
1565 if (!frame.library.isEmpty()) {
1566 if (frame.function.isEmpty())
1567 result.append(u'?' + frame.library + u'?');
1569 result.append(frame.function);
1572 if (!result.isEmpty())
1573 result.append(QStringLiteral(
"???"));
1576 if (result.size() == frameCount)
1582#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1585static QString formatBacktraceForLogMessage(
const QMessagePattern::BacktraceParams backtraceParams,
1586 const QMessageLogContext &ctx)
1589 if (ctx.version <= QMessageLogContext::CurrentVersion)
1592 auto &fullctx =
static_cast<
const QInternalMessageLogContext &>(ctx);
1593 if (!fullctx.backtrace.has_value())
1596 QString backtraceSeparator = backtraceParams.backtraceSeparator;
1597 int backtraceDepth = backtraceParams.backtraceDepth;
1599 QStringList frames = backtraceFramesForLogMessage(backtraceDepth, *fullctx.backtrace);
1600 if (frames.isEmpty())
1604 if (ctx.function && frames.at(0).startsWith(u'?'))
1605 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1607 return frames.join(backtraceSeparator);
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1635 return formatLogMessage(type, context, str);
1650 message.append(str);
1656 int timeArgsIdx = 0;
1657#ifdef QLOGGING_HAVE_BACKTRACE
1658 int backtraceArgsIdx = 0;
1662 for (
int i = 0; pattern->tokens[i]; ++i) {
1663 const char *token = pattern->tokens[i];
1671#ifdef QLOGGING_HAVE_BACKTRACE
1672 else if (token == backtraceTokenC)
1676 message.append(str);
1678 message.append(QLatin1StringView(context
.category));
1681 case QtDebugMsg: message.append(
"debug"_L1);
break;
1682 case QtInfoMsg: message.append(
"info"_L1);
break;
1683 case QtWarningMsg: message.append(
"warning"_L1);
break;
1685 case QtFatalMsg: message.append(
"fatal"_L1);
break;
1689 message.append(QLatin1StringView(context
.file));
1691 message.append(
"unknown"_L1);
1693 message.append(QString::number(context.line));
1696 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1698 message.append(
"unknown"_L1);
1700 message.append(QString::number(QCoreApplication::applicationPid()));
1702 message.append(QCoreApplication::applicationName());
1705 message.append(QString::number(qt_gettid()));
1707 if (!qt_append_thread_name_to(message))
1708 message.append(QString::number(qt_gettid()));
1710 message.append(
"0x"_L1);
1711 message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1712#ifdef QLOGGING_HAVE_BACKTRACE
1713 }
else if (token == backtraceTokenC) {
1714 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1716 message.append(formatBacktraceForLogMessage(backtraceParams, context));
1719 using namespace std::chrono;
1720 auto formatElapsedTime = [](steady_clock::duration time) {
1722 auto ms = duration_cast<milliseconds>(time);
1723 auto sec = duration_cast<seconds>(ms);
1725 return QString::asprintf(
"%6lld.%03u", qint64(sec.count()), uint(ms.count()));
1727 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1729 if (timeFormat ==
"process"_L1) {
1730 message += formatElapsedTime(steady_clock::now() - pattern->appStartTime);
1731 }
else if (timeFormat ==
"boot"_L1) {
1734 message += formatElapsedTime(steady_clock::now().time_since_epoch());
1735#if QT_CONFIG(datestring)
1736 }
else if (timeFormat.isEmpty()) {
1737 message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1739 message.append(QDateTime::currentDateTime().toString(timeFormat));
1745#define HANDLE_IF_TOKEN(LEVEL)
1746 } else if (token == if##LEVEL##TokenC) {
1747 skip = type != Qt##LEVEL##Msg;
1753#undef HANDLE_IF_TOKEN
1755 message.append(QLatin1StringView(token));
1764Q_CONSTINIT
static QBasicAtomicPointer<
void (QtMsgType,
const QMessageLogContext &,
const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(
nullptr);
1770#define QT_LOG_CODE 9000
1773static bool slog2_default_handler(QtMsgType type,
const QMessageLogContext &,
1774 const QString &message)
1776 if (shouldLogToStderr())
1779 QString formattedMessage = message;
1780 formattedMessage.append(u'\n');
1781 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1782 slog2_buffer_set_config_t buffer_config;
1783 slog2_buffer_t buffer_handle;
1785 buffer_config.buffer_set_name = __progname;
1786 buffer_config.num_buffers = 1;
1787 buffer_config.verbosity_level = SLOG2_DEBUG1;
1788 buffer_config.buffer_config[0].buffer_name =
"default";
1789 buffer_config.buffer_config[0].num_pages = 8;
1791 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1792 fprintf(stderr,
"Error registering slogger2 buffer!\n");
1793 fprintf(stderr,
"%s", formattedMessage.toLocal8Bit().constData());
1799 slog2_set_default_buffer(buffer_handle);
1801 int severity = SLOG2_INFO;
1805 severity = SLOG2_DEBUG1;
1808 severity = SLOG2_INFO;
1811 severity = SLOG2_NOTICE;
1814 severity = SLOG2_WARNING;
1817 severity = SLOG2_ERROR;
1821 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1827#if QT_CONFIG(journald)
1828static bool systemd_default_message_handler(QtMsgType type,
1829 const QMessageLogContext &context,
1830 const QString &message)
1832 if (shouldLogToStderr())
1835 int priority = LOG_INFO;
1838 priority = LOG_DEBUG;
1841 priority = LOG_INFO;
1844 priority = LOG_WARNING;
1847 priority = LOG_CRIT;
1850 priority = LOG_ALERT;
1855 const QByteArray messageField =
"MESSAGE="_ba + message.toUtf8().constData();
1856 const QByteArray priorityField =
"PRIORITY="_ba + QByteArray::number(priority);
1857 const QByteArray tidField =
"TID="_ba + QByteArray::number(qlonglong(qt_gettid()));
1858 const QByteArray fileField = context.file
1859 ?
"CODE_FILE="_ba + context.file : QByteArray();
1860 const QByteArray funcField = context.function
1861 ?
"CODE_FUNC="_ba + context.function : QByteArray();
1862 const QByteArray lineField = context.line
1863 ?
"CODE_LINE="_ba + QByteArray::number(context.line) : QByteArray();
1864 const QByteArray categoryField = context.category
1865 ?
"QT_CATEGORY="_ba + context.category : QByteArray();
1867 auto toIovec = [](
const QByteArray &ba) {
1868 return iovec{
const_cast<
char*>(ba.data()), size_t(ba.size()) };
1871 struct iovec fields[7] = {
1872 toIovec(messageField),
1873 toIovec(priorityField),
1878 fields[nFields++] = toIovec(fileField);
1879 if (context.function)
1880 fields[nFields++] = toIovec(funcField);
1882 fields[nFields++] = toIovec(lineField);
1883 if (context.category)
1884 fields[nFields++] = toIovec(categoryField);
1886 sd_journal_sendv(fields, nFields);
1892#if QT_CONFIG(syslog)
1893static bool syslog_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
1894 const QString &formattedMessage)
1896 if (shouldLogToStderr())
1899 int priority = LOG_INFO;
1902 priority = LOG_DEBUG;
1905 priority = LOG_INFO;
1908 priority = LOG_WARNING;
1911 priority = LOG_CRIT;
1914 priority = LOG_ALERT;
1918 syslog(priority,
"%s", formattedMessage.toUtf8().constData());
1925static bool android_default_message_handler(QtMsgType type,
1926 const QMessageLogContext &context,
1927 const QString &formattedMessage)
1929 if (shouldLogToStderr())
1932 android_LogPriority priority = ANDROID_LOG_DEBUG;
1935 priority = ANDROID_LOG_DEBUG;
1938 priority = ANDROID_LOG_INFO;
1941 priority = ANDROID_LOG_WARN;
1944 priority = ANDROID_LOG_ERROR;
1947 priority = ANDROID_LOG_FATAL;
1951 QMessagePattern *pattern = qMessagePattern();
1952 const QString tag = (pattern && pattern->containsToken(categoryTokenC))
1954 ? QCoreApplication::applicationName().replace(u' ', u'_')
1955 : QString::fromUtf8(context.category);
1956 __android_log_print(priority, qPrintable(tag),
"%s\n", qPrintable(formattedMessage));
1963static void win_outputDebugString_helper(
const QString &message)
1965 const qsizetype maxOutputStringLength = 32766;
1966 Q_CONSTINIT
static QBasicMutex m;
1967 auto locker = qt_unique_lock(m);
1969 if (message.length() <= maxOutputStringLength) {
1970 OutputDebugString(
reinterpret_cast<
const wchar_t *>(message.utf16()));
1972 wchar_t messagePart[maxOutputStringLength + 1];
1973 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
1974 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
1975 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
1976 Q_ASSERT(len == length);
1977 messagePart[len] = 0;
1978 OutputDebugString(messagePart);
1983static bool win_message_handler(QtMsgType,
const QMessageLogContext &,
1984 const QString &formattedMessage)
1986 if (shouldLogToStderr())
1989 win_outputDebugString_helper(formattedMessage + u'\n');
1996static bool wasm_default_message_handler(QtMsgType type,
1997 const QMessageLogContext &,
1998 const QString &formattedMessage)
2000 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
2001 if (forceStderrLogging)
2004 int emOutputFlags = EM_LOG_CONSOLE;
2005 QByteArray localMsg = formattedMessage.toLocal8Bit();
2012 emOutputFlags |= EM_LOG_WARN;
2015 emOutputFlags |= EM_LOG_ERROR;
2018 emOutputFlags |= EM_LOG_ERROR;
2020 emscripten_log(emOutputFlags,
"%s\n", qPrintable(formattedMessage));
2029 const QString &formattedMessage)
2036 if (formattedMessage.isNull())
2038 fprintf(stderr,
"%s\n", formattedMessage.toLocal8Bit().constData());
2043struct SystemMessageSink
2047 bool messageIsUnformatted =
false;
2052#if defined(Q_OS_WIN)
2054#elif QT_CONFIG(slog2)
2055 slog2_default_handler
2056#elif QT_CONFIG(journald)
2057 systemd_default_message_handler,
true
2058#elif QT_CONFIG(syslog)
2059 syslog_default_message_handler
2060#elif defined(Q_OS_ANDROID)
2061 android_default_message_handler
2062#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
2063 AppleUnifiedLogger::messageHandler,
true
2064#elif defined Q_OS_WASM
2065 wasm_default_message_handler
2072 const QString &formattedMessage)
2075QT_WARNING_DISABLE_GCC(
"-Waddress")
2076 if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
2080 stderr_message_handler(type, context, formattedMessage);
2084
2085
2087 const QString &message)
2098 preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
2123 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2124 if (!defaultCategory->isEnabled(msgType))
2133 auto msgHandler = messageHandler.loadAcquire();
2140template <
typename String>
static void
2145#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2146 wchar_t contextFileL[256];
2150 convert_to_wchar_t_elided(contextFileL,
sizeof contextFileL /
sizeof *contextFileL,
2153 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2154 _CrtSetReportMode(_CRT_ERROR, reportMode);
2156 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2157 reinterpret_cast<
const wchar_t *>(message.utf16()));
2158 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2166 if constexpr (
std::is_class_v<String> && !
std::is_const_v<String>)
2174
2175
2179 qt_message_print(msgType, ctx, message);
2180 qt_maybe_message_fatal(msgType, ctx, message);
2187 QString error_string = qt_error_string(-1);
2191 QString buf = QString::vasprintf(msg, ap);
2194 buf +=
" ("_L1 + error_string + u')';
2196 qt_message_output(QtWarningMsg, context, buf);
2205 QString buf = QString::vasprintf(msg, ap);
2208 buf +=
" ("_L1 + qt_error_string(code) + u')';
2210 qt_message_output(QtWarningMsg, context, buf);
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
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
2286
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
2376
2380 const auto old = messageHandler.fetchAndStoreOrdered(h);
2391 if (!qMessagePattern()->fromEnvironment)
2392 qMessagePattern()->setPattern(pattern);
2398 if (logContext.version == self->version) {
2399 auto other =
static_cast<
const QInternalMessageLogContext *>(&logContext);
2400 self->backtrace = other->backtrace;
2405
2406
2407
2408
2411 version = CurrentVersion + 1;
2412 copyContextFrom(logContext);
2414#ifdef QLOGGING_HAVE_BACKTRACE
2415 if (backtrace.has_value())
2419 if (
auto pattern = qMessagePattern())
2420 return pattern->maxBacktraceDepth;
2427
2428
2429
2430
2431
2432
2433
2440 if (Q_UNLIKELY(version == CurrentVersion + 1))
2441 copyInternalContext(
static_cast<QInternalMessageLogContext *>(
this), logContext);
2446
2447
2448
2449
2450
2453
2454
2455
2456
2457
2459
2460
2461
2462
2463
2464
2465
2468
2469
2470
2471
2472
2473
2474
2477
2478
2479
2480
2481
2484
2485
2486
2487
2488
2489
2490
2491
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
2521
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
2552
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
2591
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
2629
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
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