Qt: Drop log messages if rate is too high

Prevents the application locking up and memory usage going bananas
if log messages do end up spammed at crazy rates.
This commit is contained in:
Stenzek 2025-01-02 00:14:10 +10:00
parent 37e5e64ddc
commit c11468b9f1
No known key found for this signature in database
2 changed files with 56 additions and 18 deletions

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "logwindow.h"
@ -177,6 +177,7 @@ void LogWindow::createUi()
m_text->setUndoRedoEnabled(false);
m_text->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
m_text->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_text->setMaximumBlockCount(MAX_LINES);
#if defined(_WIN32)
QFont font("Consolas");
@ -271,6 +272,8 @@ void LogWindow::logCallback(void* pUserParam, Log::MessageCategory cat, const ch
const QLatin1StringView qchannel(
(Log::UnpackLevel(cat) <= Log::Level::Warning) ? functionName : Log::GetChannelName(Log::UnpackChannel(cat)));
this_ptr->m_lines_pending.fetch_add(1, std::memory_order_acq_rel);
if (QThread::isMainThread())
{
this_ptr->appendMessage(qchannel, static_cast<u32>(cat), qmessage);
@ -307,6 +310,43 @@ void LogWindow::changeEvent(QEvent* event)
}
void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 cat, const QString& message)
{
const int num_lines_still_pending = m_lines_pending.fetch_sub(1, std::memory_order_acq_rel) - 1;
if (m_lines_to_skip > 0)
{
m_lines_to_skip--;
return;
}
if (num_lines_still_pending > MAX_LINES)
{
realAppendMessage(
QLatin1StringView(Log::GetChannelName(Log::Channel::Log)),
Log::PackCategory(Log::Channel::Log, Log::Level::Warning, Log::Color::StrongYellow),
tr("Dropped %1 log messages, please use file or system console logging.\n").arg(num_lines_still_pending));
m_lines_to_skip = num_lines_still_pending;
return;
}
else if (num_lines_still_pending > BLOCK_UPDATES_THRESHOLD)
{
if (m_text->updatesEnabled())
{
m_text->setUpdatesEnabled(false);
m_text->document()->blockSignals(true);
m_text->blockSignals(true);
}
}
else if (!m_text->updatesEnabled())
{
m_text->blockSignals(false);
m_text->document()->blockSignals(false);
m_text->setUpdatesEnabled(true);
}
realAppendMessage(channel, cat, message);
}
void LogWindow::realAppendMessage(const QLatin1StringView& channel, quint32 cat, const QString& message)
{
QTextCursor temp_cursor = m_text->textCursor();
QScrollBar* scrollbar = m_text->verticalScrollBar();
@ -370,6 +410,7 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 cat, con
QTextCharFormat format = temp_cursor.charFormat();
const size_t dark = static_cast<size_t>(m_is_dark_theme);
temp_cursor.beginEditBlock();
if (Log::AreTimestampsEnabled())
{
const float message_time = Log::GetCurrentMessageTime();
@ -395,23 +436,11 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 cat, con
format.setForeground(QBrush(message_colors[dark][static_cast<size_t>(color)]));
temp_cursor.setCharFormat(format);
temp_cursor.insertText(message);
temp_cursor.endEditBlock();
}
if (cursor_at_end)
{
if (scroll_at_end)
{
m_text->setTextCursor(temp_cursor);
scrollbar->setSliderPosition(scrollbar->maximum());
}
else
{
// Can't let changing the cursor affect the scroll bar...
const int pos = scrollbar->sliderPosition();
m_text->setTextCursor(temp_cursor);
scrollbar->setSliderPosition(pos);
}
}
if (cursor_at_end && scroll_at_end)
m_text->centerCursor();
}
void LogWindow::saveSize()

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
@ -7,9 +7,11 @@
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QPlainTextEdit>
#include <atomic>
#include <span>
class LogWindow : public QMainWindow
class ALIGN_TO_CACHE_LINE LogWindow : public QMainWindow
{
Q_OBJECT
@ -43,10 +45,13 @@ private Q_SLOTS:
void onClearTriggered();
void onSaveTriggered();
void appendMessage(const QLatin1StringView& channel, quint32 cat, const QString& message);
void realAppendMessage(const QLatin1StringView& channel, quint32 cat, const QString& message);
private:
static constexpr int DEFAULT_WIDTH = 750;
static constexpr int DEFAULT_HEIGHT = 400;
static constexpr int MAX_LINES = 1000;
static constexpr int BLOCK_UPDATES_THRESHOLD = 100;
void saveSize();
void restoreSize();
@ -54,9 +59,13 @@ private:
QPlainTextEdit* m_text;
QMenu* m_level_menu;
int m_lines_to_skip = 0;
bool m_is_dark_theme = false;
bool m_attached_to_main_window = true;
bool m_destroying = false;
ALIGN_TO_CACHE_LINE std::atomic_int m_lines_pending{0};
};
extern LogWindow* g_log_window;