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:
parent
37e5e64ddc
commit
c11468b9f1
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue