Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qlogging.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
3// Copyright (C) 2022 Intel Corporation.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qglobal_p.h"
7#include "qlogging.h"
8#include "qlogging_p.h"
9#include "qlist.h"
10#include "qbytearray.h"
11#include "qscopeguard.h"
12#include "qstring.h"
13#include "qvarlengtharray.h"
14#include "qdebug.h"
15#include "qmutex.h"
16#include <QtCore/private/qlocking_p.h>
17#include "qloggingcategory.h"
18#ifndef QT_BOOTSTRAPPED
19#include "qelapsedtimer.h"
20#include "qdeadlinetimer.h"
21#include "qdatetime.h"
22#include "qcoreapplication.h"
23#include "qthread.h"
24#include "private/qloggingregistry_p.h"
25#include "private/qcoreapplication_p.h"
26#include <qtcore_tracepoints_p.h>
27#endif
28#ifdef Q_OS_WIN
29#include <qt_windows.h>
30#endif
31#ifdef Q_CC_MSVC
32#include <intrin.h>
33#endif
34#if QT_CONFIG(slog2)
35#include <sys/slog2.h>
36#endif
37#if __has_include(<paths.h>)
38#include <paths.h>
39#endif
40
41#ifdef Q_OS_ANDROID
42#include <android/log.h>
43#endif
44
45#ifdef Q_OS_DARWIN
46#include <QtCore/private/qcore_mac_p.h>
47#endif
48
49#if QT_CONFIG(journald)
50# define SD_JOURNAL_SUPPRESS_LOCATION
51# include <systemd/sd-journal.h>
52# include <syslog.h>
53#endif
54#if QT_CONFIG(syslog)
55# include <syslog.h>
56#endif
57#ifdef Q_OS_UNIX
58# include <sys/types.h>
59# include <sys/stat.h>
60# include <unistd.h>
61# include "private/qcore_unix_p.h"
62#endif
63
64#ifdef Q_OS_WASM
65#include <emscripten/emscripten.h>
66#endif
67
68#if QT_CONFIG(slog2)
69extern char *__progname;
70#endif
71
72#ifdef QLOGGING_HAVE_BACKTRACE
73# include <qregularexpression.h>
74#endif
75
76#ifdef QLOGGING_USE_EXECINFO_BACKTRACE
77# if QT_CONFIG(dladdr)
78# include <dlfcn.h>
79# endif
80# include BACKTRACE_HEADER
81# include <cxxabi.h>
82#endif // QLOGGING_USE_EXECINFO_BACKTRACE
83
84#ifndef QT_BOOTSTRAPPED
85#if defined(Q_OS_LINUX) && (defined(__GLIBC__) || __has_include(<sys/syscall.h>))
86# include <sys/syscall.h>
87
88# if defined(Q_OS_ANDROID) && !defined(SYS_gettid)
89# define SYS_gettid __NR_gettid
90# endif
91
92static long qt_gettid()
93{
94 // no error handling
95 // this syscall has existed since Linux 2.4.11 and cannot fail
96 return syscall(SYS_gettid);
97}
98#elif defined(Q_OS_DARWIN)
99# include <pthread.h>
100static int qt_gettid()
101{
102 // no error handling: this call cannot fail
103 __uint64_t tid;
104 pthread_threadid_np(NULL, &tid);
105 return tid;
106}
107#elif defined(Q_OS_FREEBSD_KERNEL) && defined(__FreeBSD_version) && __FreeBSD_version >= 900031
108# include <pthread_np.h>
109static int qt_gettid()
110{
111 return pthread_getthreadid_np();
112}
113#else
114static QT_PREPEND_NAMESPACE(qint64) qt_gettid()
115{
118}
119#endif
120#endif // !QT_BOOTSTRAPPED
121
122#include <cstdlib>
123#include <algorithm>
124#include <memory>
125#include <vector>
126
127#include <stdio.h>
128
130
131using namespace Qt::StringLiterals;
132
133#ifndef QT_BOOTSTRAPPED
134Q_TRACE_POINT(qtcore, qt_message_print, int type, const char *category, const char *function, const char *file, int line, const QString &message);
135#endif
136
167template <typename String>
168#if !defined(Q_CC_MSVC_ONLY)
170#endif
174 const QString &formattedMessage);
176
177static int checked_var_value(const char *varname)
178{
179 // qEnvironmentVariableIntValue returns 0 on both parsing failure and on
180 // empty, but we need to distinguish between the two for backwards
181 // compatibility reasons.
182 QByteArray str = qgetenv(varname);
183 if (str.isEmpty())
184 return 0;
185
186 bool ok;
187 int value = str.toInt(&ok, 0);
188 return ok ? value : 1;
189}
190
192{
193 // it's fatal if the current value is exactly 1,
194 // otherwise decrement if it's non-zero
195
196 int v = n.loadRelaxed();
197 while (v != 0 && !n.testAndSetRelaxed(v, v - 1, v))
198 qYieldCpu();
199 return v == 1; // we exited the loop, so either v == 0 or CAS succeeded to set n from v to v-1
200}
201
202static bool isFatal(QtMsgType msgType)
203{
204 if (msgType == QtFatalMsg)
205 return true;
206
207 if (msgType == QtCriticalMsg) {
208 static QAtomicInt fatalCriticals = checked_var_value("QT_FATAL_CRITICALS");
209 return is_fatal_count_down(fatalCriticals);
210 }
211
212 if (msgType == QtWarningMsg || msgType == QtCriticalMsg) {
213 static QAtomicInt fatalWarnings = checked_var_value("QT_FATAL_WARNINGS");
214 return is_fatal_count_down(fatalWarnings);
215 }
216
217 return false;
218}
219
226static bool systemHasStderr()
227{
228 return true;
229}
230
231#ifndef Q_OS_WASM
232
254{
255 static const bool stderrHasConsoleAttached = []() -> bool {
256 if (!systemHasStderr())
257 return false;
258
259 if (qEnvironmentVariableIntValue("QT_LOGGING_TO_CONSOLE")) {
260 fprintf(stderr, "warning: Environment variable QT_LOGGING_TO_CONSOLE is deprecated, use\n"
261 "QT_ASSUME_STDERR_HAS_CONSOLE and/or QT_FORCE_STDERR_LOGGING instead.\n");
262 return true;
263 }
264
265 if (qEnvironmentVariableIntValue("QT_ASSUME_STDERR_HAS_CONSOLE"))
266 return true;
267
268#if defined(Q_OS_WIN)
269 return GetConsoleWindow();
270#elif defined(Q_OS_UNIX)
271# ifndef _PATH_TTY
272# define _PATH_TTY "/dev/tty"
273# endif
274
275 // If we can open /dev/tty, we have a controlling TTY
276 int ttyDevice = -1;
277 if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
278 qt_safe_close(ttyDevice);
279 return true;
280 } else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
281 // Fall back to isatty for some non-critical errors
282 return isatty(STDERR_FILENO);
283 } else {
284 return false;
285 }
286#else
287 return false; // No way to detect if stderr has a console attached
288#endif
289 }();
290
292}
293
294
295namespace QtPrivate {
296
307{
308 static bool forceStderrLogging = qEnvironmentVariableIntValue("QT_FORCE_STDERR_LOGGING");
309 return forceStderrLogging || stderrHasConsoleAttached();
310}
311
312
313} // QtPrivate
314
315using namespace QtPrivate;
316
317#endif // ifndef Q_OS_WASM
318
353#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
354static inline void convert_to_wchar_t_elided(wchar_t *d, size_t space, const char *s) noexcept
355{
356 size_t len = qstrlen(s);
357 if (len + 1 > space) {
358 const size_t skip = len - space + 4; // 4 for "..." + '\0'
359 s += skip;
360 len -= skip;
361 for (int i = 0; i < 3; ++i)
362 *d++ = L'.';
363 }
364 while (len--)
365 *d++ = *s++;
366 *d++ = 0;
367}
368#endif
369
374static void qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
375{
376 QString buf = QString::vasprintf(msg, ap);
377 qt_message_print(msgType, context, buf);
378
379 if (isFatal(msgType))
380 qt_message_fatal(msgType, context, buf);
381}
382
389void QMessageLogger::debug(const char *msg, ...) const
390{
391 QInternalMessageLogContext ctxt(context);
392 va_list ap;
393 va_start(ap, msg); // use variable arg list
394 qt_message(QtDebugMsg, ctxt, msg, ap);
395 va_end(ap);
396}
397
405void QMessageLogger::info(const char *msg, ...) const
406{
407 QInternalMessageLogContext ctxt(context);
408 va_list ap;
409 va_start(ap, msg); // use variable arg list
410 qt_message(QtInfoMsg, ctxt, msg, ap);
411 va_end(ap);
412}
413
435void QMessageLogger::debug(const QLoggingCategory &cat, const char *msg, ...) const
436{
437 if (!cat.isDebugEnabled())
438 return;
439
440 QInternalMessageLogContext ctxt(context, cat());
441
442 va_list ap;
443 va_start(ap, msg); // use variable arg list
444 qt_message(QtDebugMsg, ctxt, msg, ap);
445 va_end(ap);
446}
447
456 const char *msg, ...) const
457{
458 const QLoggingCategory &cat = (*catFunc)();
459 if (!cat.isDebugEnabled())
460 return;
461
462 QInternalMessageLogContext ctxt(context, cat());
463
464 va_list ap;
465 va_start(ap, msg); // use variable arg list
466 qt_message(QtDebugMsg, ctxt, msg, ap);
467 va_end(ap);
468}
469
470#ifndef QT_NO_DEBUG_STREAM
471
478{
479 QDebug dbg = QDebug(QtDebugMsg);
480 QMessageLogContext &ctxt = dbg.stream->context;
481 ctxt.copyContextFrom(context);
482 return dbg;
483}
484
492{
493 QDebug dbg = QDebug(QtDebugMsg);
494 if (!cat.isDebugEnabled())
495 dbg.stream->message_output = false;
496
497 QMessageLogContext &ctxt = dbg.stream->context;
498 ctxt.copyContextFrom(context);
499 ctxt.category = cat.categoryName();
500
501 return dbg;
502}
503
511{
512 return debug((*catFunc)());
513}
514
522QNoDebug QMessageLogger::noDebug() const noexcept
523{
524 return QNoDebug();
525}
526
527#endif
528
536void QMessageLogger::info(const QLoggingCategory &cat, const char *msg, ...) const
537{
538 if (!cat.isInfoEnabled())
539 return;
540
541 QInternalMessageLogContext ctxt(context, cat());
542
543 va_list ap;
544 va_start(ap, msg); // use variable arg list
545 qt_message(QtInfoMsg, ctxt, msg, ap);
546 va_end(ap);
547}
548
557 const char *msg, ...) const
558{
559 const QLoggingCategory &cat = (*catFunc)();
560 if (!cat.isInfoEnabled())
561 return;
562
563 QInternalMessageLogContext ctxt(context, cat());
564
565 va_list ap;
566 va_start(ap, msg); // use variable arg list
567 qt_message(QtInfoMsg, ctxt, msg, ap);
568 va_end(ap);
569}
570
571#ifndef QT_NO_DEBUG_STREAM
572
580{
581 QDebug dbg = QDebug(QtInfoMsg);
582 QMessageLogContext &ctxt = dbg.stream->context;
583 ctxt.copyContextFrom(context);
584 return dbg;
585}
586
594{
595 QDebug dbg = QDebug(QtInfoMsg);
596 if (!cat.isInfoEnabled())
597 dbg.stream->message_output = false;
598
599 QMessageLogContext &ctxt = dbg.stream->context;
600 ctxt.copyContextFrom(context);
601 ctxt.category = cat.categoryName();
602
603 return dbg;
604}
605
613{
614 return info((*catFunc)());
615}
616
617#endif
618
625void QMessageLogger::warning(const char *msg, ...) const
626{
627 QInternalMessageLogContext ctxt(context);
628 va_list ap;
629 va_start(ap, msg); // use variable arg list
630 qt_message(QtWarningMsg, ctxt, msg, ap);
631 va_end(ap);
632}
633
641void QMessageLogger::warning(const QLoggingCategory &cat, const char *msg, ...) const
642{
643 if (!cat.isWarningEnabled())
644 return;
645
646 QInternalMessageLogContext ctxt(context, cat());
647
648 va_list ap;
649 va_start(ap, msg); // use variable arg list
650 qt_message(QtWarningMsg, ctxt, msg, ap);
651 va_end(ap);
652}
653
662 const char *msg, ...) const
663{
664 const QLoggingCategory &cat = (*catFunc)();
665 if (!cat.isWarningEnabled())
666 return;
667
668 QInternalMessageLogContext ctxt(context, cat());
669
670 va_list ap;
671 va_start(ap, msg); // use variable arg list
672 qt_message(QtWarningMsg, ctxt, msg, ap);
673 va_end(ap);
674}
675
676#ifndef QT_NO_DEBUG_STREAM
683{
685 QMessageLogContext &ctxt = dbg.stream->context;
686 ctxt.copyContextFrom(context);
687 return dbg;
688}
689
696{
698 if (!cat.isWarningEnabled())
699 dbg.stream->message_output = false;
700
701 QMessageLogContext &ctxt = dbg.stream->context;
702 ctxt.copyContextFrom(context);
703 ctxt.category = cat.categoryName();
704
705 return dbg;
706}
707
715{
716 return warning((*catFunc)());
717}
718
719#endif
720
727void QMessageLogger::critical(const char *msg, ...) const
728{
729 QInternalMessageLogContext ctxt(context);
730 va_list ap;
731 va_start(ap, msg); // use variable arg list
732 qt_message(QtCriticalMsg, ctxt, msg, ap);
733 va_end(ap);
734}
735
743void QMessageLogger::critical(const QLoggingCategory &cat, const char *msg, ...) const
744{
745 if (!cat.isCriticalEnabled())
746 return;
747
748 QInternalMessageLogContext ctxt(context, cat());
749
750 va_list ap;
751 va_start(ap, msg); // use variable arg list
752 qt_message(QtCriticalMsg, ctxt, msg, ap);
753 va_end(ap);
754}
755
764 const char *msg, ...) const
765{
766 const QLoggingCategory &cat = (*catFunc)();
767 if (!cat.isCriticalEnabled())
768 return;
769
770 QInternalMessageLogContext ctxt(context, cat());
771
772 va_list ap;
773 va_start(ap, msg); // use variable arg list
774 qt_message(QtCriticalMsg, ctxt, msg, ap);
775 va_end(ap);
776}
777
778#ifndef QT_NO_DEBUG_STREAM
785{
787 QMessageLogContext &ctxt = dbg.stream->context;
788 ctxt.copyContextFrom(context);
789 return dbg;
790}
791
799{
801 if (!cat.isCriticalEnabled())
802 dbg.stream->message_output = false;
803
804 QMessageLogContext &ctxt = dbg.stream->context;
805 ctxt.copyContextFrom(context);
806 ctxt.category = cat.categoryName();
807
808 return dbg;
809}
810
818{
819 return critical((*catFunc)());
820}
821
822#endif
823
831void QMessageLogger::fatal(const QLoggingCategory &cat, const char *msg, ...) const noexcept
832{
833 QInternalMessageLogContext ctxt(context, cat());
834
835 va_list ap;
836 va_start(ap, msg); // use variable arg list
838 va_end(ap);
839
840#ifndef Q_CC_MSVC_ONLY
841 Q_UNREACHABLE();
842#endif
843}
844
853 const char *msg, ...) const noexcept
854{
855 const QLoggingCategory &cat = (*catFunc)();
856
857 QInternalMessageLogContext ctxt(context, cat());
858
859 va_list ap;
860 va_start(ap, msg); // use variable arg list
862 va_end(ap);
863
864#ifndef Q_CC_MSVC_ONLY
865 Q_UNREACHABLE();
866#endif
867}
868
875void QMessageLogger::fatal(const char *msg, ...) const noexcept
876{
877 QInternalMessageLogContext ctxt(context);
878 va_list ap;
879 va_start(ap, msg); // use variable arg list
881 va_end(ap);
882
883#ifndef Q_CC_MSVC_ONLY
884 Q_UNREACHABLE();
885#endif
886}
887
888#ifndef QT_NO_DEBUG_STREAM
897{
898 QDebug dbg = QDebug(QtFatalMsg);
899 QMessageLogContext &ctxt = dbg.stream->context;
900 ctxt.copyContextFrom(context);
901 return dbg;
902}
903
911{
912 QDebug dbg = QDebug(QtFatalMsg);
913
914 QMessageLogContext &ctxt = dbg.stream->context;
915 ctxt.copyContextFrom(context);
916 ctxt.category = cat.categoryName();
917
918 return dbg;
919}
920
928{
929 return fatal((*catFunc)());
930}
931#endif // QT_NO_DEBUG_STREAM
932
933#if !defined(QT_BOOTSTRAPPED)
934static bool isDefaultCategory(const char *category)
935{
936 return !category || strcmp(category, "default") == 0;
937}
938
943{
944 // Strip the function info down to the base function name
945 // note that this throws away the template definitions,
946 // the parameter types (overloads) and any const/volatile qualifiers.
947
948 if (info.isEmpty())
949 return info;
950
952
953 // Skip trailing [with XXX] for templates (gcc), but make
954 // sure to not affect Objective-C message names.
955 pos = info.size() - 1;
956 if (info.endsWith(']') && !(info.startsWith('+') || info.startsWith('-'))) {
957 while (--pos) {
958 if (info.at(pos) == '[') {
959 info.truncate(pos);
960 break;
961 }
962 }
963 if (info.endsWith(' ')) {
964 info.chop(1);
965 }
966 }
967
968 // operator names with '(', ')', '<', '>' in it
969 static const char operator_call[] = "operator()";
970 static const char operator_lessThan[] = "operator<";
971 static const char operator_greaterThan[] = "operator>";
972 static const char operator_lessThanEqual[] = "operator<=";
973 static const char operator_greaterThanEqual[] = "operator>=";
974
975 // canonize operator names
976 info.replace("operator ", "operator");
977
978 pos = -1;
979 // remove argument list
980 forever {
981 int parencount = 0;
982 pos = info.lastIndexOf(')', pos);
983 if (pos == -1) {
984 // Don't know how to parse this function name
985 return info;
986 }
987 if (info.indexOf('>', pos) != -1
988 || info.indexOf(':', pos) != -1) {
989 // that wasn't the function argument list.
990 --pos;
991 continue;
992 }
993
994 // find the beginning of the argument list
995 --pos;
996 ++parencount;
997 while (pos && parencount) {
998 if (info.at(pos) == ')')
999 ++parencount;
1000 else if (info.at(pos) == '(')
1001 --parencount;
1002 --pos;
1003 }
1004 if (parencount != 0)
1005 return info;
1006
1007 info.truncate(++pos);
1008
1009 if (info.at(pos - 1) == ')') {
1010 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
1011 break;
1012
1013 // this function returns a pointer to a function
1014 // and we matched the arguments of the return type's parameter list
1015 // try again
1016 info.remove(0, info.indexOf('('));
1017 info.chop(1);
1018 continue;
1019 } else {
1020 break;
1021 }
1022 }
1023
1024 // find the beginning of the function name
1025 int parencount = 0;
1026 int templatecount = 0;
1027 --pos;
1028
1029 // make sure special characters in operator names are kept
1030 if (pos > -1) {
1031 switch (info.at(pos)) {
1032 case ')':
1033 if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
1034 pos -= 2;
1035 break;
1036 case '<':
1037 if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
1038 --pos;
1039 break;
1040 case '>':
1041 if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
1042 --pos;
1043 break;
1044 case '=': {
1045 auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
1046 if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
1047 pos -= 2;
1048 else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
1049 pos -= 2;
1050 break;
1051 }
1052 default:
1053 break;
1054 }
1055 }
1056
1057 while (pos > -1) {
1058 if (parencount < 0 || templatecount < 0)
1059 return info;
1060
1061 char c = info.at(pos);
1062 if (c == ')')
1063 ++parencount;
1064 else if (c == '(')
1065 --parencount;
1066 else if (c == '>')
1067 ++templatecount;
1068 else if (c == '<')
1069 --templatecount;
1070 else if (c == ' ' && templatecount == 0 && parencount == 0)
1071 break;
1072
1073 --pos;
1074 }
1075 info = info.mid(pos + 1);
1076
1077 // remove trailing '*', '&' that are part of the return argument
1078 while ((info.at(0) == '*')
1079 || (info.at(0) == '&'))
1080 info = info.mid(1);
1081
1082 // we have the full function name now.
1083 // clean up the templates
1084 while ((pos = info.lastIndexOf('>')) != -1) {
1085 if (!info.contains('<'))
1086 break;
1087
1088 // find the matching close
1089 qsizetype end = pos;
1090 templatecount = 1;
1091 --pos;
1092 while (pos && templatecount) {
1093 char c = info.at(pos);
1094 if (c == '>')
1095 ++templatecount;
1096 else if (c == '<')
1097 --templatecount;
1098 --pos;
1099 }
1100 ++pos;
1101 info.remove(pos, end - pos + 1);
1102 }
1103
1104 return info;
1105}
1106
1107// tokens as recognized in QT_MESSAGE_PATTERN
1108static const char categoryTokenC[] = "%{category}";
1109static const char typeTokenC[] = "%{type}";
1110static const char messageTokenC[] = "%{message}";
1111static const char fileTokenC[] = "%{file}";
1112static const char lineTokenC[] = "%{line}";
1113static const char functionTokenC[] = "%{function}";
1114static const char pidTokenC[] = "%{pid}";
1115static const char appnameTokenC[] = "%{appname}";
1116static const char threadidTokenC[] = "%{threadid}";
1117static const char qthreadptrTokenC[] = "%{qthreadptr}";
1118static const char timeTokenC[] = "%{time"; //not a typo: this command has arguments
1119static const char backtraceTokenC[] = "%{backtrace"; //ditto
1120static const char ifCategoryTokenC[] = "%{if-category}";
1121static const char ifDebugTokenC[] = "%{if-debug}";
1122static const char ifInfoTokenC[] = "%{if-info}";
1123static const char ifWarningTokenC[] = "%{if-warning}";
1124static const char ifCriticalTokenC[] = "%{if-critical}";
1125static const char ifFatalTokenC[] = "%{if-fatal}";
1126static const char endifTokenC[] = "%{endif}";
1127static const char emptyTokenC[] = "";
1128
1129static const char defaultPattern[] = "%{if-category}%{category}: %{endif}%{message}";
1130
1132{
1135
1136 void setPattern(const QString &pattern);
1137
1138 // 0 terminated arrays of literal tokens / literal or placeholder tokens
1139 std::unique_ptr<std::unique_ptr<const char[]>[]> literals;
1140 std::unique_ptr<const char *[]> tokens;
1141 QList<QString> timeArgs; // timeFormats in sequence of %{time
1142#ifndef QT_BOOTSTRAPPED
1144#endif
1145#ifdef QLOGGING_HAVE_BACKTRACE
1146 struct BacktraceParams
1147 {
1148 QString backtraceSeparator;
1149 int backtraceDepth;
1150 };
1151 QList<BacktraceParams> backtraceArgs; // backtrace arguments in sequence of %{backtrace
1152 int maxBacktraceDepth = 0;
1153#endif
1154
1157};
1158#ifdef QLOGGING_HAVE_BACKTRACE
1159Q_DECLARE_TYPEINFO(QMessagePattern::BacktraceParams, Q_RELOCATABLE_TYPE);
1160#endif
1161
1163
1165{
1166#ifndef QT_BOOTSTRAPPED
1167 timer.start();
1168#endif
1169 const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN"));
1170 if (envPattern.isEmpty()) {
1172 fromEnvironment = false;
1173 } else {
1174 setPattern(envPattern);
1175 fromEnvironment = true;
1176 }
1177}
1178
1180
1182{
1183 timeArgs.clear();
1184#ifdef QLOGGING_HAVE_BACKTRACE
1185 backtraceArgs.clear();
1186 maxBacktraceDepth = 0;
1187#endif
1188
1189 // scanner
1190 QList<QString> lexemes;
1191 QString lexeme;
1192 bool inPlaceholder = false;
1193 for (int i = 0; i < pattern.size(); ++i) {
1194 const QChar c = pattern.at(i);
1195 if (c == u'%' && !inPlaceholder) {
1196 if ((i + 1 < pattern.size())
1197 && pattern.at(i + 1) == u'{') {
1198 // beginning of placeholder
1199 if (!lexeme.isEmpty()) {
1200 lexemes.append(lexeme);
1201 lexeme.clear();
1202 }
1203 inPlaceholder = true;
1204 }
1205 }
1206
1207 lexeme.append(c);
1208
1209 if (c == u'}' && inPlaceholder) {
1210 // end of placeholder
1211 lexemes.append(lexeme);
1212 lexeme.clear();
1213 inPlaceholder = false;
1214 }
1215 }
1216 if (!lexeme.isEmpty())
1217 lexemes.append(lexeme);
1218
1219 // tokenizer
1220 std::vector<std::unique_ptr<const char[]>> literalsVar;
1221 tokens.reset(new const char *[lexemes.size() + 1]);
1222 tokens[lexemes.size()] = nullptr;
1223
1224 bool nestedIfError = false;
1225 bool inIf = false;
1226 QString error;
1227
1228 for (int i = 0; i < lexemes.size(); ++i) {
1229 const QString lexeme = lexemes.at(i);
1230 if (lexeme.startsWith("%{"_L1) && lexeme.endsWith(u'}')) {
1231 // placeholder
1232 if (lexeme == QLatin1StringView(typeTokenC)) {
1233 tokens[i] = typeTokenC;
1234 } else if (lexeme == QLatin1StringView(categoryTokenC))
1236 else if (lexeme == QLatin1StringView(messageTokenC))
1238 else if (lexeme == QLatin1StringView(fileTokenC))
1239 tokens[i] = fileTokenC;
1240 else if (lexeme == QLatin1StringView(lineTokenC))
1241 tokens[i] = lineTokenC;
1242 else if (lexeme == QLatin1StringView(functionTokenC))
1244 else if (lexeme == QLatin1StringView(pidTokenC))
1245 tokens[i] = pidTokenC;
1246 else if (lexeme == QLatin1StringView(appnameTokenC))
1248 else if (lexeme == QLatin1StringView(threadidTokenC))
1250 else if (lexeme == QLatin1StringView(qthreadptrTokenC))
1252 else if (lexeme.startsWith(QLatin1StringView(timeTokenC))) {
1253 tokens[i] = timeTokenC;
1254 qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(' '));
1255 if (spaceIdx > 0)
1256 timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2));
1257 else
1259 } else if (lexeme.startsWith(QLatin1StringView(backtraceTokenC))) {
1260#ifdef QLOGGING_HAVE_BACKTRACE
1262 QString backtraceSeparator = QStringLiteral("|");
1263 int backtraceDepth = 5;
1264 static const QRegularExpression depthRx(QStringLiteral(" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1265 static const QRegularExpression separatorRx(QStringLiteral(" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1266 QRegularExpressionMatch m = depthRx.match(lexeme);
1267 if (m.hasMatch()) {
1268 int depth = m.capturedView(1).toInt();
1269 if (depth <= 0)
1270 error += "QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n"_L1;
1271 else
1272 backtraceDepth = depth;
1273 }
1274 m = separatorRx.match(lexeme);
1275 if (m.hasMatch())
1276 backtraceSeparator = m.captured(1);
1277 BacktraceParams backtraceParams;
1278 backtraceParams.backtraceDepth = backtraceDepth;
1279 backtraceParams.backtraceSeparator = backtraceSeparator;
1280 backtraceArgs.append(backtraceParams);
1281 maxBacktraceDepth = qMax(maxBacktraceDepth, backtraceDepth);
1282#else
1283 error += "QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
1284 tokens[i] = "";
1285#endif
1286 }
1287
1288#define IF_TOKEN(LEVEL) \
1289 else if (lexeme == QLatin1StringView(LEVEL)) { \
1290 if (inIf) \
1291 nestedIfError = true; \
1292 tokens[i] = LEVEL; \
1293 inIf = true; \
1294 }
1301#undef IF_TOKEN
1302 else if (lexeme == QLatin1StringView(endifTokenC)) {
1303 tokens[i] = endifTokenC;
1304 if (!inIf && !nestedIfError)
1305 error += "QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"_L1;
1306 inIf = false;
1307 } else {
1308 tokens[i] = emptyTokenC;
1309 error += "QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme + '\n'_L1;
1310 }
1311 } else {
1312 using UP = std::unique_ptr<char[]>;
1313 tokens[i] = literalsVar.emplace_back(UP(qstrdup(lexeme.toLatin1().constData()))).get();
1314 }
1315 }
1316 if (nestedIfError)
1317 error += "QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"_L1;
1318 else if (inIf)
1319 error += "QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
1320
1321 if (!error.isEmpty()) {
1322 // remove the last '\n' because the sinks deal with that on their own
1323 error.chop(1);
1324
1326 "QMessagePattern::setPattern", nullptr);
1328 }
1329
1330 literals.reset(new std::unique_ptr<const char[]>[literalsVar.size() + 1]);
1331 std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
1332}
1333
1334#if defined(QLOGGING_HAVE_BACKTRACE)
1335// make sure the function has "Message" in the name so the function is removed
1336/*
1337 A typical backtrace in debug mode looks like:
1338 #0 QInternalMessageLogContext::populateBacktrace (this=0x7fffffffd660, frameCount=5) at qlogging.cpp:1342
1339 #1 QInternalMessageLogContext::QInternalMessageLogContext (logContext=..., this=<optimized out>) at qlogging_p.h:42
1340 #2 QDebug::~QDebug (this=0x7fffffffdac8, __in_chrg=<optimized out>) at qdebug.cpp:160
1341
1342 In release mode, the QInternalMessageLogContext constructor will be usually
1343 inlined. Empirical testing with GCC 13 and Clang 17 suggest they do obey the
1344 Q_ALWAYS_INLINE in that constructor even in debug mode and do inline it.
1345 Unfortunately, we can't know for sure if it has been.
1346*/
1347static constexpr int TypicalBacktraceFrameCount = 3;
1348static constexpr const char *QtCoreLibraryName = "Qt" QT_STRINGIFY(QT_VERSION_MAJOR) "Core";
1349
1350#if defined(QLOGGING_USE_STD_BACKTRACE)
1352{
1353 assert(frameCount >= 0);
1354 backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
1355}
1356
1357static QStringList
1358backtraceFramesForLogMessage(int frameCount,
1360{
1362 result.reserve(buffer.size());
1363
1364 const auto shouldSkipFrame = [](QByteArrayView description)
1365 {
1366#if defined(_MSVC_STL_VERSION)
1367 const auto libraryNameEnd = description.indexOf('!');
1368 if (libraryNameEnd != -1) {
1369 const auto libraryName = description.first(libraryNameEnd);
1370 if (!libraryName.contains(QtCoreLibraryName))
1371 return false;
1372 }
1373#endif
1374 if (description.contains("populateBacktrace"))
1375 return true;
1376 if (description.contains("QInternalMessageLogContext"))
1377 return true;
1378 if (description.contains("~QDebug"))
1379 return true;
1380 return false;
1381 };
1382
1383 for (const auto &entry : buffer) {
1384 const std::string description = entry.description();
1385 if (result.isEmpty() && shouldSkipFrame(description))
1386 continue;
1387 result.append(QString::fromStdString(description));
1388 }
1389
1390 return result;
1391}
1392
1393#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
1394
1396{
1397 assert(frameCount >= 0);
1398 BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
1399 int n = ::backtrace(result.data(), result.size());
1400 if (n <= 0)
1401 result.clear();
1402 else
1403 result.resize(n);
1404}
1405
1406static QStringList
1407backtraceFramesForLogMessage(int frameCount,
1409{
1410 struct DecodedFrame {
1411 QString library;
1413 };
1414
1416 if (frameCount == 0)
1417 return result;
1418
1419 auto shouldSkipFrame = [&result](const auto &library, const auto &function) {
1420 if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
1421 return false;
1422 if (function.isEmpty())
1423 return true;
1424 if (function.contains("6QDebug"_L1))
1425 return true;
1426 if (function.contains("14QMessageLogger"_L1))
1427 return true;
1428 if (function.contains("17qt_message_output"_L1))
1429 return true;
1430 if (function.contains("26QInternalMessageLogContext"_L1))
1431 return true;
1432 return false;
1433 };
1434
1435 auto demangled = [](auto &function) -> QString {
1436 if (!function.startsWith("_Z"_L1))
1437 return function;
1438
1439 // we optimize for the case where __cxa_demangle succeeds
1440 auto fn = [&]() {
1441 if constexpr (sizeof(function.at(0)) == 1)
1442 return function.data(); // -> const char *
1443 else
1444 return std::move(function).toUtf8(); // -> QByteArray
1445 }();
1446 QScopedPointer<char, QScopedPointerPodDeleter> demangled;
1447 demangled.reset(abi::__cxa_demangle(fn, nullptr, nullptr, nullptr));
1448
1449 if (demangled)
1450 return QString::fromUtf8(qCleanupFuncinfo(demangled.data()));
1451 else
1452 return QString::fromUtf8(fn); // restore
1453 };
1454
1455# if QT_CONFIG(dladdr)
1456 // use dladdr() instead of backtrace_symbols()
1457 QString cachedLibrary;
1458 const char *cachedFname = nullptr;
1459 auto decodeFrame = [&](void *addr) -> DecodedFrame {
1460 Dl_info info;
1461 if (!dladdr(addr, &info))
1462 return {};
1463
1464 // These are actually UTF-8, so we'll correct below
1465 QLatin1StringView fn(info.dli_sname);
1467 if (const char *lastSlash = strrchr(info.dli_fname, '/'))
1468 lib = QLatin1StringView(lastSlash + 1);
1469 else
1470 lib = QLatin1StringView(info.dli_fname);
1471
1472 if (shouldSkipFrame(lib, fn))
1473 return {};
1474
1475 QString function = demangled(fn);
1476 if (lib.data() != cachedFname) {
1477 cachedFname = lib.data();
1478 cachedLibrary = QString::fromUtf8(cachedFname, lib.size());
1479 }
1480 return { cachedLibrary, function };
1481 };
1482# else
1483 // The results of backtrace_symbols looks like this:
1484 // /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
1485 // The offset and function name are optional.
1486 // This regexp tries to extract the library name (without the path) and the function name.
1487 // This code is protected by QMessagePattern::mutex so it is thread safe on all compilers
1488 static const QRegularExpression rx(QStringLiteral("^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1489
1490 auto decodeFrame = [&](void *&addr) -> DecodedFrame {
1491 QScopedPointer<char*, QScopedPointerPodDeleter> strings(backtrace_symbols(&addr, 1));
1494 if (!m.hasMatch())
1495 return {};
1496
1497 QString library = m.captured(1);
1498 QString function = m.captured(2);
1499
1500 // skip the trace from QtCore that are because of the qDebug itself
1501 if (shouldSkipFrame(library, function))
1502 return {};
1503
1504 function = demangled(function);
1505 return { library, function };
1506 };
1507# endif
1508
1509 for (void *const &addr : buffer) {
1510 DecodedFrame frame = decodeFrame(addr);
1511 if (!frame.library.isEmpty()) {
1512 if (frame.function.isEmpty())
1513 result.append(u'?' + frame.library + u'?');
1514 else
1515 result.append(frame.function);
1516 } else {
1517 // innermost, unknown frames are usually the logging framework itself
1518 if (!result.isEmpty())
1519 result.append(QStringLiteral("???"));
1520 }
1521
1522 if (result.size() == frameCount)
1523 break;
1524 }
1525 return result;
1526}
1527#else
1528#error "Internal error: backtrace enabled, but no way to gather backtraces available"
1529#endif // QLOGGING_USE_..._BACKTRACE
1530
1531static QString formatBacktraceForLogMessage(const QMessagePattern::BacktraceParams backtraceParams,
1532 const QMessageLogContext &ctx)
1533{
1534 // do we have a backtrace stored?
1536 return QString();
1537
1538 auto &fullctx = static_cast<const QInternalMessageLogContext &>(ctx);
1539 if (!fullctx.backtrace.has_value())
1540 return QString();
1541
1542 QString backtraceSeparator = backtraceParams.backtraceSeparator;
1543 int backtraceDepth = backtraceParams.backtraceDepth;
1544
1545 QStringList frames = backtraceFramesForLogMessage(backtraceDepth, *fullctx.backtrace);
1546 if (frames.isEmpty())
1547 return QString();
1548
1549 // if the first frame is unknown, replace it with the context function
1550 if (ctx.function && frames.at(0).startsWith(u'?'))
1551 frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
1552
1553 return frames.join(backtraceSeparator);
1554}
1555#endif // QLOGGING_HAVE_BACKTRACE && !QT_BOOTSTRAPPED
1556
1557Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
1558
1559
1574{
1575 return formatLogMessage(type, context, str);
1576}
1577
1578// Separate function so the default message handler can bypass the public,
1579// exported function above. Static functions can't get added to the dynamic
1580// symbol tables, so they never show up in backtrace_symbols() or equivalent.
1582{
1584
1585 const auto locker = qt_scoped_lock(QMessagePattern::mutex);
1586
1587 QMessagePattern *pattern = qMessagePattern();
1588 if (!pattern) {
1589 // after destruction of static QMessagePattern instance
1590 message.append(str);
1591 return message;
1592 }
1593
1594 bool skip = false;
1595
1596 int timeArgsIdx = 0;
1597#ifdef QLOGGING_HAVE_BACKTRACE
1598 int backtraceArgsIdx = 0;
1599#endif
1600
1601 // we do not convert file, function, line literals to local encoding due to overhead
1602 for (int i = 0; pattern->tokens[i]; ++i) {
1603 const char *token = pattern->tokens[i];
1604 if (token == endifTokenC) {
1605 skip = false;
1606 } else if (skip) {
1607 // we skip adding messages, but we have to iterate over
1608 // timeArgsIdx and backtraceArgsIdx anyway
1609 if (token == timeTokenC)
1610 timeArgsIdx++;
1611#ifdef QLOGGING_HAVE_BACKTRACE
1612 else if (token == backtraceTokenC)
1613 backtraceArgsIdx++;
1614#endif
1615 } else if (token == messageTokenC) {
1616 message.append(str);
1617 } else if (token == categoryTokenC) {
1618#ifndef Q_OS_ANDROID
1619 // Don't add the category to the message on Android
1620 message.append(QLatin1StringView(context.category));
1621#endif
1622 } else if (token == typeTokenC) {
1623 switch (type) {
1624 case QtDebugMsg: message.append("debug"_L1); break;
1625 case QtInfoMsg: message.append("info"_L1); break;
1626 case QtWarningMsg: message.append("warning"_L1); break;
1627 case QtCriticalMsg:message.append("critical"_L1); break;
1628 case QtFatalMsg: message.append("fatal"_L1); break;
1629 }
1630 } else if (token == fileTokenC) {
1631 if (context.file)
1632 message.append(QLatin1StringView(context.file));
1633 else
1634 message.append("unknown"_L1);
1635 } else if (token == lineTokenC) {
1636 message.append(QString::number(context.line));
1637 } else if (token == functionTokenC) {
1638 if (context.function)
1640 else
1641 message.append("unknown"_L1);
1642 } else if (token == pidTokenC) {
1644 } else if (token == appnameTokenC) {
1646 } else if (token == threadidTokenC) {
1647 // print the TID as decimal
1648 message.append(QString::number(qt_gettid()));
1649 } else if (token == qthreadptrTokenC) {
1650 message.append("0x"_L1);
1651 message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1652#ifdef QLOGGING_HAVE_BACKTRACE
1653 } else if (token == backtraceTokenC) {
1654 QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1655 backtraceArgsIdx++;
1656 message.append(formatBacktraceForLogMessage(backtraceParams, context));
1657#endif
1658 } else if (token == timeTokenC) {
1659 QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1660 timeArgsIdx++;
1661 if (timeFormat == "process"_L1) {
1662 quint64 ms = pattern->timer.elapsed();
1663 message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
1664 } else if (timeFormat == "boot"_L1) {
1665 // just print the milliseconds since the elapsed timer reference
1666 // like the Linux kernel does
1667 qint64 ms = QDeadlineTimer::current().deadline();
1668 message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
1669#if QT_CONFIG(datestring)
1670 } else if (timeFormat.isEmpty()) {
1672 } else {
1673 message.append(QDateTime::currentDateTime().toString(timeFormat));
1674#endif // QT_CONFIG(datestring)
1675 }
1676 } else if (token == ifCategoryTokenC) {
1677 if (isDefaultCategory(context.category))
1678 skip = true;
1679#define HANDLE_IF_TOKEN(LEVEL) \
1680 } else if (token == if##LEVEL##TokenC) { \
1681 skip = type != Qt##LEVEL##Msg;
1684 HANDLE_IF_TOKEN(Warning)
1685 HANDLE_IF_TOKEN(Critical)
1686 HANDLE_IF_TOKEN(Fatal)
1687#undef HANDLE_IF_TOKEN
1688 } else {
1690 }
1691 }
1692 return message;
1693}
1694#else // QT_BOOTSTRAPPED
1696{
1697 Q_UNUSED(type);
1699 return str;
1700}
1701#endif
1702#ifndef QLOGGING_HAVE_BACKTRACE
1704{
1705 Q_UNREACHABLE();
1706}
1707#endif
1708
1710
1711// pointer to QtMessageHandler debug handler (with context)
1713
1714// ------------------------ Alternate logging sinks -------------------------
1715
1716#if defined(QT_BOOTSTRAPPED)
1717 // Bootstrapped tools always print to stderr, so no need for alternate sinks
1718#else
1719
1720#if QT_CONFIG(slog2)
1721#ifndef QT_LOG_CODE
1722#define QT_LOG_CODE 9000
1723#endif
1724
1725static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &,
1726 const QString &message)
1727{
1728 if (shouldLogToStderr())
1729 return false; // Leave logging up to stderr handler
1730
1731 QString formattedMessage = message;
1732 formattedMessage.append(u'\n');
1733 if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1734 slog2_buffer_set_config_t buffer_config;
1735 slog2_buffer_t buffer_handle;
1736
1737 buffer_config.buffer_set_name = __progname;
1738 buffer_config.num_buffers = 1;
1739 buffer_config.verbosity_level = SLOG2_DEBUG1;
1740 buffer_config.buffer_config[0].buffer_name = "default";
1741 buffer_config.buffer_config[0].num_pages = 8;
1742
1743 if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1744 fprintf(stderr, "Error registering slogger2 buffer!\n");
1745 fprintf(stderr, "%s", formattedMessage.toLocal8Bit().constData());
1746 fflush(stderr);
1747 return false;
1748 }
1749
1750 // Set as the default buffer
1751 slog2_set_default_buffer(buffer_handle);
1752 }
1753 int severity = SLOG2_INFO;
1754 //Determines the severity level
1755 switch (type) {
1756 case QtDebugMsg:
1757 severity = SLOG2_DEBUG1;
1758 break;
1759 case QtInfoMsg:
1760 severity = SLOG2_INFO;
1761 break;
1762 case QtWarningMsg:
1763 severity = SLOG2_NOTICE;
1764 break;
1765 case QtCriticalMsg:
1766 severity = SLOG2_WARNING;
1767 break;
1768 case QtFatalMsg:
1769 severity = SLOG2_ERROR;
1770 break;
1771 }
1772 //writes to the slog2 buffer
1773 slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1774
1775 return true; // Prevent further output to stderr
1776}
1777#endif // slog2
1778
1779#if QT_CONFIG(journald)
1780static bool systemd_default_message_handler(QtMsgType type,
1782 const QString &formattedMessage)
1783{
1784 if (shouldLogToStderr())
1785 return false; // Leave logging up to stderr handler
1786
1787 int priority = LOG_INFO; // Informational
1788 switch (type) {
1789 case QtDebugMsg:
1790 priority = LOG_DEBUG; // Debug-level messages
1791 break;
1792 case QtInfoMsg:
1793 priority = LOG_INFO; // Informational conditions
1794 break;
1795 case QtWarningMsg:
1796 priority = LOG_WARNING; // Warning conditions
1797 break;
1798 case QtCriticalMsg:
1799 priority = LOG_CRIT; // Critical conditions
1800 break;
1801 case QtFatalMsg:
1802 priority = LOG_ALERT; // Action must be taken immediately
1803 break;
1804 }
1805
1806 sd_journal_send("MESSAGE=%s", formattedMessage.toUtf8().constData(),
1807 "PRIORITY=%i", priority,
1808 "CODE_FUNC=%s", context.function ? context.function : "unknown",
1809 "CODE_LINE=%d", context.line,
1810 "CODE_FILE=%s", context.file ? context.file : "unknown",
1811 "QT_CATEGORY=%s", context.category ? context.category : "unknown",
1812 NULL);
1813
1814 return true; // Prevent further output to stderr
1815}
1816#endif
1817
1818#if QT_CONFIG(syslog)
1819static bool syslog_default_message_handler(QtMsgType type, const QMessageLogContext &context,
1820 const QString &formattedMessage)
1821{
1822 if (shouldLogToStderr())
1823 return false; // Leave logging up to stderr handler
1824
1825 int priority = LOG_INFO; // Informational
1826 switch (type) {
1827 case QtDebugMsg:
1828 priority = LOG_DEBUG; // Debug-level messages
1829 break;
1830 case QtInfoMsg:
1831 priority = LOG_INFO; // Informational conditions
1832 break;
1833 case QtWarningMsg:
1834 priority = LOG_WARNING; // Warning conditions
1835 break;
1836 case QtCriticalMsg:
1837 priority = LOG_CRIT; // Critical conditions
1838 break;
1839 case QtFatalMsg:
1840 priority = LOG_ALERT; // Action must be taken immediately
1841 break;
1842 }
1843
1844 syslog(priority, "%s", formattedMessage.toUtf8().constData());
1845
1846 return true; // Prevent further output to stderr
1847}
1848#endif
1849
1850#ifdef Q_OS_ANDROID
1851static bool android_default_message_handler(QtMsgType type,
1853 const QString &formattedMessage)
1854{
1855 if (shouldLogToStderr())
1856 return false; // Leave logging up to stderr handler
1857
1858 android_LogPriority priority = ANDROID_LOG_DEBUG;
1859 switch (type) {
1860 case QtDebugMsg:
1861 priority = ANDROID_LOG_DEBUG;
1862 break;
1863 case QtInfoMsg:
1864 priority = ANDROID_LOG_INFO;
1865 break;
1866 case QtWarningMsg:
1867 priority = ANDROID_LOG_WARN;
1868 break;
1869 case QtCriticalMsg:
1870 priority = ANDROID_LOG_ERROR;
1871 break;
1872 case QtFatalMsg:
1873 priority = ANDROID_LOG_FATAL;
1874 break;
1875 };
1876
1877 // If application name is a tag ensure it has no spaces
1878 // If a category is defined, use it as an Android logging tag
1879 __android_log_print(priority, isDefaultCategory(context.category) ?
1881 "%s\n", qPrintable(formattedMessage));
1882
1883 return true; // Prevent further output to stderr
1884}
1885#endif //Q_OS_ANDROID
1886
1887#ifdef Q_OS_WIN
1888static void win_outputDebugString_helper(const QString &message)
1889{
1890 const qsizetype maxOutputStringLength = 32766;
1891 Q_CONSTINIT static QBasicMutex m;
1892 auto locker = qt_unique_lock(m);
1893 // fast path: Avoid string copies if one output is enough
1894 if (message.length() <= maxOutputStringLength) {
1895 OutputDebugString(reinterpret_cast<const wchar_t *>(message.utf16()));
1896 } else {
1897 wchar_t *messagePart = new wchar_t[maxOutputStringLength + 1];
1898 for (qsizetype i = 0; i < message.length(); i += maxOutputStringLength) {
1899 const qsizetype length = qMin(message.length() - i, maxOutputStringLength);
1900 const qsizetype len = QStringView{message}.mid(i, length).toWCharArray(messagePart);
1901 Q_ASSERT(len == length);
1902 messagePart[len] = 0;
1903 OutputDebugString(messagePart);
1904 }
1905 delete[] messagePart;
1906 }
1907}
1908
1909static bool win_message_handler(QtMsgType, const QMessageLogContext &,
1910 const QString &formattedMessage)
1911{
1912 if (shouldLogToStderr())
1913 return false; // Leave logging up to stderr handler
1914
1915 win_outputDebugString_helper(formattedMessage + u'\n');
1916
1917 return true; // Prevent further output to stderr
1918}
1919#endif
1920
1921#ifdef Q_OS_WASM
1922static bool wasm_default_message_handler(QtMsgType type,
1923 const QMessageLogContext &,
1924 const QString &formattedMessage)
1925{
1926 static bool forceStderrLogging = qEnvironmentVariableIntValue("QT_FORCE_STDERR_LOGGING");
1927 if (forceStderrLogging)
1928 return false;
1929
1930 int emOutputFlags = EM_LOG_CONSOLE;
1931 QByteArray localMsg = formattedMessage.toLocal8Bit();
1932 switch (type) {
1933 case QtDebugMsg:
1934 break;
1935 case QtInfoMsg:
1936 break;
1937 case QtWarningMsg:
1938 emOutputFlags |= EM_LOG_WARN;
1939 break;
1940 case QtCriticalMsg:
1941 emOutputFlags |= EM_LOG_ERROR;
1942 break;
1943 case QtFatalMsg:
1944 emOutputFlags |= EM_LOG_ERROR;
1945 }
1946 emscripten_log(emOutputFlags, "%s\n", qPrintable(formattedMessage));
1947
1948 return true; // Prevent further output to stderr
1949}
1950#endif
1951
1952#endif // Bootstrap check
1953
1954// --------------------------------------------------------------------------
1955
1957 const QString &formattedMessage)
1958{
1959 Q_UNUSED(type);
1961
1962 // print nothing if message pattern didn't apply / was empty.
1963 // (still print empty lines, e.g. because message itself was empty)
1964 if (formattedMessage.isNull())
1965 return;
1966 fprintf(stderr, "%s\n", formattedMessage.toLocal8Bit().constData());
1967 fflush(stderr);
1968}
1969
1970namespace {
1971struct SystemMessageSink
1972{
1973 using Fn = bool(QtMsgType, const QMessageLogContext &, const QString &);
1974 Fn *sink;
1975 bool messageIsUnformatted = false;
1976};
1977}
1978
1979static constexpr SystemMessageSink systemMessageSink = {
1980#if defined(QT_BOOTSTRAPPED)
1981 nullptr
1982#elif defined(Q_OS_WIN)
1983 win_message_handler
1984#elif QT_CONFIG(slog2)
1985 slog2_default_handler
1986#elif QT_CONFIG(journald)
1987 systemd_default_message_handler
1988#elif QT_CONFIG(syslog)
1989 syslog_default_message_handler
1990#elif defined(Q_OS_ANDROID)
1991 android_default_message_handler
1992#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
1994#elif defined Q_OS_WASM
1995 wasm_default_message_handler
1996#else
1997 nullptr
1998#endif
1999};
2000
2002 const QString &formattedMessage)
2003{
2005QT_WARNING_DISABLE_GCC("-Waddress") // "the address of ~~ will never be NULL
2006 if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
2007 return;
2009
2010 stderr_message_handler(type, context, formattedMessage);
2011}
2012
2017 const QString &message)
2018{
2019 // A message sink logs the message to a structured or unstructured destination,
2020 // optionally formatting the message if the latter, and returns true if the sink
2021 // handled stderr output as well, which will shortcut our default stderr output.
2022
2023 if (systemMessageSink.messageIsUnformatted) {
2025 return;
2026 }
2027
2029}
2030
2031#if defined(QT_BOOTSTRAPPED)
2032// there's no message handler in bootstrapped mode; force everything to stderr
2033static bool grabMessageHandler() { return false; }
2034static void ungrabMessageHandler() { }
2035
2036#elif defined(Q_COMPILER_THREAD_LOCAL)
2037
2038Q_CONSTINIT static thread_local bool msgHandlerGrabbed = false;
2039
2040static bool grabMessageHandler()
2041{
2042 if (msgHandlerGrabbed)
2043 return false;
2044
2045 msgHandlerGrabbed = true;
2046 return true;
2047}
2048
2049static void ungrabMessageHandler()
2050{
2051 msgHandlerGrabbed = false;
2052}
2053
2054#else
2055static bool grabMessageHandler() { return true; }
2056static void ungrabMessageHandler() { }
2057#endif // (Q_COMPILER_THREAD_LOCAL)
2058
2060{
2061#ifndef QT_BOOTSTRAPPED
2062 Q_TRACE(qt_message_print, msgType, context.category, context.function, context.file, context.line, message);
2063
2064 // qDebug, qWarning, ... macros do not check whether category is enabledgc
2065 if (msgType != QtFatalMsg && isDefaultCategory(context.category)) {
2066 if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
2067 if (!defaultCategory->isEnabled(msgType))
2068 return;
2069 }
2070 }
2071#endif
2072
2073 // prevent recursion in case the message handler generates messages
2074 // itself, e.g. by using Qt API
2075 if (grabMessageHandler()) {
2076 const auto ungrab = qScopeGuard([]{ ungrabMessageHandler(); });
2077 auto msgHandler = messageHandler.loadAcquire();
2078 (msgHandler ? msgHandler : qDefaultMessageHandler)(msgType, context, message);
2079 } else {
2081 }
2082}
2083
2084template <typename String>
2086{
2087#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
2088 wchar_t contextFileL[256];
2089 // we probably should let the compiler do this for us, by declaring QMessageLogContext::file to
2090 // be const wchar_t * in the first place, but the #ifdefery above is very complex and we
2091 // wouldn't be able to change it later on...
2092 convert_to_wchar_t_elided(contextFileL, sizeof contextFileL / sizeof *contextFileL,
2093 context.file);
2094 // get the current report mode
2095 int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
2096 _CrtSetReportMode(_CRT_ERROR, reportMode);
2097
2098 int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
2099 reinterpret_cast<const wchar_t *>(message.utf16()));
2100 if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
2101 return; // ignore
2102 else if (ret == 1)
2103 _CrtDbgBreak();
2104#else
2106#endif
2107
2108 if constexpr (std::is_class_v<String> && !std::is_const_v<String>)
2109 message.clear();
2110 else
2112 qAbort();
2113}
2114
2119{
2121 qt_message_print(msgType, ctx, message);
2122 if (isFatal(msgType))
2123 qt_message_fatal(msgType, ctx, message);
2124}
2125
2126void qErrnoWarning(const char *msg, ...)
2127{
2128 // qt_error_string() will allocate anyway, so we don't have
2129 // to be careful here (like we do in plain qWarning())
2130 QString error_string = qt_error_string(-1); // before vasprintf changes errno/GetLastError()
2131
2132 va_list ap;
2133 va_start(ap, msg);
2134 QString buf = QString::vasprintf(msg, ap);
2135 va_end(ap);
2136
2137 buf += " ("_L1 + error_string + u')';
2140}
2141
2142void qErrnoWarning(int code, const char *msg, ...)
2143{
2144 // qt_error_string() will allocate anyway, so we don't have
2145 // to be careful here (like we do in plain qWarning())
2146 va_list ap;
2147 va_start(ap, msg);
2148 QString buf = QString::vasprintf(msg, ap);
2149 va_end(ap);
2150
2151 buf += " ("_L1 + qt_error_string(code) + u')';
2154}
2155
2316{
2317 const auto old = messageHandler.fetchAndStoreOrdered(h);
2318 if (old)
2319 return old;
2320 else
2322}
2323
2324#ifndef QT_BOOTSTRAPPED
2326{
2327 const auto locker = qt_scoped_lock(QMessagePattern::mutex);
2328
2329 if (!qMessagePattern()->fromEnvironment)
2330 qMessagePattern()->setPattern(pattern);
2331}
2332#endif
2333
2335 const QMessageLogContext &logContext) noexcept
2336{
2337 if (logContext.version == self->version) {
2338 auto other = static_cast<const QInternalMessageLogContext *>(&logContext);
2339 self->backtrace = other->backtrace;
2340 }
2341}
2342
2349{
2350 version = CurrentVersion + 1;
2351 copyContextFrom(logContext);
2352
2353#ifdef QLOGGING_HAVE_BACKTRACE
2354 if (backtrace.has_value())
2355 return 0; // we have a stored backtrace, no need to get it again
2356
2357 // initializes the message pattern, if needed
2358 if (auto pattern = qMessagePattern())
2359 return pattern->maxBacktraceDepth;
2360#endif
2361
2362 return 0;
2363}
2364
2373QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext &logContext) noexcept
2374{
2375 this->category = logContext.category;
2376 this->file = logContext.file;
2377 this->line = logContext.line;
2378 this->function = logContext.function;
2379 if (Q_UNLIKELY(version == CurrentVersion + 1))
2380 copyInternalContext(static_cast<QInternalMessageLogContext *>(this), logContext);
2381 return *this;
2382}
2383
static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
\inmodule QtCore
Definition qatomic.h:112
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
static qint64 applicationPid() Q_DECL_CONST_FUNCTION
QString applicationName
the name of this application
static QDateTime currentDateTime()
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QDeadlineTimer current(Qt::TimerType timerType=Qt::CoarseTimer) noexcept
Returns a QDeadlineTimer that is expired but is guaranteed to contain the current time.
\inmodule QtCore
\inmodule QtCore
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
int initFrom(const QMessageLogContext &logContext)
void populateBacktrace(int frameCount)
std::optional< BacktraceStorage > backtrace
Definition qlogging_p.h:57
constexpr const char * data() const noexcept
constexpr qsizetype size() const noexcept
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
\inmodule QtCore
static QLoggingCategory * defaultCategory()
Returns a pointer to the global category "default" that is used, for example, by qDebug(),...
\inmodule QtCore
Definition qlogging.h:42
const char * category
Definition qlogging.h:54
static constexpr int CurrentVersion
Definition qlogging.h:45
Q_DECL_COLD_FUNCTION QDebug critical() const
Logs a critical message using a QDebug stream.
Definition qlogging.cpp:784
Q_DECL_COLD_FUNCTION QDebug warning() const
Logs a warning message using a QDebug stream.
Definition qlogging.cpp:682
void void void void Q_DECL_COLD_FUNCTION void Q_DECL_COLD_FUNCTION void Q_DECL_COLD_FUNCTION void Q_DECL_COLD_FUNCTION void QT_MESSAGE_LOGGER_NORETURN Q_DECL_COLD_FUNCTION void QT_MESSAGE_LOGGER_NORETURN Q_DECL_COLD_FUNCTION void QDebug debug() const
Logs a debug message using a QDebug stream.
Definition qlogging.cpp:477
Q_DECL_COLD_FUNCTION QDebug fatal() const
Logs a fatal message using a QDebug stream.
Definition qlogging.cpp:896
QDebug info() const
Logs an informational message using a QDebug stream.
Definition qlogging.cpp:579
QNoDebug noDebug() const noexcept
Definition qlogging.cpp:522
void void Q_DECL_COLD_FUNCTION void Q_DECL_COLD_FUNCTION void QT_MESSAGE_LOGGER_NORETURN Q_DECL_COLD_FUNCTION void typedef const QLoggingCategory &(* CategoryFunction)()
This is a typedef for a pointer to a function with the following signature:
Definition qlogging.h:92
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore \reentrant
QStringView capturedView(int nth=0) const
\inmodule QtCore \reentrant
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
int toInt(bool *ok=nullptr, int base=10) const
Returns the string view converted to an int using base base, which is 10 by default and must be betwe...
Definition qstring.h:1132
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition qstring.h:731
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromStdString(const std::string &s)
Definition qstring.h:1447
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
static QString vasprintf(const char *format, va_list ap) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7357
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7263
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:149
static QThread * currentThread()
Definition qthread.cpp:1039
EGLContext ctx
const QLoggingCategory & category()
[1]
QString str
[2]
static const char functionTokenC[]
static const char typeTokenC[]
static const char timeTokenC[]
static const char endifTokenC[]
static bool grabMessageHandler()
static const char ifInfoTokenC[]
void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
static Q_NEVER_INLINE void qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
Definition qlogging.cpp:374
static const char emptyTokenC[]
static void preformattedMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &formattedMessage)
static bool systemHasStderr()
Returns true if writing to stderr is supported.
Definition qlogging.cpp:226
static const char ifCategoryTokenC[]
static bool isDefaultCategory(const char *category)
Definition qlogging.cpp:934
static const char appnameTokenC[]
Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
Definition qlogging.cpp:942
static const char ifCriticalTokenC[]
#define HANDLE_IF_TOKEN(LEVEL)
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf)
static bool is_fatal_count_down(QAtomicInt &n)
Definition qlogging.cpp:191
static const char qthreadptrTokenC[]
static const char categoryTokenC[]
static const char lineTokenC[]
static const char messageTokenC[]
static const char fileTokenC[]
static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &formattedMessage)
static constexpr SystemMessageSink systemMessageSink
static const char pidTokenC[]
static const char threadidTokenC[]
static const char defaultPattern[]
static void ungrabMessageHandler()
static void copyInternalContext(QInternalMessageLogContext *self, const QMessageLogContext &logContext) noexcept
static int checked_var_value(const char *varname)
Definition qlogging.cpp:177
static Q_CONSTINIT QBasicAtomicPointer< void(QtMsgType, const QMessageLogContext &, const QString &) messageHandler)
static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
void qErrnoWarning(const char *msg,...)
static const char ifWarningTokenC[]
#define IF_TOKEN(LEVEL)
static const char ifDebugTokenC[]
static const char backtraceTokenC[]
static Q_NORETURN void qt_message_fatal(QtMsgType, const QMessageLogContext &context, String &&message)
\inmodule QtCore \title Qt Logging Types
static const char ifFatalTokenC[]
static bool isFatal(QtMsgType msgType)
Definition qlogging.cpp:202
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.
Definition qlogging.cpp:253
void qSetMessagePattern(const QString &pattern)
Token token
Definition keywords.cpp:444
Combined button and popup list for selecting options.
Lock qt_unique_lock(Mutex &mutex)
Definition qlocking_p.h:64
\macro QT_NO_KEYWORDS >
bool shouldLogToStderr()
Returns true if logging stderr should be ensured.
Definition qlogging.cpp:306
@ ISODate
Definition qctf_p.h:75
static void * context
QT_BEGIN_NAMESPACE void qAbort()
Definition qassert.cpp:24
#define Q_BASIC_ATOMIC_INITIALIZER(a)
size_t qstrlen(const char *str)
Q_CORE_EXPORT char * qstrdup(const char *)
#define assert
#define Q_UNLIKELY(x)
#define Q_NORETURN
#define Q_NEVER_INLINE
#define QT_WARNING_POP
#define QT_WARNING_DISABLE_GCC(text)
#define QT_WARNING_PUSH
static int qt_safe_open(const char *pathname, int flags, mode_t mode=0777)
static int qt_safe_close(int fd)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define QT_TERMINATE_ON_EXCEPTION(expr)
#define forever
Definition qforeach.h:78
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define QT_MESSAGELOG_FILE
Definition qlogging.h:155
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
Q_CORE_EXPORT QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &buf)
#define QT_MESSAGELOG_LINE
Definition qlogging.h:156
QtMsgType
Definition qlogging.h:29
@ QtCriticalMsg
Definition qlogging.h:32
@ QtInfoMsg
Definition qlogging.h:34
@ QtWarningMsg
Definition qlogging.h:31
@ QtFatalMsg
Definition qlogging.h:33
@ QtDebugMsg
Definition qlogging.h:30
void(* QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &)
Definition qlogging.h:191
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLsizei const GLfloat * v
[13]
GLint GLenum GLsizei GLsizei GLsizei depth
const GLfloat * m
GLuint GLuint end
GLsizei const GLchar ** strings
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLuint buffer
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLuint GLsizei const GLchar * message
GLenum GLenum severity
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint entry
GLenum const void * addr
GLsizei GLenum GLboolean sink
GLuint64EXT * result
[6]
GLenum GLsizei len
GLubyte * pattern
#define _PATH_TTY
static void decodeFrame(const QString &f, QV4::CppStackFrame **frame)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
#define Q_AUTOTEST_EXPORT
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define QT_STRINGIFY(x)
#define Q_UNUSED(x)
#define Q_TRACE(x,...)
Definition qtrace_p.h:144
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
@ Q_RELOCATABLE_TYPE
Definition qtypeinfo.h:158
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:180
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
qint64 qlonglong
Definition qtypes.h:63
ptrdiff_t qintptr
Definition qtypes.h:166
QT_BEGIN_NAMESPACE Q_ALWAYS_INLINE void qYieldCpu(void) Q_DECL_NOEXCEPT
Definition qyieldcpu.h:29
QFile file
[0]
p rx()++
QSharedPointer< T > other(t)
[5]
QFrame frame
[0]
QHostInfo info
[0]
char * toString(const MyType &t)
[31]
QList< QString > timeArgs
std::unique_ptr< std::unique_ptr< const char[]>[]> literals
void setPattern(const QString &pattern)
std::unique_ptr< const char *[]> tokens
QElapsedTimer timer
static QBasicMutex mutex