diff options
Diffstat (limited to 'lib/perfdata/perfdatawriter.cpp')
-rw-r--r-- | lib/perfdata/perfdatawriter.cpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/lib/perfdata/perfdatawriter.cpp b/lib/perfdata/perfdatawriter.cpp new file mode 100644 index 0000000..849f19e --- /dev/null +++ b/lib/perfdata/perfdatawriter.cpp @@ -0,0 +1,201 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "perfdata/perfdatawriter.hpp" +#include "perfdata/perfdatawriter-ti.cpp" +#include "icinga/service.hpp" +#include "icinga/macroprocessor.hpp" +#include "icinga/icingaapplication.hpp" +#include "base/configtype.hpp" +#include "base/objectlock.hpp" +#include "base/logger.hpp" +#include "base/convert.hpp" +#include "base/utility.hpp" +#include "base/context.hpp" +#include "base/exception.hpp" +#include "base/application.hpp" +#include "base/statsfunction.hpp" + +using namespace icinga; + +REGISTER_TYPE(PerfdataWriter); + +REGISTER_STATSFUNCTION(PerfdataWriter, &PerfdataWriter::StatsFunc); + +void PerfdataWriter::OnConfigLoaded() +{ + ObjectImpl<PerfdataWriter>::OnConfigLoaded(); + + if (!GetEnableHa()) { + Log(LogDebug, "PerfdataWriter") + << "HA functionality disabled. Won't pause connection: " << GetName(); + + SetHAMode(HARunEverywhere); + } else { + SetHAMode(HARunOnce); + } +} + +void PerfdataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&) +{ + DictionaryData nodes; + + for (const PerfdataWriter::Ptr& perfdatawriter : ConfigType::GetObjectsByType<PerfdataWriter>()) { + nodes.emplace_back(perfdatawriter->GetName(), 1); //add more stats + } + + status->Set("perfdatawriter", new Dictionary(std::move(nodes))); +} + +void PerfdataWriter::Resume() +{ + ObjectImpl<PerfdataWriter>::Resume(); + + Log(LogInformation, "PerfdataWriter") + << "'" << GetName() << "' resumed."; + + m_HandleCheckResults = Checkable::OnNewCheckResult.connect([this](const Checkable::Ptr& checkable, + const CheckResult::Ptr& cr, const MessageOrigin::Ptr&) { + CheckResultHandler(checkable, cr); + }); + + m_RotationTimer = Timer::Create(); + m_RotationTimer->OnTimerExpired.connect([this](const Timer * const&) { RotationTimerHandler(); }); + m_RotationTimer->SetInterval(GetRotationInterval()); + m_RotationTimer->Start(); + + RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath()); + RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath()); +} + +void PerfdataWriter::Pause() +{ + m_HandleCheckResults.disconnect(); + m_RotationTimer->Stop(true); + +#ifdef I2_DEBUG + //m_HostOutputFile << "\n# Pause the feature" << "\n\n"; + //m_ServiceOutputFile << "\n# Pause the feature" << "\n\n"; +#endif /* I2_DEBUG */ + + /* Force a rotation closing the file stream. */ + RotateAllFiles(); + + Log(LogInformation, "PerfdataWriter") + << "'" << GetName() << "' paused."; + + ObjectImpl<PerfdataWriter>::Pause(); +} + +Value PerfdataWriter::EscapeMacroMetric(const Value& value) +{ + if (value.IsObjectType<Array>()) + return Utility::Join(value, ';'); + else + return value; +} + +void PerfdataWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) +{ + if (IsPaused()) + return; + + CONTEXT("Writing performance data for object '" << checkable->GetName() << "'"); + + if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata()) + return; + + Service::Ptr service = dynamic_pointer_cast<Service>(checkable); + Host::Ptr host; + + if (service) + host = service->GetHost(); + else + host = static_pointer_cast<Host>(checkable); + + MacroProcessor::ResolverList resolvers; + if (service) + resolvers.emplace_back("service", service); + resolvers.emplace_back("host", host); + + if (service) { + String line = MacroProcessor::ResolveMacros(GetServiceFormatTemplate(), resolvers, cr, nullptr, &PerfdataWriter::EscapeMacroMetric); + + { + std::unique_lock<std::mutex> lock(m_StreamMutex); + + if (!m_ServiceOutputFile.good()) + return; + + m_ServiceOutputFile << line << "\n"; + } + } else { + String line = MacroProcessor::ResolveMacros(GetHostFormatTemplate(), resolvers, cr, nullptr, &PerfdataWriter::EscapeMacroMetric); + + { + std::unique_lock<std::mutex> lock(m_StreamMutex); + + if (!m_HostOutputFile.good()) + return; + + m_HostOutputFile << line << "\n"; + } + } +} + +void PerfdataWriter::RotateFile(std::ofstream& output, const String& temp_path, const String& perfdata_path) +{ + Log(LogDebug, "PerfdataWriter") + << "Rotating perfdata files."; + + std::unique_lock<std::mutex> lock(m_StreamMutex); + + if (output.good()) { + output.close(); + + if (Utility::PathExists(temp_path)) { + String finalFile = perfdata_path + "." + Convert::ToString((long)Utility::GetTime()); + + Log(LogDebug, "PerfdataWriter") + << "Closed output file and renaming into '" << finalFile << "'."; + + Utility::RenameFile(temp_path, finalFile); + } + } + + output.open(temp_path.CStr()); + + if (!output.good()) { + Log(LogWarning, "PerfdataWriter") + << "Could not open perfdata file '" << temp_path << "' for writing. Perfdata will be lost."; + } +} + +void PerfdataWriter::RotationTimerHandler() +{ + if (IsPaused()) + return; + + RotateAllFiles(); +} + +void PerfdataWriter::RotateAllFiles() +{ + RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath()); + RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath()); +} + +void PerfdataWriter::ValidateHostFormatTemplate(const Lazy<String>& lvalue, const ValidationUtils& utils) +{ + ObjectImpl<PerfdataWriter>::ValidateHostFormatTemplate(lvalue, utils); + + if (!MacroProcessor::ValidateMacroString(lvalue())) + BOOST_THROW_EXCEPTION(ValidationError(this, { "host_format_template" }, "Closing $ not found in macro format string '" + lvalue() + "'.")); +} + +void PerfdataWriter::ValidateServiceFormatTemplate(const Lazy<String>& lvalue, const ValidationUtils& utils) +{ + ObjectImpl<PerfdataWriter>::ValidateServiceFormatTemplate(lvalue, utils); + + if (!MacroProcessor::ValidateMacroString(lvalue())) + BOOST_THROW_EXCEPTION(ValidationError(this, { "service_format_template" }, "Closing $ not found in macro format string '" + lvalue() + "'.")); +} |