13#ifdef SWIFT_USE_CRASHPAD
14# include "crashpad/client/simulate_crash.h"
19#include <QAbstractNativeEventFilter>
20#include <QCoreApplication>
21#include <QGlobalStatic>
22#include <QMessageLogContext>
38 Q_ASSERT(!g_handler.isDestroyed());
43 void messageHandler(QtMsgType type,
const QMessageLogContext &context,
const QString &message)
54#if defined(Q_CC_MSVC) && defined(QT_NO_DEBUG)
55 if (type == QtFatalMsg)
57 struct EventFilter :
public QAbstractNativeEventFilter
60 virtual bool nativeEventFilter(
const QByteArray &,
void *message, qintptr *result)
override
62 auto msg =
static_cast<MSG *
>(message);
63 *result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
68 qApp->installNativeEventFilter(&ef);
69 MessageBoxW(
nullptr, message.
toStdWString().c_str(),
nullptr,
71 qApp->removeNativeEventFilter(&ef);
72# if defined(SWIFT_USE_CRASHPAD)
73 CRASHPAD_SIMULATE_CRASH();
84 if (skipIfAlreadyInstalled && m_oldHandler)
88 Q_ASSERT_X(!m_oldHandler, Q_FUNC_INFO,
"Re-installing the log handler should be avoided");
89 m_oldHandler = qInstallMessageHandler(messageHandler);
92 CLogHandler::CLogHandler()
98 CLogHandler::~CLogHandler() { qInstallMessageHandler(m_oldHandler); }
104 auto finder = [&](
const PatternPair &pair) {
return pair.first == pattern; };
105 auto comparator = [](
const PatternPair &a,
const PatternPair &b) {
return a.first.isProperSubsetOf(b.first); };
107 auto it = std::ranges::find_if(m_patternHandlers, finder);
108 if (it == m_patternHandlers.cend())
110 auto *handler =
new CLogPatternHandler(
this, pattern);
125 QList<CLogPatternHandler *> CLogHandler::handlersForMessage(
const CStatusMessage &message)
const
127 QList<CLogPatternHandler *> m_handlers;
128 for (
const auto &pair : m_patternHandlers)
130 if (pair.first.match(message))
138 bool CLogHandler::isFallThroughEnabled(
const QList<CLogPatternHandler *> &handlers)
const
140 for (
const auto *handler : handlers)
142 if (!handler->m_inheritFallThrough)
144 return handler->m_enableFallThrough;
147 return m_enableFallThrough;
152 using namespace swift::config;
153 CStatusMessage statusMessage = i_statusMessage;
154 if (!CBuildConfig::isLocalDeveloperDebugBuild() &&
161 if (!CBuildConfig::isLocalDeveloperDebugBuild() &&
167 if (statusMessage.getMessage().startsWith(QStringLiteral(
"libpng warning")))
173 else if (statusMessage.getMessage().startsWith(QStringLiteral(
"QCommandLineParser: option not defined")))
179 auto bucket = m_tokenBuckets.find(statusMessage);
180 if (bucket == m_tokenBuckets.end())
182 bucket = m_tokenBuckets.insert(statusMessage, { { 5, 1000, 1 }, 0 });
184 if (!bucket->first.tryConsume())
189 if (bucket->second > 0)
191 auto copy = statusMessage;
192 copy.appendMessage(QStringLiteral(
" (+%1 identical messages)").arg(bucket->second));
200 logMessage(statusMessage);
206 logMessage(statusMessage);
212 Q_ASSERT_X(m_oldHandler, Q_FUNC_INFO,
"Install the log handler before using it");
214 m_enableFallThrough = enable;
219 const auto handlers = handlersForMessage(statusMessage);
221 if (isFallThroughEnabled(handlers))
223 Q_ASSERT_X(m_oldHandler, Q_FUNC_INFO,
"Handler must be installed");
227 statusMessage.toQtLogTriple(&type, &category, &message);
228 m_oldHandler(type, QMessageLogContext(
nullptr, 0,
nullptr, qPrintable(category)), message);
231 for (
auto *handler : handlers)
233 emit handler->messageLogged(statusMessage);
239 auto it = std::ranges::find_if(m_patternHandlers,
240 [handler](
const PatternPair &pair) {
return pair.second == handler; });
241 if (it != m_patternHandlers.end())
243 it->second->deleteLater();
244 m_patternHandlers.erase(it);
250 QList<CLogPattern> result;
251 for (
const auto &pair : m_patternHandlers)
262 : QObject(parent), m_parent(parent), m_pattern(pattern)
265 m_subscriptionUpdateTimer.start(1);
268 void CLogPatternHandler::updateSubscription()
270 if (m_subscriptionNeedsUpdate)
272 m_subscriptionNeedsUpdate =
false;
275 if (isSubscribed != m_isSubscribed)
277 m_isSubscribed = isSubscribed;
280 emit m_parent->subscriptionAdded(m_pattern);
284 emit m_parent->subscriptionRemoved(m_pattern);
288 if (m_inheritFallThrough && !m_isSubscribed)
290 m_parent->removePatternHandler(
this);
295 void CLogSubscriber::changeSubscription(
const CLogPattern &pattern)
303 self->changeSubscription(pattern);
310 m_handler = CLogHandler::instance()->handlerForPattern(pattern);
312 if (!m_inheritFallThrough)
314 m_handler->enableConsoleOutput(m_enableFallThrough);
316 connect(m_handler.data(), &CLogPatternHandler::messageLogged,
this, &CLogSubscriber::ps_logMessage,
320 void CLogSubscriber::unsubscribe()
336 if (!m_inheritFallThrough)
338 m_handler->inheritConsoleOutput();
340 m_handler->disconnect(
this);
344 void CLogSubscriber::inheritConsoleOutput()
352 self->inheritConsoleOutput();
358 m_inheritFallThrough =
true;
361 m_handler->inheritConsoleOutput();
365 void CLogSubscriber::enableConsoleOutput(
bool enable)
373 self->enableConsoleOutput(enable);
379 m_inheritFallThrough =
false;
380 m_enableFallThrough = enable;
383 m_handler->enableConsoleOutput(enable);
A log category is an arbitrary string tag which can be attached to log messages.
Class for subscribing to log messages.
void localMessageLogged(const swift::misc::CStatusMessage &message)
Emitted when a message is logged in this process.
void enableConsoleOutput(bool enable)
Enable or disable the default Qt handler.
static CLogHandler * instance()
Return pointer to the CLogHandler singleton.
CLogPatternHandler * handlerForCategory(const CLogCategory &category)
Return a pattern handler for subscribing to all messages which contain the given category.
QList< CLogPattern > getAllSubscriptions() const
Returns all log patterns for which there are currently subscribed log pattern handlers.
void logLocalMessage(const swift::misc::CStatusMessage &message)
Called by our QtMessageHandler to log a message.
void logRemoteMessage(const swift::misc::CStatusMessage &message)
Called by the context to relay a message.
void remoteMessageLogged(const swift::misc::CStatusMessage &message)
Emitted when a log message is relayed from a different process.
void install(bool skipIfAlreadyInstalled=false)
Tell the CLogHandler to install itself with qInstallMessageHandler.
CLogPatternHandler * handlerForPattern(const CLogPattern &pattern)
Return a pattern handler for subscribing to all messages which match the given pattern.
A class for subscribing to log messages which match particular patterns.
void messageLogged(const swift::misc::CStatusMessage &message)
Emitted when a message is logged which matches the relevant pattern.
Value class for matching log messages based on their categories.
static CLogPattern exactMatch(const CLogCategory &category)
Returns a CLogPattern which will match any message with the given category.
static CLogPattern empty()
Returns a CLogPattern which will match any message without a category.
Streamable status message, e.g.
static constexpr auto SeverityError
Status severities.
static constexpr auto SeverityDebug
Status severities.
static constexpr auto SeverityWarning
Status severities.
Free functions in swift::misc.
void topologicallySortedInsert(C &container, T &&value, F comparator)
Insert an element into a sequential container while preserving the topological ordering of the contai...
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
QCoreApplication * instance()
void push_back(QList< T >::parameter_type value)
bool moveToThread(QThread *targetThread)
QThread * thread() const const
std::wstring toStdWString() const const
QFuture< QtFuture::ArgsType< Signal > > connect(Sender *sender, Signal signal)
QThread * currentThread()