1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "perfdata/perfdatawriter.hpp"
4 #include "perfdata/perfdatawriter-ti.cpp"
5 #include "icinga/service.hpp"
6 #include "icinga/macroprocessor.hpp"
7 #include "icinga/icingaapplication.hpp"
8 #include "base/configtype.hpp"
9 #include "base/objectlock.hpp"
10 #include "base/logger.hpp"
11 #include "base/convert.hpp"
12 #include "base/utility.hpp"
13 #include "base/context.hpp"
14 #include "base/exception.hpp"
15 #include "base/application.hpp"
16 #include "base/statsfunction.hpp"
18 using namespace icinga;
20 REGISTER_TYPE(PerfdataWriter);
22 REGISTER_STATSFUNCTION(PerfdataWriter, &PerfdataWriter::StatsFunc);
24 void PerfdataWriter::OnConfigLoaded()
26 ObjectImpl<PerfdataWriter>::OnConfigLoaded();
29 Log(LogDebug, "PerfdataWriter")
30 << "HA functionality disabled. Won't pause connection: " << GetName();
32 SetHAMode(HARunEverywhere);
38 void PerfdataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
42 for (const PerfdataWriter::Ptr& perfdatawriter : ConfigType::GetObjectsByType<PerfdataWriter>()) {
43 nodes.emplace_back(perfdatawriter->GetName(), 1); //add more stats
46 status->Set("perfdatawriter", new Dictionary(std::move(nodes)));
49 void PerfdataWriter::Resume()
51 ObjectImpl<PerfdataWriter>::Resume();
53 Log(LogInformation, "PerfdataWriter")
54 << "'" << GetName() << "' resumed.";
56 Checkable::OnNewCheckResult.connect(std::bind(&PerfdataWriter::CheckResultHandler, this, _1, _2));
58 m_RotationTimer = new Timer();
59 m_RotationTimer->OnTimerExpired.connect(std::bind(&PerfdataWriter::RotationTimerHandler, this));
60 m_RotationTimer->SetInterval(GetRotationInterval());
61 m_RotationTimer->Start();
63 RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath());
64 RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath());
67 void PerfdataWriter::Pause()
69 m_RotationTimer.reset();
72 //m_HostOutputFile << "\n# Pause the feature" << "\n\n";
73 //m_ServiceOutputFile << "\n# Pause the feature" << "\n\n";
76 /* Force a rotation closing the file stream. */
79 Log(LogInformation, "PerfdataWriter")
80 << "'" << GetName() << "' paused.";
82 ObjectImpl<PerfdataWriter>::Pause();
85 Value PerfdataWriter::EscapeMacroMetric(const Value& value)
87 if (value.IsObjectType<Array>())
88 return Utility::Join(value, ';');
93 void PerfdataWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr)
98 CONTEXT("Writing performance data for object '" + checkable->GetName() + "'");
100 if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata())
103 Service::Ptr service = dynamic_pointer_cast<Service>(checkable);
107 host = service->GetHost();
109 host = static_pointer_cast<Host>(checkable);
111 MacroProcessor::ResolverList resolvers;
113 resolvers.emplace_back("service", service);
114 resolvers.emplace_back("host", host);
115 resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
118 String line = MacroProcessor::ResolveMacros(GetServiceFormatTemplate(), resolvers, cr, nullptr, &PerfdataWriter::EscapeMacroMetric);
121 boost::mutex::scoped_lock lock(m_StreamMutex);
123 if (!m_ServiceOutputFile.good())
126 m_ServiceOutputFile << line << "\n";
129 String line = MacroProcessor::ResolveMacros(GetHostFormatTemplate(), resolvers, cr, nullptr, &PerfdataWriter::EscapeMacroMetric);
132 boost::mutex::scoped_lock lock(m_StreamMutex);
134 if (!m_HostOutputFile.good())
137 m_HostOutputFile << line << "\n";
142 void PerfdataWriter::RotateFile(std::ofstream& output, const String& temp_path, const String& perfdata_path)
144 Log(LogDebug, "PerfdataWriter")
145 << "Rotating perfdata files.";
147 boost::mutex::scoped_lock lock(m_StreamMutex);
152 if (Utility::PathExists(temp_path)) {
153 String finalFile = perfdata_path + "." + Convert::ToString((long)Utility::GetTime());
155 Log(LogDebug, "PerfdataWriter")
156 << "Closed output file and renaming into '" << finalFile << "'.";
158 Utility::RenameFile(temp_path, finalFile);
162 output.open(temp_path.CStr());
164 if (!output.good()) {
165 Log(LogWarning, "PerfdataWriter")
166 << "Could not open perfdata file '" << temp_path << "' for writing. Perfdata will be lost.";
170 void PerfdataWriter::RotationTimerHandler()
178 void PerfdataWriter::RotateAllFiles()
180 RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath());
181 RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath());
184 void PerfdataWriter::ValidateHostFormatTemplate(const Lazy<String>& lvalue, const ValidationUtils& utils)
186 ObjectImpl<PerfdataWriter>::ValidateHostFormatTemplate(lvalue, utils);
188 if (!MacroProcessor::ValidateMacroString(lvalue()))
189 BOOST_THROW_EXCEPTION(ValidationError(this, { "host_format_template" }, "Closing $ not found in macro format string '" + lvalue() + "'."));
192 void PerfdataWriter::ValidateServiceFormatTemplate(const Lazy<String>& lvalue, const ValidationUtils& utils)
194 ObjectImpl<PerfdataWriter>::ValidateServiceFormatTemplate(lvalue, utils);
196 if (!MacroProcessor::ValidateMacroString(lvalue()))
197 BOOST_THROW_EXCEPTION(ValidationError(this, { "service_format_template" }, "Closing $ not found in macro format string '" + lvalue() + "'."));