Move logging into a separate thread

This commit is contained in:
Cameron Gutman 2024-10-20 21:52:15 -05:00
parent 2257cb0cef
commit 103f988dbf

View File

@ -62,22 +62,37 @@
static QElapsedTimer s_LoggerTime; static QElapsedTimer s_LoggerTime;
static QTextStream s_LoggerStream(stderr); static QTextStream s_LoggerStream(stderr);
static QMutex s_LoggerLock; static QThreadPool s_LoggerThread;
static bool s_SuppressVerboseOutput; static bool s_SuppressVerboseOutput;
static QRegularExpression k_RikeyRegex("&rikey=\\w+"); static QRegularExpression k_RikeyRegex("&rikey=\\w+");
static QRegularExpression k_RikeyIdRegex("&rikeyid=[\\d-]+"); static QRegularExpression k_RikeyIdRegex("&rikeyid=[\\d-]+");
#ifdef LOG_TO_FILE #ifdef LOG_TO_FILE
// Max log file size of 10 MB // Max log file size of 10 MB
#define MAX_LOG_SIZE_BYTES (10 * 1024 * 1024) static const uint64_t k_MaxLogSizeBytes = 10 * 1024 * 1024;
static int s_LogBytesWritten = 0; static QAtomicInteger<uint64_t> s_LogBytesWritten = 0;
static bool s_LogLimitReached = false;
static QFile* s_LoggerFile; static QFile* s_LoggerFile;
#endif #endif
class LoggerTask : public QRunnable
{
public:
LoggerTask(const QString& msg) : m_Msg(msg)
{
setAutoDelete(true);
}
void run() override
{
s_LoggerStream << m_Msg;
s_LoggerStream.flush();
}
private:
QString m_Msg;
};
void logToLoggerStream(QString& message) void logToLoggerStream(QString& message)
{ {
QMutexLocker lock(&s_LoggerLock);
#if defined(QT_DEBUG) && defined(Q_OS_WIN32) #if defined(QT_DEBUG) && defined(Q_OS_WIN32)
// Output log messages to a debugger if attached // Output log messages to a debugger if attached
if (IsDebuggerPresent()) { if (IsDebuggerPresent()) {
@ -95,26 +110,25 @@ void logToLoggerStream(QString& message)
message.replace(k_RikeyIdRegex, "&rikeyid=REDACTED"); message.replace(k_RikeyIdRegex, "&rikeyid=REDACTED");
#ifdef LOG_TO_FILE #ifdef LOG_TO_FILE
if (s_LogLimitReached) { auto oldLogSize = s_LogBytesWritten.fetchAndAddRelaxed(message.size());
if (oldLogSize >= k_MaxLogSizeBytes) {
return; return;
} }
else if (s_LogBytesWritten >= MAX_LOG_SIZE_BYTES) { else if (oldLogSize >= k_MaxLogSizeBytes - message.size()) {
s_LoggerThread.waitForDone();
s_LoggerStream << "Log size limit reached!"; s_LoggerStream << "Log size limit reached!";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
s_LoggerStream << Qt::endl; s_LoggerStream << Qt::endl;
#else #else
s_LoggerStream << endl; s_LoggerStream << endl;
#endif #endif
s_LogLimitReached = true; s_LoggerStream.flush();
return; return;
} }
else {
s_LogBytesWritten += message.size();
}
#endif #endif
s_LoggerStream << message; // Queue the log message to be written asynchronously
s_LoggerStream.flush(); s_LoggerThread.start(new LoggerTask(message));
} }
void sdlLogToDiskHandler(void*, int category, SDL_LogPriority priority, const char* message) void sdlLogToDiskHandler(void*, int category, SDL_LogPriority priority, const char* message)
@ -344,6 +358,9 @@ int main(int argc, char *argv[])
} }
#endif #endif
// Serialize log messages on a single thread
s_LoggerThread.setMaxThreadCount(1);
s_LoggerTime.start(); s_LoggerTime.start();
qInstallMessageHandler(qtLogToDiskHandler); qInstallMessageHandler(qtLogToDiskHandler);
SDL_LogSetOutputFunction(sdlLogToDiskHandler, nullptr); SDL_LogSetOutputFunction(sdlLogToDiskHandler, nullptr);
@ -784,6 +801,9 @@ int main(int argc, char *argv[])
// sometimes freezing and blocking process exit. // sometimes freezing and blocking process exit.
QThreadPool::globalInstance()->waitForDone(30000); QThreadPool::globalInstance()->waitForDone(30000);
// Wait for pending log messages to be printed
s_LoggerThread.waitForDone();
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
// Without an explicit flush, console redirection for the list command // Without an explicit flush, console redirection for the list command
// doesn't work reliably (sometimes the target file contains no text). // doesn't work reliably (sometimes the target file contains no text).