From 05ca30a6a0e8f2485da22ae0d3da9774a7c97f9b Mon Sep 17 00:00:00 2001 From: Julian Brost Date: Thu, 8 Apr 2021 13:49:53 +0200 Subject: [PATCH] Write early log messages to the Windows Event Log When Icinga 2 is started as a service, the early log messages generated until the FileLogger object is activated are lost and make it really hard to debug issues that (only) occur when Icinga 2 reloads. With this commit, these early log messages are written to the Windows Event Log. --- lib/base/logger.cpp | 18 ++++++++++++++++++ lib/base/logger.hpp | 3 +++ lib/base/windowseventloglogger.cpp | 14 +++++++++++++- lib/base/windowseventloglogger.hpp | 2 ++ lib/config/configitem.cpp | 14 ++++++++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 53698bf3c..fe5668779 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -9,6 +9,9 @@ #include "base/objectlock.hpp" #include "base/context.hpp" #include "base/scriptglobal.hpp" +#ifdef _WIN32 +#include "base/windowseventloglogger.hpp" +#endif /* _WIN32 */ #include #include @@ -29,6 +32,7 @@ REGISTER_TYPE(Logger); std::set Logger::m_Loggers; std::mutex Logger::m_Mutex; bool Logger::m_ConsoleLogEnabled = true; +std::atomic Logger::m_EarlyLoggingEnabled (true); bool Logger::m_TimestampEnabled = true; LogSeverity Logger::m_ConsoleLogSeverity = LogInformation; @@ -157,6 +161,14 @@ LogSeverity Logger::GetConsoleLogSeverity() return m_ConsoleLogSeverity; } +void Logger::DisableEarlyLogging() { + m_EarlyLoggingEnabled = false; +} + +bool Logger::IsEarlyLoggingEnabled() { + return m_EarlyLoggingEnabled; +} + void Logger::DisableTimestamp() { m_TimestampEnabled = false; @@ -242,6 +254,12 @@ Log::~Log() * then cout will not flush lines automatically. */ std::cout << std::flush; } + +#ifdef _WIN32 + if (Logger::IsEarlyLoggingEnabled() && entry.Severity >= Logger::GetConsoleLogSeverity()) { + WindowsEventLogLogger::WriteToWindowsEventLog(entry); + } +#endif /* _WIN32 */ } Log& Log::operator<<(const char *val) diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index 9a53e13cf..6d87c29b7 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -67,6 +67,8 @@ public: static void DisableConsoleLog(); static void EnableConsoleLog(); static bool IsConsoleLogEnabled(); + static void DisableEarlyLogging(); + static bool IsEarlyLoggingEnabled(); static void DisableTimestamp(); static void EnableTimestamp(); static bool IsTimestampEnabled(); @@ -84,6 +86,7 @@ private: static std::mutex m_Mutex; static std::set m_Loggers; static bool m_ConsoleLogEnabled; + static std::atomic m_EarlyLoggingEnabled; static bool m_TimestampEnabled; static LogSeverity m_ConsoleLogSeverity; }; diff --git a/lib/base/windowseventloglogger.cpp b/lib/base/windowseventloglogger.cpp index 8c9582351..cc28358f9 100644 --- a/lib/base/windowseventloglogger.cpp +++ b/lib/base/windowseventloglogger.cpp @@ -37,9 +37,21 @@ void WindowsEventLogLogger::StatsFunc(const Dictionary::Ptr& status, const Array /** * Processes a log entry and outputs it to the Windows Event Log. * + * This function implements the interface expected by the Logger base class and passes + * the log entry to WindowsEventLogLogger::WriteToWindowsEventLog(). + * * @param entry The log entry. */ -void WindowsEventLogLogger::ProcessLogEntry(const LogEntry& entry) +void WindowsEventLogLogger::ProcessLogEntry(const LogEntry& entry) { + WindowsEventLogLogger::WriteToWindowsEventLog(entry); +} + +/** + * Writes a LogEntry object to the Windows Event Log. + * + * @param entry The log entry. + */ +void WindowsEventLogLogger::WriteToWindowsEventLog(const LogEntry& entry) { if (l_EventLog != nullptr) { std::string message = Logger::SeverityToString(entry.Severity) + "/" + entry.Facility + ": " + entry.Message; diff --git a/lib/base/windowseventloglogger.hpp b/lib/base/windowseventloglogger.hpp index 7b8b03e91..cefc245c7 100644 --- a/lib/base/windowseventloglogger.hpp +++ b/lib/base/windowseventloglogger.hpp @@ -24,6 +24,8 @@ public: static void StaticInitialize(); static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); + static void WriteToWindowsEventLog(const LogEntry& entry); + protected: void ProcessLogEntry(const LogEntry& entry) override; void Flush() override; diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index da91efc58..cb241eb8c 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -675,6 +675,14 @@ bool ConfigItem::ActivateItems(const std::vector& newItems, boo return false; }); + /* Find the last logger type to be activated. */ + Type::Ptr lastLoggerType = nullptr; + for (const Type::Ptr& type : types) { + if (Logger::TypeInstance->IsAssignableFrom(type)) { + lastLoggerType = type; + } + } + for (const Type::Ptr& type : types) { for (const ConfigItem::Ptr& item : newItems) { if (!item->m_Object) @@ -695,6 +703,12 @@ bool ConfigItem::ActivateItems(const std::vector& newItems, boo object->Activate(runtimeCreated, cookie); } + + // TODO: find a better name for silent + if (!silent && type == lastLoggerType) { + /* Disable early logging configuration once the last logger type was activated. */ + Logger::DisableEarlyLogging(); + } } if (!silent)