logs: Batch log messages (optimization)

This commit is contained in:
Eladash 2022-06-19 18:33:09 +03:00 committed by Megamouse
parent 0bfdfd8433
commit 74a909cfbc
2 changed files with 124 additions and 54 deletions

View file

@ -79,7 +79,6 @@ struct gui_listener : logs::listener
} }
_new->msg += text; _new->msg += text;
_new->msg += '\n';
queue.push(std::move(p)); queue.push(std::move(p));
} }
@ -587,32 +586,24 @@ void log_frame::UpdateUI()
const QString font_start_tag_stack = "<font color = \"" % m_color_stack.name() % "\">"; const QString font_start_tag_stack = "<font color = \"" % m_color_stack.name() % "\">";
const QString font_end_tag = QStringLiteral("</font>"); const QString font_end_tag = QStringLiteral("</font>");
static constexpr auto escaped = [](QString& text) static constexpr auto escaped = [](const QString& text)
{ {
return text.toHtmlEscaped().replace(QStringLiteral("\n"), QStringLiteral("<br/>")); return text.toHtmlEscaped().replace(QStringLiteral("\n"), QStringLiteral("<br/>"));
}; };
// Check main logs // Preserve capacity
while (auto* packet = s_gui_listener.get()) m_log_text.resize(0);
{
// Confirm log level
if (packet->sev <= s_gui_listener.enabled)
{
QString text;
switch (packet->sev)
{
case logs::level::always: text = QStringLiteral("- "); break;
case logs::level::fatal: text = QStringLiteral("F "); break;
case logs::level::error: text = QStringLiteral("E "); break;
case logs::level::todo: text = QStringLiteral("U "); break;
case logs::level::success: text = QStringLiteral("S "); break;
case logs::level::warning: text = QStringLiteral("W "); break;
case logs::level::notice: text = QStringLiteral("! "); break;
case logs::level::trace: text = QStringLiteral("T "); break;
}
// Print UTF-8 text. // Handle a special case in which we may need to override the previous repetition count
text += qstr(packet->msg); bool is_first_rep = true;
// Batch output of multiple lines if possible (optimization)
auto flush = [&]()
{
if (m_log_text.isEmpty() && !is_first_rep)
{
return;
}
// save old log state // save old log state
QScrollBar* sb = m_log->verticalScrollBar(); QScrollBar* sb = m_log->verticalScrollBar();
@ -627,32 +618,31 @@ void log_frame::UpdateUI()
// clear selection or else it will get colorized as well // clear selection or else it will get colorized as well
text_cursor.clearSelection(); text_cursor.clearSelection();
// remove the new line because Qt's append adds a new line already. m_log->setTextCursor(text_cursor);
text.chop(1);
// create counter suffix and remove recurring line if needed if (is_first_rep)
if (m_stack_log)
{
// add counter suffix if needed
if (text == m_old_log_text)
{ {
// Override repetition count of previous UpdateUI() (special case)
text_cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); text_cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
text_cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor); text_cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, (m_log_counter != 2 ? 1 + QString::number(m_log_counter - 1).size() : 0));
text_cursor.insertHtml(font_start_tag(m_color[static_cast<int>(packet->sev)]) % escaped(text) % font_start_tag_stack % QStringLiteral(" x") % QString::number(++m_log_counter) % font_end_tag % font_end_tag); text_cursor.insertHtml(font_start_tag_stack % QStringLiteral(" x") % QString::number(m_log_counter) % font_end_tag);
} }
else else if (m_log_counter > 1)
{ {
m_log_counter = 1; // Insert both messages and repetition prefix (append is more optimized than concatenation)
m_old_log_text = text; m_log_text += font_end_tag;
m_log_text += font_start_tag_stack;
m_log_text += QStringLiteral(" x");
m_log_text += QString::number(m_log_counter);
m_log_text += font_end_tag;
m_log->setTextCursor(text_cursor); m_log->appendHtml(m_log_text);
m_log->appendHtml(font_start_tag(m_color[static_cast<int>(packet->sev)]) % escaped(text) % font_end_tag); m_log_counter = 0;
}
} }
else else
{ {
m_log->setTextCursor(text_cursor); m_log_text += font_end_tag;
m_log->appendHtml(font_start_tag(m_color[static_cast<int>(packet->sev)]) % escaped(text) % font_end_tag); m_log->appendHtml(m_log_text);
} }
// if we mark text from right to left we need to swap sides (start is always smaller than end) // if we mark text from right to left we need to swap sides (start is always smaller than end)
@ -668,6 +658,81 @@ void log_frame::UpdateUI()
// set scrollbar to max means auto-scroll // set scrollbar to max means auto-scroll
sb->setValue(isMax ? sb->maximum() : sb_pos); sb->setValue(isMax ? sb->maximum() : sb_pos);
m_log_text.clear();
};
// Check main logs
while (auto* packet = s_gui_listener.get())
{
// Confirm log level
if (packet->sev <= s_gui_listener.enabled)
{
if (m_stack_log && m_old_log_level == packet->sev && packet->msg == m_old_log_text)
{
m_log_counter++;
if (is_first_rep)
{
flush();
}
s_gui_listener.pop();
continue;
}
is_first_rep = false;
if (m_log_counter > 1)
{
// Add counter suffix if needed
flush();
}
if (m_log_text.size() > 0x1000)
{
// Try not to hold too much data at a time so the frame content will be updated frequently
flush();
}
if (!m_log_text.isEmpty())
{
if (packet->sev != m_old_log_level)
{
flush();
m_old_log_level = packet->sev;
m_log_text += font_start_tag(m_color[static_cast<int>(m_old_log_level)]);
}
else
{
m_log_text += QStringLiteral("<br/>");
}
}
else
{
m_old_log_level = packet->sev;
m_log_text += font_start_tag(m_color[static_cast<int>(m_old_log_level)]);
}
switch (packet->sev)
{
case logs::level::always: m_log_text += QStringLiteral("- "); break;
case logs::level::fatal: m_log_text += QStringLiteral("F "); break;
case logs::level::error: m_log_text += QStringLiteral("E "); break;
case logs::level::todo: m_log_text += QStringLiteral("U "); break;
case logs::level::success: m_log_text += QStringLiteral("S "); break;
case logs::level::warning: m_log_text += QStringLiteral("W "); break;
case logs::level::notice: m_log_text += QStringLiteral("! "); break;
case logs::level::trace: m_log_text += QStringLiteral("T "); break;
}
// Print UTF-8 text.
m_log_text += escaped(qstr(packet->msg));
if (m_stack_log)
{
m_log_counter = 1;
m_old_log_text = std::move(packet->msg);
}
} }
// Drop packet // Drop packet
@ -676,6 +741,9 @@ void log_frame::UpdateUI()
// Limit processing time // Limit processing time
if (steady_clock::now() >= start + 7ms) break; if (steady_clock::now() >= start + 7ms) break;
} }
is_first_rep = false;
flush();
} }
void log_frame::closeEvent(QCloseEvent *event) void log_frame::closeEvent(QCloseEvent *event)

View file

@ -49,12 +49,14 @@ private:
QList<QColor> m_color; QList<QColor> m_color;
QColor m_color_stack; QColor m_color_stack;
QPlainTextEdit* m_log = nullptr; QPlainTextEdit* m_log = nullptr;
QString m_old_log_text; std::string m_old_log_text;
QString m_old_tty_text; QString m_old_tty_text;
QString m_log_text;
ullong m_log_counter{}; ullong m_log_counter{};
ullong m_tty_counter{}; ullong m_tty_counter{};
bool m_stack_log{}; bool m_stack_log{};
bool m_stack_tty{}; bool m_stack_tty{};
logs::level m_old_log_level{};
fs::file m_tty_file; fs::file m_tty_file;
QWidget* m_tty_container = nullptr; QWidget* m_tty_container = nullptr;