Don't format log messages if we can't actually log them.

This should prevent debug messages from potentially causing
performance issues on production servers.
This commit is contained in:
Sadie Powell 2025-01-11 16:45:15 +00:00
parent e358bb781d
commit c6238d80de
2 changed files with 43 additions and 14 deletions

View File

@ -51,6 +51,12 @@ namespace Log
/** A sensitive message that we should not store lightly. */
RAWIO = 4,
/** The lowest log level supported. */
LOWEST = CRITICAL,
/** The highest log level supported. */
HIGHEST = RAWIO,
};
/** Converts a log level to a string.
@ -236,8 +242,11 @@ private:
/** Whether we are currently logging to a file. */
bool logging = false;
/** Check whether raw logging is enabled. */
void CheckRawLog();
/** The highest level that loggers will accept. */
Log::Level maxlevel = Level::HIGHEST;
/** Check for the highest log level and warn about raw logging */
void CheckLevel();
/** Writes a message to the server log.
* @param level The level to log at.
@ -246,6 +255,15 @@ private:
*/
void Write(Level level, const std::string& type, const std::string& message);
template <typename... Args>
void Write(Level level, const std::string& type, const char* format, Args&&... args)
{
if (maxlevel < level && !caching)
return; // No loggers care about this message.
Write(level, type, fmt::vformat(format, fmt::make_format_args(args...)));
}
public:
Manager();
@ -283,7 +301,7 @@ public:
template <typename... Args>
void Critical(const std::string& type, const char* format, Args&&... args)
{
Write(Level::CRITICAL, type, fmt::vformat(format, fmt::make_format_args(args...)));
Write(Level::CRITICAL, type, format, std::forward<Args>(args)...);
}
/** Writes a warning message to the server log.
@ -303,7 +321,7 @@ public:
template <typename... Args>
void Warning(const std::string& type, const char* format, Args&&... args)
{
Write(Level::WARNING, type, fmt::vformat(format, fmt::make_format_args(args...)));
Write(Level::WARNING, type, format, std::forward<Args>(args)...);
}
/** Writes a normal message to the server log.
@ -323,7 +341,7 @@ public:
template <typename... Args>
void Normal(const std::string& type, const char* format, Args&&... args)
{
Write(Level::NORMAL, type, fmt::vformat(format, fmt::make_format_args(args...)));
Write(Level::NORMAL, type, format, std::forward<Args>(args)...);
}
/** Writes a debug message to the server log.
@ -342,7 +360,7 @@ public:
template <typename... Args>
void Debug(const std::string& type, const char* format, Args&&... args)
{
Write(Level::DEBUG, type, fmt::vformat(format, fmt::make_format_args(args...)));
Write(Level::DEBUG, type, format, std::forward<Args>(args)...);
}
/** Writes a raw I/O message to the server log.
@ -362,6 +380,6 @@ public:
template <typename... Args>
void RawIO(const std::string& type, const char* format, Args&&... args)
{
Write(Level::RAWIO, type, fmt::vformat(format, fmt::make_format_args(args...)));
Write(Level::RAWIO, type, format, std::forward<Args>(args)...);
}
};

View File

@ -224,7 +224,7 @@ void Log::Manager::OpenLogs(bool requiremethods)
{
const auto* option = ServerInstance->Config->CommandLine.forceprotodebug ? "--protocoldebug" : "--debug";
Normal("LOG", "Not opening loggers because we were started with {}", option);
CheckRawLog();
CheckLevel();
return;
}
@ -232,7 +232,7 @@ void Log::Manager::OpenLogs(bool requiremethods)
if (!ServerInstance->Config->CommandLine.writelog)
{
Normal("LOG", "Not opening loggers because we were started with --nolog");
CheckRawLog();
CheckLevel();
return;
}
@ -297,7 +297,7 @@ void Log::Manager::OpenLogs(bool requiremethods)
cache.shrink_to_fit();
caching = false;
}
CheckRawLog();
CheckLevel();
}
void Log::Manager::RegisterServices()
@ -316,12 +316,20 @@ void Log::Manager::UnloadEngine(const Engine* engine)
Normal("LOG", "The {} log engine is unloading; removed {}/{} loggers.", engine->name.c_str(), logger_count - loggers.size(), logger_count);
}
void Log::Manager::CheckRawLog()
void Log::Manager::CheckLevel()
{
// There might be a logger not from the config so we need to check this outside of the creation loop.
ServerInstance->Config->RawLog = std::any_of(loggers.begin(), loggers.end(), [](const auto& logger) {
return logger.level >= Level::RAWIO;
});
auto newmaxlevel = Level::LOWEST;
for (const auto& logger : loggers)
{
if (logger.level > newmaxlevel)
newmaxlevel = logger.level;
}
std::swap(maxlevel, newmaxlevel);
ServerInstance->Config->RawLog = (newmaxlevel >= Level::RAWIO);
Debug("LOG", "Changed maximum log level from {} to {}", LevelToString(newmaxlevel), LevelToString(maxlevel));
}
void Log::Manager::Write(Level level, const std::string& type, const std::string& message)
@ -329,6 +337,9 @@ void Log::Manager::Write(Level level, const std::string& type, const std::string
if (logging)
return; // Avoid log loops.
if (maxlevel < level && !caching)
return; // No loggers care about this message.
logging = true;
time_t time = ServerInstance->Time();
for (auto& logger : loggers)