From 6da58a6871d1b53c2cc38de04acd19fb7f84fc64 Mon Sep 17 00:00:00 2001
From: Ivan Savenko <saven.ivan@gmail.com>
Date: Mon, 23 Dec 2024 21:24:00 +0000
Subject: [PATCH] Fixes excessive logging causing RMG slowdown

- Do not apply formatting on log entries that will be discarded due to
high log level
- Do not log incorrect access to visitablePos due to its numerous use by
RMG
---
 include/vstd/CLoggerBase.h          | 22 +++++++++++++---------
 lib/logging/CLogger.cpp             | 15 +++++++++------
 lib/logging/CLogger.h               |  4 ++--
 lib/mapObjects/CGObjectInstance.cpp |  8 ++++----
 4 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/include/vstd/CLoggerBase.h b/include/vstd/CLoggerBase.h
index a1cf6edba..4408a4cd8 100644
--- a/include/vstd/CLoggerBase.h
+++ b/include/vstd/CLoggerBase.h
@@ -58,6 +58,7 @@ public:
 
 	virtual void log(ELogLevel::ELogLevel level, const std::string & message) const = 0;
 	virtual void log(ELogLevel::ELogLevel level, const boost::format & fmt) const = 0;
+	virtual ELogLevel::ELogLevel getEffectiveLevel() const = 0;
 
 	/// Returns true if a debug/trace log message will be logged, false if not.
 	/// Useful if performance is important and concatenating the log message is a expensive task.
@@ -67,16 +68,19 @@ public:
 	template<typename T, typename ... Args>
 	void log(ELogLevel::ELogLevel level, const std::string & format, T t, Args ... args) const
 	{
-		try
+		if (getEffectiveLevel() <= level)
 		{
-			boost::format fmt(format);
-			makeFormat(fmt, t, args...);
-			log(level, fmt);
-		}
-		catch(...)
-		{
-			log(ELogLevel::ERROR, "Log formatting failed, format was:");
-			log(ELogLevel::ERROR, format);
+			try
+			{
+				boost::format fmt(format);
+				makeFormat(fmt, t, args...);
+				log(level, fmt);
+			}
+			catch(...)
+			{
+				log(ELogLevel::ERROR, "Log formatting failed, format was:");
+				log(ELogLevel::ERROR, format);
+			}
 		}
 	}
 
diff --git a/lib/logging/CLogger.cpp b/lib/logging/CLogger.cpp
index e33c6425e..3968068b3 100644
--- a/lib/logging/CLogger.cpp
+++ b/lib/logging/CLogger.cpp
@@ -146,13 +146,16 @@ void CLogger::log(ELogLevel::ELogLevel level, const std::string & message) const
 
 void CLogger::log(ELogLevel::ELogLevel level, const boost::format & fmt) const
 {
-	try
+	if (getEffectiveLevel() <= level)
 	{
-		log(level, fmt.str());
-	}
-	catch(...)
-	{
-		log(ELogLevel::ERROR, "Invalid log format!");
+		try
+		{
+			log(level, fmt.str());
+		}
+		catch (...)
+		{
+			log(ELogLevel::ERROR, "Invalid log format!");
+		}
 	}
 }
 
diff --git a/lib/logging/CLogger.h b/lib/logging/CLogger.h
index 22c3035f1..654f5bf95 100644
--- a/lib/logging/CLogger.h
+++ b/lib/logging/CLogger.h
@@ -46,7 +46,7 @@ private:
 
 /// The logger is used to log messages to certain targets of a specific domain/name.
 /// It is thread-safe and can be used concurrently by several threads.
-class DLL_LINKAGE CLogger: public vstd::CLoggerBase
+class DLL_LINKAGE CLogger final: public vstd::CLoggerBase
 {
 public:
 	ELogLevel::ELogLevel getLevel() const;
@@ -70,7 +70,7 @@ public:
 
 private:
 	explicit CLogger(const CLoggerDomain & domain);
-	inline ELogLevel::ELogLevel getEffectiveLevel() const; /// Returns the log level applied on this logger whether directly or indirectly.
+	inline ELogLevel::ELogLevel getEffectiveLevel() const override; /// Returns the log level applied on this logger whether directly or indirectly.
 	inline void callTargets(const LogRecord & record) const;
 
 	CLoggerDomain domain;
diff --git a/lib/mapObjects/CGObjectInstance.cpp b/lib/mapObjects/CGObjectInstance.cpp
index 8511a9875..cfaab7462 100644
--- a/lib/mapObjects/CGObjectInstance.cpp
+++ b/lib/mapObjects/CGObjectInstance.cpp
@@ -217,8 +217,8 @@ int CGObjectInstance::getSightRadius() const
 
 int3 CGObjectInstance::getVisitableOffset() const
 {
-	if (!isVisitable())
-		logGlobal->debug("Attempt to access visitable offset on a non-visitable object!");
+//	if (!isVisitable())
+//		logGlobal->debug("Attempt to access visitable offset on a non-visitable object!");
 	return appearance->getVisitableOffset();
 }
 
@@ -317,8 +317,8 @@ void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
 
 int3 CGObjectInstance::visitablePos() const
 {
-	if (!isVisitable())
-		logGlobal->debug("Attempt to access visitable position on a non-visitable object!");
+//	if (!isVisitable())
+//		logGlobal->debug("Attempt to access visitable position on a non-visitable object!");
 
 	return pos - getVisitableOffset();
 }