diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 5856cba98a4..89a3c8f76e9 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -15,10 +15,12 @@ #include "base/scriptglobal.hpp" #include "base/process.hpp" #include "base/tlsutility.hpp" +#include #include #include #include #include +#include #include #include #include @@ -56,11 +58,12 @@ double Application::m_StartTime; bool Application::m_ScriptDebuggerEnabled = false; #ifdef _WIN32 -double Application::m_LastReloadFailed = 0; +Application::LastFailedReload Application::m_LastReloadFailed; +std::mutex Application::m_LastReloadFailedMutex; #else /* _WIN32 */ -std::atomic* Application::m_LastReloadFailed = ([]() -> std::atomic* { +Application::LastFailedReload* Application::m_LastReloadFailed = ([]() -> Application::LastFailedReload* { auto memory (mmap( - nullptr, sizeof(std::atomic), + nullptr, sizeof(Application::LastFailedReload), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0 )); if (memory == MAP_FAILED) { @@ -69,8 +72,11 @@ std::atomic* Application::m_LastReloadFailed = ([]() -> std::atomic*)memory); - lrf->store(0); + auto lrf ((Application::LastFailedReload*)memory); + + lrf->When.store(0); + std::fill((volatile char*)lrf->Why, (volatile char*)lrf->Why + sizeof(lrf->Why), 0); + return lrf; })(); #endif /* _WIN32 */ @@ -383,7 +389,7 @@ void Application::OnShutdown() static void ReloadProcessCallbackInternal(const ProcessResult& pr) { if (pr.ExitStatus != 0) { - Application::SetLastReloadFailed(Utility::GetTime()); + Application::SetLastReloadFailed(Utility::GetTime(), pr.Output); Log(LogCritical, "Application", "Found error in config: reloading aborted"); } #ifdef _WIN32 @@ -1188,21 +1194,30 @@ void Application::SetScriptDebuggerEnabled(bool enabled) m_ScriptDebuggerEnabled = enabled; } -double Application::GetLastReloadFailed() +std::pair Application::GetLastReloadFailed() { #ifdef _WIN32 - return m_LastReloadFailed; + std::unique_lock lock (m_LastReloadFailedMutex); + return std::pair(m_LastReloadFailed.When, m_LastReloadFailed.Why); #else /* _WIN32 */ - return m_LastReloadFailed->load(); + char reason[sizeof(m_LastReloadFailed->Why)]; + std::copy((volatile char*)m_LastReloadFailed->Why, (volatile char*)m_LastReloadFailed->Why + sizeof(m_LastReloadFailed->Why), (char*)reason); + + return std::pair(m_LastReloadFailed->When.load(), String((char*)reason)); #endif /* _WIN32 */ } -void Application::SetLastReloadFailed(double ts) +void Application::SetLastReloadFailed(double ts, const String& reason) { #ifdef _WIN32 - m_LastReloadFailed = ts; + std::unique_lock lock (m_LastReloadFailedMutex); + m_LastReloadFailed = LastFailedReload{ts, reason}; #else /* _WIN32 */ - m_LastReloadFailed->store(ts); + char buf[sizeof(m_LastReloadFailed->Why)] = {0}; + + (void)strncpy((char*)buf, reason.CStr(), sizeof(buf)); + std::copy((char*)buf, (char*)buf + sizeof(buf), (volatile char*)m_LastReloadFailed->Why); + m_LastReloadFailed->When.store(ts); #endif /* _WIN32 */ } diff --git a/lib/base/application.hpp b/lib/base/application.hpp index 3fe9a8e2400..8ea75c1f626 100644 --- a/lib/base/application.hpp +++ b/lib/base/application.hpp @@ -9,6 +9,8 @@ #include "base/configuration.hpp" #include #include +#include +#include namespace icinga { @@ -101,8 +103,8 @@ class Application : public ObjectImpl { static bool GetScriptDebuggerEnabled(); static void SetScriptDebuggerEnabled(bool enabled); - static double GetLastReloadFailed(); - static void SetLastReloadFailed(double ts); + static std::pair GetLastReloadFailed(); + static void SetLastReloadFailed(double ts, const String& reason); static void DisplayInfoMessage(std::ostream& os, bool skipVersion = false); @@ -138,10 +140,24 @@ class Application : public ObjectImpl { static double m_StartTime; static double m_MainTime; static bool m_ScriptDebuggerEnabled; + #ifdef _WIN32 - static double m_LastReloadFailed; + struct LastFailedReload + { + double When = 0; + String Why; + }; + + static LastFailedReload m_LastReloadFailed; + static std::mutex m_LastReloadFailedMutex; #else /* _WIN32 */ - static std::atomic *m_LastReloadFailed; + struct LastFailedReload + { + std::atomic When; + volatile char Why[4096]; + }; + + static LastFailedReload *m_LastReloadFailed; #endif /* _WIN32 */ #ifdef _WIN32 diff --git a/lib/cli/daemoncommand.cpp b/lib/cli/daemoncommand.cpp index 92b87e5f8b9..7c0a052020f 100644 --- a/lib/cli/daemoncommand.cpp +++ b/lib/cli/daemoncommand.cpp @@ -10,6 +10,7 @@ #include "base/atomic.hpp" #include "base/defer.hpp" #include "base/logger.hpp" +#include "base/streamlogger.hpp" #include "base/application.hpp" #include "base/timer.hpp" #include "base/utility.hpp" @@ -23,6 +24,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -233,6 +235,12 @@ int RunWorker(const std::vector& configs, bool closeConsoleLog = fa } #endif /* I2_DEBUG */ + std::ostringstream oss; + StreamLogger::Ptr sl = new StreamLogger(); + + sl->BindStream(&oss, false); + sl->Start(true); + Log(LogInformation, "cli", "Loading configuration file(s)."); { @@ -240,9 +248,18 @@ int RunWorker(const std::vector& configs, bool closeConsoleLog = fa if (!DaemonUtility::LoadConfigFiles(configs, newItems, Configuration::ObjectsPath, Configuration::VarsPath)) { Log(LogCritical, "cli", "Config validation failed. Re-run with 'icinga2 daemon -C' after fixing the config."); + + sl->Stop(true); + sl = nullptr; + Application::SetLastReloadFailed(Utility::GetTime(), oss.str()); + return EXIT_FAILURE; } + sl->Stop(true); + sl = nullptr; + oss = decltype(oss)(); + #ifndef _WIN32 Log(LogNotice, "cli") << "Notifying umbrella process (PID " << l_UmbrellaPid << ") about the config loading success"; @@ -477,6 +494,7 @@ static pid_t StartUnixWorker(const std::vector& configs, bool close } (void)sigprocmask(SIG_UNBLOCK, &l_UnixWorkerSignals, nullptr); + Application::SetLastReloadFailed(Utility::GetTime(), "fork() failed"); return -1; case 0: @@ -511,11 +529,13 @@ static pid_t StartUnixWorker(const std::vector& configs, bool close } catch (const std::exception& ex) { Log(LogCritical, "cli") << "Failed to re-initialize thread pool after forking (child): " << DiagnosticInformation(ex); + Application::SetLastReloadFailed(Utility::GetTime(), "Failed to re-initialize thread pool after forking (child)"); _exit(EXIT_FAILURE); } _exit(RunWorker(configs, closeConsoleLog, stderrFile)); } catch (...) { + Application::SetLastReloadFailed(Utility::GetTime(), ""); _exit(EXIT_FAILURE); } @@ -767,12 +787,11 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector