blob: cc981f18474bc8a8508142bdb433474de8297fad [file] [log] [blame]
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02001#include "report.hpp"
2
3#include "report_manager.hpp"
Krzysztof Grobelny51497a02021-11-09 14:56:22 +01004#include "utils/contains.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01005#include "utils/transform.hpp"
6
7#include <phosphor-logging/log.hpp>
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +02008#include <sdbusplus/vtable.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02009
Szymon Dompke3eb56862021-09-20 15:32:04 +020010#include <limits>
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020011#include <numeric>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020012
13Report::Report(boost::asio::io_context& ioc,
14 const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010015 const std::string& reportName,
Szymon Dompke3eb56862021-09-20 15:32:04 +020016 const ReportingType reportingTypeIn,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010017 std::vector<ReportAction> reportActionsIn,
Szymon Dompke3eb56862021-09-20 15:32:04 +020018 const Milliseconds intervalIn, const uint64_t appendLimitIn,
19 const ReportUpdates reportUpdatesIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020020 interfaces::ReportManager& reportManager,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010021 interfaces::JsonStorage& reportStorageIn,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020022 std::vector<std::shared_ptr<interfaces::Metric>> metricsIn,
23 const bool enabledIn) :
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020024 name(reportName),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010025 path(reportDir + name), reportingType(reportingTypeIn),
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010026 interval(intervalIn), reportActions(std::move(reportActionsIn)),
Szymon Dompke3eb56862021-09-20 15:32:04 +020027 sensorCount(getSensorCount(metricsIn)),
28 appendLimit(deduceAppendLimit(appendLimitIn)),
29 reportUpdates(reportUpdatesIn),
30 readingsBuffer(deduceBufferSize(reportUpdates, reportingType)),
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000031 objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010032 fileName(std::to_string(std::hash<std::string>{}(name))),
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020033 reportStorage(reportStorageIn), enabled(enabledIn)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020034{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000035 readingParameters =
36 toReadingParameters(utils::transform(metrics, [](const auto& metric) {
37 return metric->dumpConfiguration();
38 }));
39
40 readingParametersPastVersion =
41 utils::transform(readingParameters, [](const auto& item) {
42 return ReadingParametersPastVersion::value_type(
43 std::get<0>(item).front(), std::get<1>(item), std::get<2>(item),
44 std::get<3>(item));
45 });
46
Wludzik, Jozefe2362792020-10-27 17:23:55 +010047 deleteIface = objServer->add_unique_interface(
48 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
49 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
50 if (persistency)
51 {
52 reportStorage.remove(fileName);
53 }
54 boost::asio::post(ioc, [this, &reportManager] {
55 reportManager.removeReport(this);
56 });
57 });
58 });
59
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000060 persistency = storeConfiguration();
61 reportIface = makeReportInterface();
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020062
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010063 if (reportingType == ReportingType::periodic)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020064 {
65 scheduleTimer(interval);
66 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000067
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020068 if (enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000069 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020070 for (auto& metric : this->metrics)
71 {
72 metric->initialize();
73 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000074 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020075}
76
Szymon Dompke3eb56862021-09-20 15:32:04 +020077uint64_t Report::getSensorCount(
78 std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
79{
80 uint64_t sensorCount = 0;
81 for (auto& metric : metrics)
82 {
83 sensorCount += metric->sensorCount();
84 }
85 return sensorCount;
86}
87
88uint64_t Report::deduceAppendLimit(const uint64_t appendLimitIn) const
89{
90 if (appendLimitIn == std::numeric_limits<uint64_t>::max())
91 {
92 return sensorCount;
93 }
94 else
95 {
96 return appendLimitIn;
97 }
98}
99
100uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
101 const ReportingType reportingTypeIn) const
102{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100103 if (reportUpdatesIn == ReportUpdates::overwrite ||
104 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200105 {
106 return sensorCount;
107 }
108 else
109 {
110 return appendLimit;
111 }
112}
113
114void Report::setReportUpdates(const ReportUpdates newReportUpdates)
115{
116 if (reportUpdates != newReportUpdates)
117 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100118 if (reportingType != ReportingType::onRequest &&
119 (reportUpdates == ReportUpdates::overwrite ||
120 newReportUpdates == ReportUpdates::overwrite))
Szymon Dompke3eb56862021-09-20 15:32:04 +0200121 {
122 readingsBuffer.clearAndResize(
123 deduceBufferSize(newReportUpdates, reportingType));
124 }
125 reportUpdates = newReportUpdates;
126 }
127}
128
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000129std::unique_ptr<sdbusplus::asio::dbus_interface> Report::makeReportInterface()
130{
131 auto dbusIface = objServer->add_unique_interface(path, reportIfaceName);
132 dbusIface->register_property_rw(
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200133 "Enabled", enabled, sdbusplus::vtable::property_::emits_change,
134 [this](bool newVal, const auto&) {
135 if (newVal != enabled)
136 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100137 if (true == newVal && ReportingType::periodic == reportingType)
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200138 {
139 scheduleTimer(interval);
140 }
141 if (newVal)
142 {
143 for (auto& metric : metrics)
144 {
145 metric->initialize();
146 }
147 }
148 else
149 {
150 for (auto& metric : metrics)
151 {
152 metric->deinitialize();
153 }
154 }
155
156 enabled = newVal;
157 persistency = storeConfiguration();
158 }
159 return true;
160 },
161 [this](const auto&) { return enabled; });
162 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000163 "Interval", interval.count(),
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000164 sdbusplus::vtable::property_::emits_change,
165 [this](uint64_t newVal, auto&) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200166 if (Milliseconds newValT{newVal};
167 newValT >= ReportManager::minInterval)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000168 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200169 if (newValT != interval)
170 {
171 interval = newValT;
172 persistency = storeConfiguration();
173 }
174 return true;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000175 }
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200176 return false;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000177 },
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000178 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000179 dbusIface->register_property_rw(
180 "Persistency", persistency, sdbusplus::vtable::property_::emits_change,
181 [this](bool newVal, const auto&) {
182 if (newVal == persistency)
183 {
184 return true;
185 }
186 if (newVal)
187 {
188 persistency = storeConfiguration();
189 }
190 else
191 {
192 reportStorage.remove(fileName);
193 persistency = false;
194 }
195 return true;
196 },
197 [this](const auto&) { return persistency; });
198
199 auto readingsFlag = sdbusplus::vtable::property_::none;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100200 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000201 {
202 readingsFlag = sdbusplus::vtable::property_::emits_change;
203 }
204 dbusIface->register_property_r("Readings", readings, readingsFlag,
205 [this](const auto&) { return readings; });
206 dbusIface->register_property_r(
Szymon Dompke3eb56862021-09-20 15:32:04 +0200207 "ReportingType", std::string(), sdbusplus::vtable::property_::const_,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100208 [this](const auto&) { return utils::enumToString(reportingType); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000209 dbusIface->register_property_r(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000210 "ReadingParameters", readingParametersPastVersion,
211 sdbusplus::vtable::property_::const_,
212 [this](const auto&) { return readingParametersPastVersion; });
213 dbusIface->register_property_r(
214 "ReadingParametersFutureVersion", readingParameters,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000215 sdbusplus::vtable::property_::const_,
216 [this](const auto&) { return readingParameters; });
217 dbusIface->register_property_r(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100218 "EmitsReadingsUpdate", bool{}, sdbusplus::vtable::property_::const_,
219 [this](const auto&) {
220 return utils::contains(reportActions,
221 ReportAction::emitsReadingsUpdate);
222 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000223 dbusIface->register_property_r(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100224 "LogToMetricReportsCollection", bool{},
225 sdbusplus::vtable::property_::const_, [this](const auto&) {
226 return utils::contains(reportActions,
227 ReportAction::logToMetricReportsCollection);
228 });
229 dbusIface->register_property_r(
230 "ReportActions", std::vector<std::string>{},
231 sdbusplus::vtable::property_::const_, [this](const auto&) {
232 return utils::transform(reportActions, [](const auto reportAction) {
233 return utils::enumToString(reportAction);
234 });
235 });
Szymon Dompke3eb56862021-09-20 15:32:04 +0200236 dbusIface->register_property_r("AppendLimit", appendLimit,
237 sdbusplus::vtable::property_::emits_change,
238 [this](const auto&) { return appendLimit; });
239 dbusIface->register_property_rw(
240 "ReportUpdates", std::string(),
241 sdbusplus::vtable::property_::emits_change,
242 [this](auto newVal, auto& oldVal) {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100243 ReportManager::verifyReportUpdates(utils::toReportUpdates(newVal));
244 setReportUpdates(utils::toReportUpdates(newVal));
Szymon Dompke3eb56862021-09-20 15:32:04 +0200245 oldVal = newVal;
246 return true;
247 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100248 [this](const auto&) { return utils::enumToString(reportUpdates); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000249 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100250 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000251 {
252 updateReadings();
253 }
254 });
255 constexpr bool skipPropertiesChangedSignal = true;
256 dbusIface->initialize(skipPropertiesChangedSignal);
257 return dbusIface;
258}
259
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200260void Report::timerProc(boost::system::error_code ec, Report& self)
261{
262 if (ec)
263 {
264 return;
265 }
266
267 self.updateReadings();
268 self.scheduleTimer(self.interval);
269}
270
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000271void Report::scheduleTimer(Milliseconds timerInterval)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200272{
273 timer.expires_after(timerInterval);
274 timer.async_wait(
275 [this](boost::system::error_code ec) { timerProc(ec, *this); });
276}
277
278void Report::updateReadings()
279{
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200280 if (!enabled)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000281 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200282 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000283 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200284
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100285 if (reportUpdates == ReportUpdates::overwrite ||
286 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200287 {
288 readingsBuffer.clear();
289 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000290
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200291 for (const auto& metric : metrics)
292 {
Szymon Dompke3eb56862021-09-20 15:32:04 +0200293 for (const auto& [id, metadata, value, timestamp] :
294 metric->getReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200295 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100296 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200297 readingsBuffer.isFull())
298 {
299 enabled = false;
300 for (auto& metric : metrics)
301 {
302 metric->deinitialize();
303 }
304 break;
305 }
306 readingsBuffer.emplace(id, metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200307 }
308 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200309
310 readings = {std::time(0), std::vector<ReadingData>(readingsBuffer.begin(),
311 readingsBuffer.end())};
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100312
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200313 reportIface->signal_property("Readings");
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200314}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100315
316bool Report::storeConfiguration() const
317{
318 try
319 {
320 nlohmann::json data;
321
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200322 data["Enabled"] = enabled;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100323 data["Version"] = reportVersion;
324 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100325 data["ReportingType"] = utils::toUnderlying(reportingType);
326 data["ReportActions"] =
327 utils::transform(reportActions, [](const auto reportAction) {
328 return utils::toUnderlying(reportAction);
329 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100330 data["Interval"] = interval.count();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200331 data["AppendLimit"] = appendLimit;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100332 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000333 data["ReadingParameters"] =
334 utils::transform(metrics, [](const auto& metric) {
335 return metric->dumpConfiguration();
336 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100337
338 reportStorage.store(fileName, data);
339 }
340 catch (const std::exception& e)
341 {
342 phosphor::logging::log<phosphor::logging::level::ERR>(
343 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100344 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100345 return false;
346 }
347
348 return true;
349}