diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 737e1d57f..e8d55bb96 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -147,6 +147,15 @@ void LogMessage(Class log_class, Level log_level, const char* filename, unsigned Entry entry = CreateEntry(log_class, log_level, filename, line_nr, function, format, args); va_end(args); + static Entry prev_entry{}; + if (entry == prev_entry) { + prev_entry.count++; + prev_entry.timestamp = entry.timestamp; + return; + } + if (prev_entry.count != 0) + PrintColoredMessage(prev_entry); PrintColoredMessage(entry); + prev_entry = std::move(entry); } -} +} // namespace Log diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index c4fe2acbf..9a90d1608 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h @@ -7,7 +7,6 @@ #include #include #include -#include #include "common/logging/log.h" namespace Log { @@ -24,6 +23,7 @@ struct Entry { Level log_level; std::string location; std::string message; + u32 count{0}; Entry() = default; Entry(Entry&& o) = default; @@ -31,6 +31,11 @@ struct Entry { Entry& operator=(Entry&& o) = default; }; +inline bool operator==(const Entry& lhs, const Entry& rhs) { + return (lhs.log_class == rhs.log_class) && (lhs.log_level == rhs.log_level) && + (lhs.location == rhs.location) && (lhs.message == rhs.message); +} + /** * Returns the name of the passed log class as a C-string. Subclasses are separated by periods * instead of underscores as in the enumeration. @@ -47,4 +52,4 @@ Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsign const char* function, const char* format, va_list args); void SetFilter(Filter* filter); -} +} // namespace Log diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp index 9d423766f..4196d6518 100644 --- a/src/common/logging/text_formatter.cpp +++ b/src/common/logging/text_formatter.cpp @@ -49,8 +49,15 @@ void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) { const char* class_name = GetLogClassName(entry.log_class); const char* level_name = GetLevelName(entry.log_level); - snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional, - class_name, level_name, TrimSourcePath(entry.location.c_str()), entry.message.c_str()); + if (entry.count < 2) { + snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional, + class_name, level_name, TrimSourcePath(entry.location.c_str()), + entry.message.c_str()); + } else { + snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s (repeats %d times)", time_seconds, + time_fractional, class_name, level_name, TrimSourcePath(entry.location.c_str()), + entry.message.c_str(), entry.count); + } } void PrintMessage(const Entry& entry) {