]> granicus.if.org Git - icinga2/blob - lib/perfdata/perfdatawriter.cpp
Merge pull request #7527 from Icinga/bugfix/checkable-command-endpoint-zone
[icinga2] / lib / perfdata / perfdatawriter.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
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"
17
18 using namespace icinga;
19
20 REGISTER_TYPE(PerfdataWriter);
21
22 REGISTER_STATSFUNCTION(PerfdataWriter, &PerfdataWriter::StatsFunc);
23
24 void PerfdataWriter::OnConfigLoaded()
25 {
26         ObjectImpl<PerfdataWriter>::OnConfigLoaded();
27
28         if (!GetEnableHa()) {
29                 Log(LogDebug, "PerfdataWriter")
30                         << "HA functionality disabled. Won't pause connection: " << GetName();
31
32                 SetHAMode(HARunEverywhere);
33         } else {
34                 SetHAMode(HARunOnce);
35         }
36 }
37
38 void PerfdataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
39 {
40         DictionaryData nodes;
41
42         for (const PerfdataWriter::Ptr& perfdatawriter : ConfigType::GetObjectsByType<PerfdataWriter>()) {
43                 nodes.emplace_back(perfdatawriter->GetName(), 1); //add more stats
44         }
45
46         status->Set("perfdatawriter", new Dictionary(std::move(nodes)));
47 }
48
49 void PerfdataWriter::Resume()
50 {
51         ObjectImpl<PerfdataWriter>::Resume();
52
53         Log(LogInformation, "PerfdataWriter")
54                 << "'" << GetName() << "' resumed.";
55
56         Checkable::OnNewCheckResult.connect(std::bind(&PerfdataWriter::CheckResultHandler, this, _1, _2));
57
58         m_RotationTimer = new Timer();
59         m_RotationTimer->OnTimerExpired.connect(std::bind(&PerfdataWriter::RotationTimerHandler, this));
60         m_RotationTimer->SetInterval(GetRotationInterval());
61         m_RotationTimer->Start();
62
63         RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath());
64         RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath());
65 }
66
67 void PerfdataWriter::Pause()
68 {
69         m_RotationTimer.reset();
70
71 #ifdef I2_DEBUG
72         //m_HostOutputFile << "\n# Pause the feature" << "\n\n";
73         //m_ServiceOutputFile << "\n# Pause the feature" << "\n\n";
74 #endif /* I2_DEBUG */
75
76         /* Force a rotation closing the file stream. */
77         RotateAllFiles();
78
79         Log(LogInformation, "PerfdataWriter")
80                 << "'" << GetName() << "' paused.";
81
82         ObjectImpl<PerfdataWriter>::Pause();
83 }
84
85 Value PerfdataWriter::EscapeMacroMetric(const Value& value)
86 {
87         if (value.IsObjectType<Array>())
88                 return Utility::Join(value, ';');
89         else
90                 return value;
91 }
92
93 void PerfdataWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr)
94 {
95         if (IsPaused())
96                 return;
97
98         CONTEXT("Writing performance data for object '" + checkable->GetName() + "'");
99
100         if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata())
101                 return;
102
103         Service::Ptr service = dynamic_pointer_cast<Service>(checkable);
104         Host::Ptr host;
105
106         if (service)
107                 host = service->GetHost();
108         else
109                 host = static_pointer_cast<Host>(checkable);
110
111         MacroProcessor::ResolverList resolvers;
112         if (service)
113                 resolvers.emplace_back("service", service);
114         resolvers.emplace_back("host", host);
115         resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
116
117         if (service) {
118                 String line = MacroProcessor::ResolveMacros(GetServiceFormatTemplate(), resolvers, cr, nullptr, &PerfdataWriter::EscapeMacroMetric);
119
120                 {
121                         boost::mutex::scoped_lock lock(m_StreamMutex);
122
123                         if (!m_ServiceOutputFile.good())
124                                 return;
125
126                         m_ServiceOutputFile << line << "\n";
127                 }
128         } else {
129                 String line = MacroProcessor::ResolveMacros(GetHostFormatTemplate(), resolvers, cr, nullptr, &PerfdataWriter::EscapeMacroMetric);
130
131                 {
132                         boost::mutex::scoped_lock lock(m_StreamMutex);
133
134                         if (!m_HostOutputFile.good())
135                                 return;
136
137                         m_HostOutputFile << line << "\n";
138                 }
139         }
140 }
141
142 void PerfdataWriter::RotateFile(std::ofstream& output, const String& temp_path, const String& perfdata_path)
143 {
144         Log(LogDebug, "PerfdataWriter")
145                 << "Rotating perfdata files.";
146
147         boost::mutex::scoped_lock lock(m_StreamMutex);
148
149         if (output.good()) {
150                 output.close();
151
152                 if (Utility::PathExists(temp_path)) {
153                         String finalFile = perfdata_path + "." + Convert::ToString((long)Utility::GetTime());
154
155                         Log(LogDebug, "PerfdataWriter")
156                                 << "Closed output file and renaming into '" << finalFile << "'.";
157
158                         Utility::RenameFile(temp_path, finalFile);
159                 }
160         }
161
162         output.open(temp_path.CStr());
163
164         if (!output.good()) {
165                 Log(LogWarning, "PerfdataWriter")
166                         << "Could not open perfdata file '" << temp_path << "' for writing. Perfdata will be lost.";
167         }
168 }
169
170 void PerfdataWriter::RotationTimerHandler()
171 {
172         if (IsPaused())
173                 return;
174
175         RotateAllFiles();
176 }
177
178 void PerfdataWriter::RotateAllFiles()
179 {
180         RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath());
181         RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath());
182 }
183
184 void PerfdataWriter::ValidateHostFormatTemplate(const Lazy<String>& lvalue, const ValidationUtils& utils)
185 {
186         ObjectImpl<PerfdataWriter>::ValidateHostFormatTemplate(lvalue, utils);
187
188         if (!MacroProcessor::ValidateMacroString(lvalue()))
189                 BOOST_THROW_EXCEPTION(ValidationError(this, { "host_format_template" }, "Closing $ not found in macro format string '" + lvalue() + "'."));
190 }
191
192 void PerfdataWriter::ValidateServiceFormatTemplate(const Lazy<String>& lvalue, const ValidationUtils& utils)
193 {
194         ObjectImpl<PerfdataWriter>::ValidateServiceFormatTemplate(lvalue, utils);
195
196         if (!MacroProcessor::ValidateMacroString(lvalue()))
197                 BOOST_THROW_EXCEPTION(ValidationError(this, { "service_format_template" }, "Closing $ not found in macro format string '" + lvalue() + "'."));
198 }