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>
93using namespace Qt::StringLiterals;
98
99
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
129template <
typename String>
133 const QString &formattedMessage);
146 int value = str.toInt(&ok, 0);
147 return ok ? value : 1;
155 int v = n.loadRelaxed();
156 while (v != 0 && !n.testAndSetRelaxed(v, v - 1, v))
168 return is_fatal_count_down(fatalCriticals);
171 if (msgType == QtWarningMsg || msgType == QtCriticalMsg) {
173 return is_fatal_count_down(fatalWarnings);
182
183
184
185
186
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
214 static const bool stderrHasConsoleAttached = []() ->
bool {
218 if (qEnvironmentVariableIntValue(
"QT_LOGGING_TO_CONSOLE")) {
219 fprintf(stderr,
"warning: Environment variable QT_LOGGING_TO_CONSOLE is deprecated, use\n"
220 "QT_ASSUME_STDERR_HAS_CONSOLE and/or QT_FORCE_STDERR_LOGGING instead.\n");
224 if (qEnvironmentVariableIntValue(
"QT_ASSUME_STDERR_HAS_CONSOLE"))
228 return GetConsoleWindow();
229#elif defined(Q_OS_UNIX)
231# define _PATH_TTY "/dev/tty"
236 if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
237 qt_safe_close(ttyDevice);
239 }
else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
241 return isatty(STDERR_FILENO);
250 return stderrHasConsoleAttached;
257
258
259
260
261
262
263
264
267 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
279
280
281
282
283
284
285
286
287
288
289
290
291
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
312#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
313static inline void convert_to_wchar_t_elided(
wchar_t *d, size_t space,
const char *s)
noexcept
315 size_t len = qstrlen(s);
316 if (len + 1 > space) {
317 const size_t skip = len - space + 4;
320 for (
int i = 0; i < 3; ++i)
330
331
335 QString buf = QString::vasprintf(msg, ap);
336 qt_message_print(msgType, context, buf);
337 qt_maybe_message_fatal(msgType, context, buf);
341
342
343
344
345
346void QMessageLogger::debug(
const char *msg, ...)
const
348 QInternalMessageLogContext ctxt(context);
351 qt_message(QtDebugMsg, ctxt, msg, ap);
356
357
358
359
360
361
362void QMessageLogger::info(
const char *msg, ...)
const
364 QInternalMessageLogContext ctxt(context);
367 qt_message(QtInfoMsg, ctxt, msg, ap);
372
373
374
375
376
377
378
379
380
381
382
383
384
385
388
389
390
391
392
393
394void QMessageLogger::debug(
const QLoggingCategory &cat,
const char *msg, ...)
const
396 if (!cat.isDebugEnabled())
399 QInternalMessageLogContext ctxt(context, cat());
403 qt_message(QtDebugMsg, ctxt, msg, ap);
408
409
410
411
412
413
414void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
415 const char *msg, ...)
const
417 const QLoggingCategory &cat = (*catFunc)();
418 if (!cat.isDebugEnabled())
421 QInternalMessageLogContext ctxt(context, cat());
425 qt_message(QtDebugMsg, ctxt, msg, ap);
429#ifndef QT_NO_DEBUG_STREAM
432
433
434
435
436QDebug QMessageLogger::debug()
const
438 QDebug dbg = QDebug(QtDebugMsg);
439 QMessageLogContext &ctxt = dbg.stream->context;
440 ctxt.copyContextFrom(context);
445
446
447
448
449
450QDebug QMessageLogger::debug(
const QLoggingCategory &cat)
const
452 QDebug dbg = QDebug(QtDebugMsg);
453 if (!cat.isDebugEnabled())
454 dbg.stream->message_output =
false;
456 QMessageLogContext &ctxt = dbg.stream->context;
457 ctxt.copyContextFrom(context);
458 ctxt.category = cat.categoryName();
464
465
466
467
468
469QDebug QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc)
const
471 return debug((*catFunc)());
476
477
478
479
480
481
482void QMessageLogger::info(
const QLoggingCategory &cat,
const char *msg, ...)
const
484 if (!cat.isInfoEnabled())
487 QInternalMessageLogContext ctxt(context, cat());
491 qt_message(QtInfoMsg, ctxt, msg, ap);
496
497
498
499
500
501
502void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
503 const char *msg, ...)
const
505 const QLoggingCategory &cat = (*catFunc)();
506 if (!cat.isInfoEnabled())
509 QInternalMessageLogContext ctxt(context, cat());
513 qt_message(QtInfoMsg, ctxt, msg, ap);
517#ifndef QT_NO_DEBUG_STREAM
520
521
522
523
524
525QDebug QMessageLogger::info()
const
527 QDebug dbg = QDebug(QtInfoMsg);
528 QMessageLogContext &ctxt = dbg.stream->context;
529 ctxt.copyContextFrom(context);
534
535
536
537
538
539QDebug QMessageLogger::info(
const QLoggingCategory &cat)
const
541 QDebug dbg = QDebug(QtInfoMsg);
542 if (!cat.isInfoEnabled())
543 dbg.stream->message_output =
false;
545 QMessageLogContext &ctxt = dbg.stream->context;
546 ctxt.copyContextFrom(context);
547 ctxt.category = cat.categoryName();
553
554
555
556
557
558QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc)
const
560 return info((*catFunc)());
566
567
568
569
570
571void QMessageLogger::warning(
const char *msg, ...)
const
573 QInternalMessageLogContext ctxt(context);
576 qt_message(QtWarningMsg, ctxt, msg, ap);
581
582
583
584
585
586
587void QMessageLogger::warning(
const QLoggingCategory &cat,
const char *msg, ...)
const
589 if (!cat.isWarningEnabled())
592 QInternalMessageLogContext ctxt(context, cat());
596 qt_message(QtWarningMsg, ctxt, msg, ap);
601
602
603
604
605
606
607void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
608 const char *msg, ...)
const
610 const QLoggingCategory &cat = (*catFunc)();
611 if (!cat.isWarningEnabled())
614 QInternalMessageLogContext ctxt(context, cat());
618 qt_message(QtWarningMsg, ctxt, msg, ap);
622#ifndef QT_NO_DEBUG_STREAM
624
625
626
627
628QDebug QMessageLogger::warning()
const
630 QDebug dbg = QDebug(QtWarningMsg);
631 QMessageLogContext &ctxt = dbg.stream->context;
632 ctxt.copyContextFrom(context);
637
638
639
640
641QDebug QMessageLogger::warning(
const QLoggingCategory &cat)
const
643 QDebug dbg = QDebug(QtWarningMsg);
644 if (!cat.isWarningEnabled())
645 dbg.stream->message_output =
false;
647 QMessageLogContext &ctxt = dbg.stream->context;
648 ctxt.copyContextFrom(context);
649 ctxt.category = cat.categoryName();
655
656
657
658
659
660QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc)
const
662 return warning((*catFunc)());
668
669
670
671
672
673void QMessageLogger::critical(
const char *msg, ...)
const
675 QInternalMessageLogContext ctxt(context);
678 qt_message(QtCriticalMsg, ctxt, msg, ap);
683
684
685
686
687
688
689void QMessageLogger::critical(
const QLoggingCategory &cat,
const char *msg, ...)
const
691 if (!cat.isCriticalEnabled())
694 QInternalMessageLogContext ctxt(context, cat());
698 qt_message(QtCriticalMsg, ctxt, msg, ap);
703
704
705
706
707
708
709void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
710 const char *msg, ...)
const
712 const QLoggingCategory &cat = (*catFunc)();
713 if (!cat.isCriticalEnabled())
716 QInternalMessageLogContext ctxt(context, cat());
720 qt_message(QtCriticalMsg, ctxt, msg, ap);
724#ifndef QT_NO_DEBUG_STREAM
726
727
728
729
730QDebug QMessageLogger::critical()
const
732 QDebug dbg = QDebug(QtCriticalMsg);
733 QMessageLogContext &ctxt = dbg.stream->context;
734 ctxt.copyContextFrom(context);
739
740
741
742
743
744QDebug QMessageLogger::critical(
const QLoggingCategory &cat)
const
746 QDebug dbg = QDebug(QtCriticalMsg);
747 if (!cat.isCriticalEnabled())
748 dbg.stream->message_output =
false;
750 QMessageLogContext &ctxt = dbg.stream->context;
751 ctxt.copyContextFrom(context);
752 ctxt.category = cat.categoryName();
758
759
760
761
762
763QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc)
const
765 return critical((*catFunc)());
771
772
773
774
775
776
777void QMessageLogger::fatal(
const QLoggingCategory &cat,
const char *msg, ...)
const noexcept
779 QInternalMessageLogContext ctxt(context, cat());
783 qt_message(QtFatalMsg, ctxt, msg, ap);
786#ifndef Q_CC_MSVC_ONLY
792
793
794
795
796
797
798void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
799 const char *msg, ...)
const noexcept
801 const QLoggingCategory &cat = (*catFunc)();
803 QInternalMessageLogContext ctxt(context, cat());
807 qt_message(QtFatalMsg, ctxt, msg, ap);
810#ifndef Q_CC_MSVC_ONLY
816
817
818
819
820
821void QMessageLogger::fatal(
const char *msg, ...)
const noexcept
823 QInternalMessageLogContext ctxt(context);
826 qt_message(QtFatalMsg, ctxt, msg, ap);
829#ifndef Q_CC_MSVC_ONLY
834#ifndef QT_NO_DEBUG_STREAM
836
837
838
839
840
841
842QDebug QMessageLogger::fatal()
const
844 QDebug dbg = QDebug(QtFatalMsg);
845 QMessageLogContext &ctxt = dbg.stream->context;
846 ctxt.copyContextFrom(context);
851
852
853
854
855
856QDebug QMessageLogger::fatal(
const QLoggingCategory &cat)
const
858 QDebug dbg = QDebug(QtFatalMsg);
860 QMessageLogContext &ctxt = dbg.stream->context;
861 ctxt.copyContextFrom(context);
862 ctxt.category = cat.categoryName();
868
869
870
871
872
873QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc)
const
875 return fatal((*catFunc)());
881 return !category || strcmp(category,
"default") == 0;
885
886
900 pos = info.size() - 1;
901 if (info.endsWith(
']') && !(info.startsWith(
'+') || info.startsWith(
'-'))) {
903 if (info.at(pos) ==
'[') {
908 if (info.endsWith(
' ')) {
914 static const char operator_call[] =
"operator()";
915 static const char operator_lessThan[] =
"operator<";
916 static const char operator_greaterThan[] =
"operator>";
917 static const char operator_lessThanEqual[] =
"operator<=";
918 static const char operator_greaterThanEqual[] =
"operator>=";
921 info.replace(
"operator ",
"operator");
927 pos = info.lastIndexOf(
')', pos);
932 if (info.indexOf(
'>', pos) != -1
933 || info.indexOf(
':', pos) != -1) {
942 while (pos && parencount) {
943 if (info.at(pos) ==
')')
945 else if (info.at(pos) ==
'(')
952 info.truncate(++pos);
954 if (info.at(pos - 1) ==
')') {
955 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
961 info.remove(0, info.indexOf(
'('));
971 int templatecount = 0;
976 switch (info.at(pos)) {
978 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
982 if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
986 if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
990 auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
991 if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
993 else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
1003 if (parencount < 0 || templatecount < 0)
1006 char c = info.at(pos);
1015 else if (c ==
' ' && templatecount == 0 && parencount == 0)
1020 info = info.mid(pos + 1);
1023 while ((info.at(0) ==
'*')
1024 || (info.at(0) ==
'&'))
1029 while ((pos = info.lastIndexOf(
'>')) != -1) {
1030 if (!info.contains(
'<'))
1034 qsizetype end = pos;
1037 while (pos && templatecount) {
1038 char c = info.at(pos);
1046 info.remove(pos, end - pos + 1);
1082 const char *
const defaultTokens[] = {
1095 Q_ASSERT(!literals);
1097 auto ptr =
new const char *[
std::size(defaultTokens) + 1];
1098 auto end =
std::copy(
std::begin(defaultTokens),
std::end(defaultTokens), ptr);
1114#ifdef QLOGGING_HAVE_BACKTRACE
1136Q_CONSTINIT QBasicMutex QMessagePattern::mutex;
1140 const QString envPattern = qEnvironmentVariable(
"QT_MESSAGE_PATTERN");
1141 if (envPattern.isEmpty()) {
1155#ifdef QLOGGING_HAVE_BACKTRACE
1156 backtraceArgs.clear();
1157 maxBacktraceDepth = 0;
1161 QList<QString> lexemes;
1163 bool inPlaceholder =
false;
1164 for (
int i = 0; i < pattern.size(); ++i) {
1165 const QChar c = pattern.at(i);
1166 if (c == u'%' && !inPlaceholder) {
1167 if ((i + 1 < pattern.size())
1168 && pattern.at(i + 1) == u'{') {
1170 if (!lexeme.isEmpty()) {
1171 lexemes.append(lexeme);
1174 inPlaceholder =
true;
1180 if (c == u'}' && inPlaceholder) {
1182 lexemes.append(lexeme);
1184 inPlaceholder =
false;
1187 if (!lexeme.isEmpty())
1188 lexemes.append(lexeme);
1191 std::vector<std::unique_ptr<
const char[]>> literalsVar;
1192 tokens.reset(
new const char *[lexemes.size() + 1]);
1193 tokens[lexemes.size()] =
nullptr;
1195 bool nestedIfError =
false;
1199 for (
int i = 0; i < lexemes.size(); ++i) {
1200 const QString lexeme = lexemes.at(i);
1201 if (lexeme.startsWith(
"%{"_L1) && lexeme.endsWith(u'}')) {
1203 if (lexeme == QLatin1StringView(
typeTokenC)) {
1204 tokens[i] = typeTokenC;
1206 tokens[i] = categoryTokenC;
1208 tokens[i] = messageTokenC;
1209 else if (lexeme == QLatin1StringView(
fileTokenC))
1210 tokens[i] = fileTokenC;
1211 else if (lexeme == QLatin1StringView(
lineTokenC))
1212 tokens[i] = lineTokenC;
1214 tokens[i] = functionTokenC;
1215 else if (lexeme == QLatin1StringView(
pidTokenC))
1216 tokens[i] = pidTokenC;
1218 tokens[i] = appnameTokenC;
1220 tokens[i] = threadidTokenC;
1222 tokens[i] = qthreadptrTokenC;
1223 else if (lexeme.startsWith(QLatin1StringView(
timeTokenC))) {
1224 tokens[i] = timeTokenC;
1225 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(
' '));
1227 timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2));
1229 timeArgs.append(QString());
1231#ifdef QLOGGING_HAVE_BACKTRACE
1232 tokens[i] = backtraceTokenC;
1233 QString backtraceSeparator = QStringLiteral(
"|");
1234 int backtraceDepth = 5;
1235 static const QRegularExpression depthRx(QStringLiteral(
" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1236 static const QRegularExpression separatorRx(QStringLiteral(
" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1237 QRegularExpressionMatch m = depthRx.match(lexeme);
1239 int depth = m.capturedView(1).toInt();
1241 error +=
"QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1243 backtraceDepth = depth;
1245 m = separatorRx.match(lexeme);
1247 backtraceSeparator = m.captured(1);
1248 BacktraceParams backtraceParams;
1249 backtraceParams.backtraceDepth = backtraceDepth;
1250 backtraceParams.backtraceSeparator = backtraceSeparator;
1251 backtraceArgs.append(backtraceParams);
1252 maxBacktraceDepth = qMax(maxBacktraceDepth, backtraceDepth);
1254 error +=
"QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1259#define IF_TOKEN(LEVEL)
1260 else if (lexeme == QLatin1StringView(LEVEL)) {
1262 nestedIfError = true;
1273 else if (lexeme == QLatin1StringView(
endifTokenC)) {
1274 tokens[i] = endifTokenC;
1275 if (!inIf && !nestedIfError)
1276 error +=
"QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1279 tokens[i] = emptyTokenC;
1280 error +=
"QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme +
'\n'_L1;
1283 using UP = std::unique_ptr<
char[]>;
1284 tokens[i] = literalsVar.emplace_back(UP(qstrdup(lexeme.toLatin1().constData()))).get();
1288 error +=
"QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1290 error +=
"QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1292 if (!error.isEmpty()) {
1297 "QMessagePattern::setPattern", nullptr);
1298 preformattedMessageHandler(QtWarningMsg, ctx, error);
1301 literals.reset(
new std::unique_ptr<
const char[]>[literalsVar.size() + 1]);
1302 std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
1305#if defined(QLOGGING_HAVE_BACKTRACE)
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318static constexpr int TypicalBacktraceFrameCount = 3;
1319static constexpr const char *QtCoreLibraryName =
"Qt" QT_STRINGIFY(QT_VERSION_MAJOR)
"Core";
1321#if defined(QLOGGING_USE_STD_BACKTRACE)
1322Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1324 assert(frameCount >= 0);
1325 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1329backtraceFramesForLogMessage(
int frameCount,
1330 const QInternalMessageLogContext::BacktraceStorage &buffer)
1333 result.reserve(buffer.size());
1335 const auto shouldSkipFrame = [](QByteArrayView description)
1337#if defined(_MSVC_STL_VERSION)
1338 const auto libraryNameEnd = description.indexOf(
'!');
1339 if (libraryNameEnd != -1) {
1340 const auto libraryName = description.first(libraryNameEnd);
1341 if (!libraryName.contains(QtCoreLibraryName))
1345 if (description.contains(
"populateBacktrace"))
1347 if (description.contains(
"QInternalMessageLogContext"))
1349 if (description.contains(
"~QDebug"))
1354 for (
const auto &entry : buffer) {
1355 const std::string description = entry.description();
1356 if (result.isEmpty() && shouldSkipFrame(description))
1358 result.append(QString::fromStdString(description));
1364#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1366Q_NEVER_INLINE
void QInternalMessageLogContext::populateBacktrace(
int frameCount)
1368 assert(frameCount >= 0);
1369 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1370 int n = ::backtrace(result.data(), result.size());
1378backtraceFramesForLogMessage(
int frameCount,
1379 const QInternalMessageLogContext::BacktraceStorage &buffer)
1381 struct DecodedFrame {
1387 if (frameCount == 0)
1390 auto shouldSkipFrame = [&result](
const auto &library,
const auto &function) {
1391 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1393 if (function.isEmpty())
1395 if (function.contains(
"6QDebug"_L1))
1397 if (function.contains(
"14QMessageLogger"_L1))
1399 if (function.contains(
"17qt_message_output"_L1))
1401 if (function.contains(
"26QInternalMessageLogContext"_L1))
1406 auto demangled = [](
auto &function) -> QString {
1407 if (!function.startsWith(
"_Z"_L1))
1412 if constexpr (
sizeof(function.at(0)) == 1)
1413 return function.data();
1415 return std::move(function).toUtf8();
1417 QScopedPointer<
char, QScopedPointerPodDeleter> demangled;
1418 demangled.reset(abi::__cxa_demangle(fn,
nullptr,
nullptr,
nullptr));
1421 return QString::fromUtf8(qCleanupFuncinfo(demangled.data()));
1423 return QString::fromUtf8(fn);
1426# if QT_CONFIG(dladdr)
1428 QString cachedLibrary;
1429 const char *cachedFname =
nullptr;
1430 auto decodeFrame = [&](
void *addr) -> DecodedFrame {
1432 if (!dladdr(addr, &info))
1436 QLatin1StringView fn(info.dli_sname);
1437 QLatin1StringView lib;
1438 if (
const char *lastSlash = strrchr(info.dli_fname,
'/'))
1439 lib = QLatin1StringView(lastSlash + 1);
1441 lib = QLatin1StringView(info.dli_fname);
1443 if (shouldSkipFrame(lib, fn))
1446 QString function = demangled(fn);
1447 if (lib.data() != cachedFname) {
1448 cachedFname = lib.data();
1449 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1451 return { cachedLibrary, function };
1459 static const QRegularExpression rx(QStringLiteral(
"^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1461 auto decodeFrame = [&](
void *&addr) -> DecodedFrame {
1462 QScopedPointer<
char*, QScopedPointerPodDeleter> strings(backtrace_symbols(&addr, 1));
1463 QString trace = QString::fromUtf8(strings.data()[0]);
1464 QRegularExpressionMatch m = rx.match(trace);
1468 QString library = m.captured(1);
1469 QString function = m.captured(2);
1472 if (shouldSkipFrame(library, function))
1475 function = demangled(function);
1476 return { library, function };
1480 for (
void *
const &addr : buffer) {
1481 DecodedFrame frame = decodeFrame(addr);
1482 if (!frame.library.isEmpty()) {
1483 if (frame.function.isEmpty())
1484 result.append(u'?' + frame.library + u'?');
1486 result.append(frame.function);
1489 if (!result.isEmpty())
1490 result.append(QStringLiteral(
"???"));
1493 if (result.size() == frameCount)
1499#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1502static QString formatBacktraceForLogMessage(
const QMessagePattern::BacktraceParams backtraceParams,
1503 const QMessageLogContext &ctx)
1506 if (ctx.version <= QMessageLogContext::CurrentVersion)
1509 auto &fullctx =
static_cast<
const QInternalMessageLogContext &>(ctx);
1510 if (!fullctx.backtrace.has_value())
1513 QString backtraceSeparator = backtraceParams.backtraceSeparator;
1514 int backtraceDepth = backtraceParams.backtraceDepth;
1516 QStringList frames = backtraceFramesForLogMessage(backtraceDepth, *fullctx.backtrace);
1517 if (frames.isEmpty())
1521 if (ctx.function && frames.at(0).startsWith(u'?'))
1522 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1524 return frames.join(backtraceSeparator);
1527void QInternalMessageLogContext::populateBacktrace(
int)
1534Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550QString qFormatLogMessage(QtMsgType type,
const QMessageLogContext &context,
const QString &str)
1552 return formatLogMessage(type, context, str);
1558static QString formatLogMessage(QtMsgType type,
const QMessageLogContext &context,
const QString &str)
1562 const auto locker = qt_scoped_lock(QMessagePattern::mutex);
1564 QMessagePattern *pattern = qMessagePattern();
1567 message.append(str);
1573 int timeArgsIdx = 0;
1574#ifdef QLOGGING_HAVE_BACKTRACE
1575 int backtraceArgsIdx = 0;
1579 for (
int i = 0; pattern->tokens[i]; ++i) {
1580 const char *token = pattern->tokens[i];
1581 if (token == endifTokenC) {
1586 if (token == timeTokenC)
1588#ifdef QLOGGING_HAVE_BACKTRACE
1589 else if (token == backtraceTokenC)
1592 }
else if (token == messageTokenC) {
1593 message.append(str);
1594 }
else if (token == categoryTokenC) {
1595 message.append(QLatin1StringView(context.category));
1596 }
else if (token == typeTokenC) {
1598 case QtDebugMsg: message.append(
"debug"_L1);
break;
1599 case QtInfoMsg: message.append(
"info"_L1);
break;
1600 case QtWarningMsg: message.append(
"warning"_L1);
break;
1601 case QtCriticalMsg:message.append(
"critical"_L1);
break;
1602 case QtFatalMsg: message.append(
"fatal"_L1);
break;
1604 }
else if (token == fileTokenC) {
1606 message.append(QLatin1StringView(context.file));
1608 message.append(
"unknown"_L1);
1609 }
else if (token == lineTokenC) {
1610 message.append(QString::number(context.line));
1611 }
else if (token == functionTokenC) {
1612 if (context.function)
1613 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1615 message.append(
"unknown"_L1);
1616 }
else if (token == pidTokenC) {
1617 message.append(QString::number(QCoreApplication::applicationPid()));
1618 }
else if (token == appnameTokenC) {
1619 message.append(QCoreApplication::applicationName());
1620 }
else if (token == threadidTokenC) {
1622 message.append(QString::number(qt_gettid()));
1623 }
else if (token == qthreadptrTokenC) {
1624 message.append(
"0x"_L1);
1625 message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1626#ifdef QLOGGING_HAVE_BACKTRACE
1627 }
else if (token == backtraceTokenC) {
1628 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1630 message.append(formatBacktraceForLogMessage(backtraceParams, context));
1632 }
else if (token == timeTokenC) {
1633 using namespace std::chrono;
1634 auto formatElapsedTime = [](steady_clock::duration time) {
1636 auto ms = duration_cast<milliseconds>(time);
1637 auto sec = duration_cast<seconds>(ms);
1639 return QString::asprintf(
"%6lld.%03u", qint64(sec.count()), uint(ms.count()));
1641 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1643 if (timeFormat ==
"process"_L1) {
1644 message += formatElapsedTime(steady_clock::now() - pattern->appStartTime);
1645 }
else if (timeFormat ==
"boot"_L1) {
1648 message += formatElapsedTime(steady_clock::now().time_since_epoch());
1649#if QT_CONFIG(datestring)
1650 }
else if (timeFormat.isEmpty()) {
1651 message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1653 message.append(QDateTime::currentDateTime().toString(timeFormat));
1656 }
else if (token == ifCategoryTokenC) {
1657 if (isDefaultCategory(context.category))
1659#define HANDLE_IF_TOKEN(LEVEL)
1660 } else if (token == if##LEVEL##TokenC) {
1661 skip = type != Qt##LEVEL##Msg;
1667#undef HANDLE_IF_TOKEN
1669 message.append(QLatin1StringView(token));
1675static void qDefaultMessageHandler(QtMsgType type,
const QMessageLogContext &context,
const QString &buf);
1678Q_CONSTINIT
static QBasicAtomicPointer<
void (QtMsgType,
const QMessageLogContext &,
const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(
nullptr);
1684#define QT_LOG_CODE 9000
1687static bool slog2_default_handler(QtMsgType type,
const QMessageLogContext &,
1688 const QString &message)
1690 if (shouldLogToStderr())
1693 QString formattedMessage = message;
1694 formattedMessage.append(u'\n');
1695 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1696 slog2_buffer_set_config_t buffer_config;
1697 slog2_buffer_t buffer_handle;
1699 buffer_config.buffer_set_name = __progname;
1700 buffer_config.num_buffers = 1;
1701 buffer_config.verbosity_level = SLOG2_DEBUG1;
1702 buffer_config.buffer_config[0].buffer_name =
"default";
1703 buffer_config.buffer_config[0].num_pages = 8;
1705 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1706 fprintf(stderr,
"Error registering slogger2 buffer!\n");
1707 fprintf(stderr,
"%s", formattedMessage.toLocal8Bit().constData());
1713 slog2_set_default_buffer(buffer_handle);
1715 int severity = SLOG2_INFO;
1719 severity = SLOG2_DEBUG1;
1722 severity = SLOG2_INFO;
1725 severity = SLOG2_NOTICE;
1728 severity = SLOG2_WARNING;
1731 severity = SLOG2_ERROR;
1735 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1741#if QT_CONFIG(journald)
1742static bool systemd_default_message_handler(QtMsgType type,
1743 const QMessageLogContext &context,
1744 const QString &message)
1746 if (shouldLogToStderr())
1749 int priority = LOG_INFO;
1752 priority = LOG_DEBUG;
1755 priority = LOG_INFO;
1758 priority = LOG_WARNING;
1761 priority = LOG_CRIT;
1764 priority = LOG_ALERT;
1768 sd_journal_send(
"MESSAGE=%s", message.toUtf8().constData(),
1769 "PRIORITY=%i", priority,
1770 "CODE_FUNC=%s", context.function ? context.function :
"unknown",
1771 "CODE_LINE=%d", context.line,
1772 "CODE_FILE=%s", context.file ? context.file :
"unknown",
1773 "QT_CATEGORY=%s", context.category ? context.category :
"unknown",
1780#if QT_CONFIG(syslog)
1781static bool syslog_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
1782 const QString &formattedMessage)
1784 if (shouldLogToStderr())
1787 int priority = LOG_INFO;
1790 priority = LOG_DEBUG;
1793 priority = LOG_INFO;
1796 priority = LOG_WARNING;
1799 priority = LOG_CRIT;
1802 priority = LOG_ALERT;
1806 syslog(priority,
"%s", formattedMessage.toUtf8().constData());
1813static bool android_default_message_handler(QtMsgType type,
1814 const QMessageLogContext &context,
1815 const QString &formattedMessage)
1817 if (shouldLogToStderr())
1820 android_LogPriority priority = ANDROID_LOG_DEBUG;
1823 priority = ANDROID_LOG_DEBUG;
1826 priority = ANDROID_LOG_INFO;
1829 priority = ANDROID_LOG_WARN;
1832 priority = ANDROID_LOG_ERROR;
1835 priority = ANDROID_LOG_FATAL;
1839 QMessagePattern *pattern = qMessagePattern();
1840 const QString tag = (pattern && pattern->containsToken(categoryTokenC))
1842 ? QCoreApplication::applicationName().replace(u' ', u'_')
1843 : QString::fromUtf8(context.category);
1844 __android_log_print(priority, qPrintable(tag),
"%s\n", qPrintable(formattedMessage));
1851static void win_outputDebugString_helper(
const QString &message)
1853 const qsizetype maxOutputStringLength = 32766;
1854 Q_CONSTINIT
static QBasicMutex m;
1855 auto locker = qt_unique_lock(m);
1857 if (message.length() <= maxOutputStringLength) {
1858 OutputDebugString(
reinterpret_cast<
const wchar_t *>(message.utf16()));
1860 wchar_t *messagePart =
new wchar_t[maxOutputStringLength + 1];
1861 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
1862 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
1863 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
1864 Q_ASSERT(len == length);
1865 messagePart[len] = 0;
1866 OutputDebugString(messagePart);
1868 delete[] messagePart;
1872static bool win_message_handler(QtMsgType,
const QMessageLogContext &,
1873 const QString &formattedMessage)
1875 if (shouldLogToStderr())
1878 win_outputDebugString_helper(formattedMessage + u'\n');
1885static bool wasm_default_message_handler(QtMsgType type,
1886 const QMessageLogContext &,
1887 const QString &formattedMessage)
1889 static bool forceStderrLogging = qEnvironmentVariableIntValue(
"QT_FORCE_STDERR_LOGGING");
1890 if (forceStderrLogging)
1893 int emOutputFlags = EM_LOG_CONSOLE;
1894 QByteArray localMsg = formattedMessage.toLocal8Bit();
1901 emOutputFlags |= EM_LOG_WARN;
1904 emOutputFlags |= EM_LOG_ERROR;
1907 emOutputFlags |= EM_LOG_ERROR;
1909 emscripten_log(emOutputFlags,
"%s\n", qPrintable(formattedMessage));
1917static void stderr_message_handler(QtMsgType type,
const QMessageLogContext &context,
1918 const QString &formattedMessage)
1925 if (formattedMessage.isNull())
1927 fprintf(stderr,
"%s\n", formattedMessage.toLocal8Bit().constData());
1932struct SystemMessageSink
1934 using Fn =
bool(QtMsgType,
const QMessageLogContext &,
const QString &);
1936 bool messageIsUnformatted =
false;
1941#if defined(Q_OS_WIN)
1943#elif QT_CONFIG(slog2)
1944 slog2_default_handler
1945#elif QT_CONFIG(journald)
1946 systemd_default_message_handler,
true
1947#elif QT_CONFIG(syslog)
1948 syslog_default_message_handler
1949#elif defined(Q_OS_ANDROID)
1950 android_default_message_handler
1951#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
1952 AppleUnifiedLogger::messageHandler,
true
1953#elif defined Q_OS_WASM
1954 wasm_default_message_handler
1960static void preformattedMessageHandler(QtMsgType type,
const QMessageLogContext &context,
1961 const QString &formattedMessage)
1964QT_WARNING_DISABLE_GCC(
"-Waddress")
1965 if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
1969 stderr_message_handler(type, context, formattedMessage);
1973
1974
1975static void qDefaultMessageHandler(QtMsgType type,
const QMessageLogContext &context,
1976 const QString &message)
1982 if (systemMessageSink.messageIsUnformatted) {
1983 if (systemMessageSink.sink(type, context, message))
1987 preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
1992static bool grabMessageHandler()
1994 if (msgHandlerGrabbed)
1997 msgHandlerGrabbed =
true;
2001static void ungrabMessageHandler()
2003 msgHandlerGrabbed =
false;
2006static void qt_message_print(QtMsgType msgType,
const QMessageLogContext &context,
const QString &message)
2008 Q_TRACE(qt_message_print, msgType, context.category, context.function, context.file, context.line, message);
2011 if (msgType != QtFatalMsg && isDefaultCategory(context.category)) {
2012 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2013 if (!defaultCategory->isEnabled(msgType))
2020 if (grabMessageHandler()) {
2021 const auto ungrab = qScopeGuard([]{ ungrabMessageHandler(); });
2022 auto msgHandler = messageHandler.loadAcquire();
2023 (msgHandler ? msgHandler : qDefaultMessageHandler)(msgType, context, message);
2025 stderr_message_handler(msgType, context, message);
2029template <
typename String>
static void
2030qt_maybe_message_fatal(QtMsgType msgType,
const QMessageLogContext &context, String &&message)
2032 if (!isFatal(msgType))
2034#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2035 wchar_t contextFileL[256];
2039 convert_to_wchar_t_elided(contextFileL,
sizeof contextFileL /
sizeof *contextFileL,
2042 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2043 _CrtSetReportMode(_CRT_ERROR, reportMode);
2045 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2046 reinterpret_cast<
const wchar_t *>(message.utf16()));
2047 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2055 if constexpr (std::is_class_v<String> && !std::is_const_v<String>)
2063
2064
2065void qt_message_output(QtMsgType msgType,
const QMessageLogContext &context,
const QString &message)
2067 QInternalMessageLogContext ctx(context);
2068 qt_message_print(msgType, ctx, message);
2069 qt_maybe_message_fatal(msgType, ctx, message);
2072void qErrnoWarning(
const char *msg, ...)
2076 QString error_string = qt_error_string(-1);
2080 QString buf = QString::vasprintf(msg, ap);
2083 buf +=
" ("_L1 + error_string + u')';
2084 QInternalMessageLogContext context{QMessageLogContext()};
2085 qt_message_output(QtWarningMsg, context, buf);
2088void qErrnoWarning(
int code,
const char *msg, ...)
2094 QString buf = QString::vasprintf(msg, ap);
2097 buf +=
" ("_L1 + qt_error_string(code) + u')';
2098 QInternalMessageLogContext context{QMessageLogContext()};
2099 qt_message_output(QtWarningMsg, context, buf);
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
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
2266QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
2268 const auto old = messageHandler.fetchAndStoreOrdered(h);
2272 return qDefaultMessageHandler;
2275void qSetMessagePattern(
const QString &pattern)
2277 const auto locker = qt_scoped_lock(QMessagePattern::mutex);
2279 if (!qMessagePattern()->fromEnvironment)
2280 qMessagePattern()->setPattern(pattern);
2283static void copyInternalContext(QInternalMessageLogContext *self,
2284 const QMessageLogContext &logContext)
noexcept
2286 if (logContext.version == self->version) {
2287 auto other =
static_cast<
const QInternalMessageLogContext *>(&logContext);
2288 self->backtrace = other->backtrace;
2293
2294
2295
2296
2297int QInternalMessageLogContext::initFrom(
const QMessageLogContext &logContext)
2299 version = CurrentVersion + 1;
2300 copyContextFrom(logContext);
2302#ifdef QLOGGING_HAVE_BACKTRACE
2303 if (backtrace.has_value())
2307 if (
auto pattern = qMessagePattern())
2308 return pattern->maxBacktraceDepth;
2315
2316
2317
2318
2319
2320
2321
2322QMessageLogContext &QMessageLogContext::copyContextFrom(
const QMessageLogContext &logContext)
noexcept
2324 this->category = logContext.category;
2325 this->file = logContext.file;
2326 this->line = logContext.line;
2327 this->function = logContext.function;
2328 if (Q_UNLIKELY(version == CurrentVersion + 1))
2329 copyInternalContext(
static_cast<QInternalMessageLogContext *>(
this), logContext);
2334
2335
2336
2337
2338
2341
2342
2343
2344
2345
2347
2348
2349
2350
2351
2352
2353
2356
2357
2358
2359
2360
2361
2362
2365
2366
2367
2368
2369
2372
2373
2374
2375
2376
2377
2378
2379
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
constexpr QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName) noexcept
static Q_CONSTINIT thread_local bool msgHandlerGrabbed
static const char ifCriticalTokenC[]
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 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 const char timeTokenC[]
static bool is_fatal_count_down(QAtomicInt &n)
static const char qthreadptrTokenC[]
static const char fileTokenC[]
static const char ifDebugTokenC[]
static const char ifFatalTokenC[]
static const char categoryTokenC[]
static const char lineTokenC[]
static const char typeTokenC[]
static const char ifCategoryTokenC[]
static int checked_var_value(const char *varname)
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[]
static const char functionTokenC[]
static const char ifWarningTokenC[]
static const char appnameTokenC[]
static bool isFatal(QtMsgType msgType)
static const char ifInfoTokenC[]
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.
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
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