blob: 70cd8f7e6d45d0d158e0de92e6b69c05698077f7 [file] [log] [blame]
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02001#include "report.hpp"
2
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +01003#include "messages/collect_trigger_id.hpp"
4#include "messages/trigger_presence_changed_ind.hpp"
5#include "messages/update_report_ind.hpp"
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02006#include "report_manager.hpp"
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +01007#include "utils/clock.hpp"
Krzysztof Grobelny51497a02021-11-09 14:56:22 +01008#include "utils/contains.hpp"
Szymon Dompke1cdd7e42022-06-08 14:43:13 +02009#include "utils/dbus_path_utils.hpp"
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010010#include "utils/ensure.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +010011#include "utils/transform.hpp"
12
13#include <phosphor-logging/log.hpp>
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +020014#include <sdbusplus/vtable.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020015
Szymon Dompke3eb56862021-09-20 15:32:04 +020016#include <limits>
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020017#include <numeric>
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010018#include <optional>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020019
20Report::Report(boost::asio::io_context& ioc,
21 const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010022 const std::string& reportId, const std::string& reportName,
Szymon Dompke3eb56862021-09-20 15:32:04 +020023 const ReportingType reportingTypeIn,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010024 std::vector<ReportAction> reportActionsIn,
Szymon Dompke3eb56862021-09-20 15:32:04 +020025 const Milliseconds intervalIn, const uint64_t appendLimitIn,
26 const ReportUpdates reportUpdatesIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020027 interfaces::ReportManager& reportManager,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010028 interfaces::JsonStorage& reportStorageIn,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020029 std::vector<std::shared_ptr<interfaces::Metric>> metricsIn,
Szymon Dompkefdb06a12022-02-11 11:04:44 +010030 const interfaces::ReportFactory& reportFactory,
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010031 const bool enabledIn, std::unique_ptr<interfaces::Clock> clock,
32 Readings readingsIn) :
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010033 id(reportId),
Szymon Dompke1cdd7e42022-06-08 14:43:13 +020034 path(utils::pathAppend(utils::constants::reportDirPath, id)),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010035 name(reportName), reportingType(reportingTypeIn), interval(intervalIn),
Szymon Dompkefdb06a12022-02-11 11:04:44 +010036 reportActions(reportActionsIn.begin(), reportActionsIn.end()),
Szymon Dompke3eb56862021-09-20 15:32:04 +020037 sensorCount(getSensorCount(metricsIn)),
38 appendLimit(deduceAppendLimit(appendLimitIn)),
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010039 reportUpdates(reportUpdatesIn), readings(std::move(readingsIn)),
40 readingsBuffer(std::get<1>(readings),
41 deduceBufferSize(reportUpdates, reportingType)),
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000042 objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010043 triggerIds(collectTriggerIds(ioc)), reportStorage(reportStorageIn),
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020044 clock(std::move(clock)), messanger(ioc)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020045{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000046 readingParameters =
47 toReadingParameters(utils::transform(metrics, [](const auto& metric) {
48 return metric->dumpConfiguration();
49 }));
50
51 readingParametersPastVersion =
52 utils::transform(readingParameters, [](const auto& item) {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010053 const auto& [sensorData, operationType, id, collectionTimeScope,
54 collectionDuration] = item;
55
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000056 return ReadingParametersPastVersion::value_type(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010057 std::get<0>(sensorData.front()), operationType, id,
58 std::get<1>(sensorData.front()));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000059 });
60
Szymon Dompkefdb06a12022-02-11 11:04:44 +010061 reportActions.insert(ReportAction::logToMetricReportsCollection);
62
Wludzik, Jozefe2362792020-10-27 17:23:55 +010063 deleteIface = objServer->add_unique_interface(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010064 getPath(), deleteIfaceName,
65 [this, &ioc, &reportManager](auto& dbusIface) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010066 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
67 if (persistency)
68 {
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010069 persistency = false;
70
71 reportIface->signal_property("Persistency");
Wludzik, Jozefe2362792020-10-27 17:23:55 +010072 }
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010073
Wludzik, Jozefe2362792020-10-27 17:23:55 +010074 boost::asio::post(ioc, [this, &reportManager] {
75 reportManager.removeReport(this);
76 });
77 });
78 });
79
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020080 errorMessages = verify();
81 state.set<ReportFlags::enabled, ReportFlags::valid>(enabledIn,
82 errorMessages.empty());
83
Szymon Dompkefdb06a12022-02-11 11:04:44 +010084 reportIface = makeReportInterface(reportFactory);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020085 persistency = storeConfiguration();
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010086
87 messanger.on_receive<messages::TriggerPresenceChangedInd>(
88 [this](const auto& msg) {
89 const auto oldSize = triggerIds.size();
90
91 if (msg.presence == messages::Presence::Exist)
92 {
93 if (utils::contains(msg.reportIds, id))
94 {
95 triggerIds.insert(msg.triggerId);
96 }
97 else if (!utils::contains(msg.reportIds, id))
98 {
99 triggerIds.erase(msg.triggerId);
100 }
101 }
102 else if (msg.presence == messages::Presence::Removed)
103 {
104 triggerIds.erase(msg.triggerId);
105 }
106
107 if (triggerIds.size() != oldSize)
108 {
Szymon Dompke1cdd7e42022-06-08 14:43:13 +0200109 reportIface->signal_property("Triggers");
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100110 }
111 });
112
113 messanger.on_receive<messages::UpdateReportInd>([this](const auto& msg) {
114 if (utils::contains(msg.reportIds, id))
115 {
116 updateReadings();
117 }
118 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200119}
120
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100121Report::~Report()
122{
123 if (persistency)
124 {
125 if (shouldStoreMetricValues())
126 {
127 storeConfiguration();
128 }
129 }
130 else
131 {
132 reportStorage.remove(reportFileName());
133 }
134}
135
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200136void Report::activate()
137{
138 for (auto& metric : this->metrics)
139 {
140 metric->initialize();
141 }
142
143 scheduleTimer();
144
145 if (reportIface)
146 {
147 reportIface->signal_property("errors");
148 }
149}
150
151void Report::deactivate()
152{
153 for (auto& metric : metrics)
154 {
155 metric->deinitialize();
156 }
157
158 unregisterFromMetrics = nullptr;
159 timer.cancel();
160
161 if (reportIface)
162 {
163 reportIface->signal_property("Errors");
164 }
165}
166
Szymon Dompke3eb56862021-09-20 15:32:04 +0200167uint64_t Report::getSensorCount(
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100168 const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200169{
170 uint64_t sensorCount = 0;
171 for (auto& metric : metrics)
172 {
173 sensorCount += metric->sensorCount();
174 }
175 return sensorCount;
176}
177
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100178std::optional<uint64_t>
179 Report::deduceAppendLimit(const uint64_t appendLimitIn) const
Szymon Dompke3eb56862021-09-20 15:32:04 +0200180{
181 if (appendLimitIn == std::numeric_limits<uint64_t>::max())
182 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100183 return std::nullopt;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200184 }
185 else
186 {
187 return appendLimitIn;
188 }
189}
190
191uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
192 const ReportingType reportingTypeIn) const
193{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100194 if (reportUpdatesIn == ReportUpdates::overwrite ||
195 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200196 {
197 return sensorCount;
198 }
199 else
200 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100201 return appendLimit.value_or(sensorCount);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200202 }
203}
204
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100205void Report::setReadingBuffer(const ReportUpdates newReportUpdates)
206{
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200207 const auto newBufferSize =
208 deduceBufferSize(newReportUpdates, reportingType);
209 if (readingsBuffer.size() != newBufferSize)
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100210 {
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200211 readingsBuffer.clearAndResize(newBufferSize);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100212 }
213}
214
Szymon Dompke3eb56862021-09-20 15:32:04 +0200215void Report::setReportUpdates(const ReportUpdates newReportUpdates)
216{
217 if (reportUpdates != newReportUpdates)
218 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100219 setReadingBuffer(newReportUpdates);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200220 reportUpdates = newReportUpdates;
221 }
222}
223
Szymon Dompke892f7c82022-10-12 09:54:22 +0200224void Report::updateSensorCount(const uint64_t newSensorCount)
225{
226 if (sensorCount != newSensorCount)
227 {
228 sensorCount = newSensorCount;
229 if (!appendLimit.has_value())
230 {
231 reportIface->signal_property("AppendLimit");
232 }
233 }
234}
235
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100236std::unique_ptr<sdbusplus::asio::dbus_interface>
237 Report::makeReportInterface(const interfaces::ReportFactory& reportFactory)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000238{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100239 auto dbusIface =
240 objServer->add_unique_interface(getPath(), reportIfaceName);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200241 dbusIface->register_property_rw<bool>(
242 "Enabled", sdbusplus::vtable::property_::emits_change,
243 [this](bool newVal, auto& oldValue) {
244 if (newVal != state.get<ReportFlags::enabled>())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200245 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200246 state.set<ReportFlags::enabled>(oldValue = newVal);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200247
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200248 persistency = storeConfiguration();
249 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100250 return 1;
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200251 },
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200252 [this](const auto&) { return state.get<ReportFlags::enabled>(); });
253 dbusIface->register_property_r<
254 std::vector<std::tuple<std::string, std::string>>>(
255 "ErrorMessages", sdbusplus::vtable::property_::emits_change,
256 [this](const auto&) {
257 return utils::transform(errorMessages, [](const auto& em) {
258 return std::tuple<std::string, std::string>(
259 utils::enumToString(em.error), em.arg0);
260 });
261 });
262 dbusIface->register_property_rw<uint64_t>(
263 "Interval", sdbusplus::vtable::property_::emits_change,
264 [this](uint64_t newVal, auto& oldVal) {
265 const Milliseconds newValT{newVal};
266 if (newValT < ReportManager::minInterval &&
267 newValT != Milliseconds{0})
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000268 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200269 throw sdbusplus::exception::SdBusError(
270 static_cast<int>(std::errc::invalid_argument),
271 "Invalid interval");
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000272 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200273
274 if (newValT != interval)
275 {
276 oldVal = newVal;
277 interval = newValT;
278
279 errorMessages = verify();
280 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
281 StateEvent::active)
282 {
283 scheduleTimer();
284 }
285
286 persistency = storeConfiguration();
287 }
288 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000289 },
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000290 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200291 dbusIface->register_property_rw<bool>(
292 "Persistency", sdbusplus::vtable::property_::emits_change,
293 [this](bool newVal, auto& oldVal) {
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000294 if (newVal == persistency)
295 {
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100296 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000297 }
298 if (newVal)
299 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200300 persistency = oldVal = storeConfiguration();
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000301 }
302 else
303 {
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100304 reportStorage.remove(reportFileName());
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200305 persistency = oldVal = false;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000306 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100307 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000308 },
309 [this](const auto&) { return persistency; });
310
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100311 dbusIface->register_property_r("Readings", readings,
312 sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000313 [this](const auto&) { return readings; });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200314 dbusIface->register_property_rw<std::string>(
315 "ReportingType", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100316 [this](auto newVal, auto& oldVal) {
317 ReportingType tmp = utils::toReportingType(newVal);
318 if (tmp != reportingType)
319 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200320 reportingType = tmp;
321 oldVal = std::move(newVal);
322
323 errorMessages = verify();
324 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
325 StateEvent::active)
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100326 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200327 scheduleTimer();
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100328 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100329
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100330 persistency = storeConfiguration();
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200331
332 setReadingBuffer(reportUpdates);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100333 }
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100334 return 1;
335 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100336 [this](const auto&) { return utils::enumToString(reportingType); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000337 dbusIface->register_property_r(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000338 "ReadingParameters", readingParametersPastVersion,
339 sdbusplus::vtable::property_::const_,
340 [this](const auto&) { return readingParametersPastVersion; });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100341 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000342 "ReadingParametersFutureVersion", readingParameters,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100343 sdbusplus::vtable::property_::emits_change,
344 [this, &reportFactory](auto newVal, auto& oldVal) {
Szymon Dompke32305f12022-07-05 15:37:21 +0200345 auto labeledMetricParams =
346 reportFactory.convertMetricParams(newVal);
347 ReportManager::verifyMetricParameters(labeledMetricParams);
348 reportFactory.updateMetrics(metrics,
349 state.get<ReportFlags::enabled>(),
350 labeledMetricParams);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100351 readingParameters = toReadingParameters(
352 utils::transform(metrics, [](const auto& metric) {
353 return metric->dumpConfiguration();
354 }));
Szymon Dompke892f7c82022-10-12 09:54:22 +0200355 updateSensorCount(getSensorCount(metrics));
356 setReadingBuffer(reportUpdates);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100357 persistency = storeConfiguration();
358 oldVal = std::move(newVal);
359 return 1;
360 },
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000361 [this](const auto&) { return readingParameters; });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200362 dbusIface->register_property_r<bool>(
363 "EmitsReadingsUpdate", sdbusplus::vtable::property_::none,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100364 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100365 return reportActions.contains(ReportAction::emitsReadingsUpdate);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100366 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200367 dbusIface->register_property_r<std::string>(
368 "Name", sdbusplus::vtable::property_::const_,
369 [this](const auto&) { return name; });
370 dbusIface->register_property_r<bool>(
371 "LogToMetricReportsCollection", sdbusplus::vtable::property_::const_,
372 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100373 return reportActions.contains(
374 ReportAction::logToMetricReportsCollection);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100375 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200376 dbusIface->register_property_rw<std::vector<std::string>>(
377 "ReportActions", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100378 [this](auto newVal, auto& oldVal) {
379 auto tmp = utils::transform<std::unordered_set>(
380 newVal, [](const auto& reportAction) {
381 return utils::toReportAction(reportAction);
382 });
383 tmp.insert(ReportAction::logToMetricReportsCollection);
384
385 if (tmp != reportActions)
386 {
387 reportActions = tmp;
388 persistency = storeConfiguration();
389 oldVal = std::move(newVal);
390 }
391 return 1;
392 },
393 [this](const auto&) {
394 return utils::transform<std::vector>(
395 reportActions, [](const auto reportAction) {
396 return utils::enumToString(reportAction);
397 });
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100398 });
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100399 dbusIface->register_property_r(
400 "AppendLimit", appendLimit.value_or(sensorCount),
401 sdbusplus::vtable::property_::emits_change,
402 [this](const auto&) { return appendLimit.value_or(sensorCount); });
Szymon Dompke3eb56862021-09-20 15:32:04 +0200403 dbusIface->register_property_rw(
404 "ReportUpdates", std::string(),
405 sdbusplus::vtable::property_::emits_change,
406 [this](auto newVal, auto& oldVal) {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100407 setReportUpdates(utils::toReportUpdates(newVal));
Szymon Dompke3eb56862021-09-20 15:32:04 +0200408 oldVal = newVal;
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100409 return 1;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200410 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100411 [this](const auto&) { return utils::enumToString(reportUpdates); });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100412 dbusIface->register_property_r(
Szymon Dompke1cdd7e42022-06-08 14:43:13 +0200413 "Triggers", std::vector<sdbusplus::message::object_path>{},
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100414 sdbusplus::vtable::property_::emits_change, [this](const auto&) {
Szymon Dompke1cdd7e42022-06-08 14:43:13 +0200415 return utils::transform<std::vector>(
416 triggerIds, [](const auto& triggerId) {
417 return utils::pathAppend(utils::constants::triggerDirPath,
418 triggerId);
419 });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100420 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000421 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100422 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000423 {
424 updateReadings();
425 }
426 });
427 constexpr bool skipPropertiesChangedSignal = true;
428 dbusIface->initialize(skipPropertiesChangedSignal);
429 return dbusIface;
430}
431
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100432void Report::timerProcForPeriodicReport(boost::system::error_code ec,
433 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200434{
435 if (ec)
436 {
437 return;
438 }
439
440 self.updateReadings();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100441 self.scheduleTimerForPeriodicReport(self.interval);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200442}
443
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100444void Report::timerProcForOnChangeReport(boost::system::error_code ec,
445 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200446{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100447 if (ec)
448 {
449 return;
450 }
451
452 const auto ensure =
453 utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
454
455 self.onChangeContext.emplace(self);
456
457 const auto steadyTimestamp = self.clock->steadyTimestamp();
458
459 for (auto& metric : self.metrics)
460 {
461 metric->updateReadings(steadyTimestamp);
462 }
463
464 self.scheduleTimerForOnChangeReport();
465}
466
467void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
468{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200469 timer.expires_after(timerInterval);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100470 timer.async_wait([this](boost::system::error_code ec) {
471 timerProcForPeriodicReport(ec, *this);
472 });
473}
474
475void Report::scheduleTimerForOnChangeReport()
476{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100477 constexpr Milliseconds timerInterval{100};
478
479 timer.expires_after(timerInterval);
480 timer.async_wait([this](boost::system::error_code ec) {
481 timerProcForOnChangeReport(ec, *this);
482 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200483}
484
485void Report::updateReadings()
486{
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200487 if (!state.isActive())
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000488 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200489 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000490 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200491
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100492 if (reportUpdates == ReportUpdates::overwrite ||
493 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200494 {
495 readingsBuffer.clear();
496 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000497
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200498 for (const auto& metric : metrics)
499 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200500 if (!state.isActive())
501 {
502 break;
503 }
504
Szymon Dompke3eb56862021-09-20 15:32:04 +0200505 for (const auto& [id, metadata, value, timestamp] :
Krzysztof Grobelny9e8da542022-02-17 10:40:16 +0100506 metric->getUpdatedReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200507 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100508 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200509 readingsBuffer.isFull())
510 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200511 state.set<ReportFlags::enabled>(false);
512 reportIface->signal_property("Enabled");
Szymon Dompke3eb56862021-09-20 15:32:04 +0200513 break;
514 }
515 readingsBuffer.emplace(id, metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200516 }
517 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200518
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100519 std::get<0>(readings) =
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100520 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100521 .count();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100522
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100523 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
524 {
525 reportIface->signal_property("Readings");
526 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200527}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100528
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100529bool Report::shouldStoreMetricValues() const
530{
531 return reportingType != ReportingType::onRequest &&
532 reportUpdates == ReportUpdates::appendStopsWhenFull;
533}
534
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100535bool Report::storeConfiguration() const
536{
537 try
538 {
539 nlohmann::json data;
540
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200541 data["Enabled"] = state.get<ReportFlags::enabled>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100542 data["Version"] = reportVersion;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100543 data["Id"] = id;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100544 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100545 data["ReportingType"] = utils::toUnderlying(reportingType);
546 data["ReportActions"] =
547 utils::transform(reportActions, [](const auto reportAction) {
548 return utils::toUnderlying(reportAction);
549 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100550 data["Interval"] = interval.count();
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100551 data["AppendLimit"] =
552 appendLimit.value_or(std::numeric_limits<uint64_t>::max());
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100553 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000554 data["ReadingParameters"] =
555 utils::transform(metrics, [](const auto& metric) {
556 return metric->dumpConfiguration();
557 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100558
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100559 if (shouldStoreMetricValues())
560 {
561 data["MetricValues"] = utils::toLabeledReadings(readings);
562 }
563
564 reportStorage.store(reportFileName(), data);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100565 }
566 catch (const std::exception& e)
567 {
568 phosphor::logging::log<phosphor::logging::level::ERR>(
569 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100570 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100571 return false;
572 }
573
574 return true;
575}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100576
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100577interfaces::JsonStorage::FilePath Report::reportFileName() const
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100578{
579 return interfaces::JsonStorage::FilePath{
580 std::to_string(std::hash<std::string>{}(id))};
581}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100582
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100583std::unordered_set<std::string>
584 Report::collectTriggerIds(boost::asio::io_context& ioc) const
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100585{
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100586 utils::Messanger tmp(ioc);
587
588 auto result = std::unordered_set<std::string>();
589
590 tmp.on_receive<messages::CollectTriggerIdResp>(
591 [&result](const auto& msg) { result.insert(msg.triggerId); });
592
593 tmp.send(messages::CollectTriggerIdReq{id});
594
595 return result;
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100596}
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100597
598void Report::metricUpdated()
599{
600 if (onChangeContext)
601 {
602 onChangeContext->metricUpdated();
603 return;
604 }
605
606 updateReadings();
607}
608
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200609void Report::scheduleTimer()
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100610{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100611 switch (reportingType)
612 {
613 case ReportingType::periodic:
614 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200615 unregisterFromMetrics = nullptr;
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100616 scheduleTimerForPeriodicReport(interval);
617 break;
618 }
619 case ReportingType::onChange:
620 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200621 if (!unregisterFromMetrics)
622 {
623 unregisterFromMetrics = [this] {
624 for (auto& metric : metrics)
625 {
626 metric->unregisterFromUpdates(*this);
627 }
628 };
629
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100630 for (auto& metric : metrics)
631 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200632 metric->registerForUpdates(*this);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100633 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200634 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100635
636 bool isTimerRequired = false;
637
638 for (auto& metric : metrics)
639 {
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100640 if (metric->isTimerRequired())
641 {
642 isTimerRequired = true;
643 }
644 }
645
646 if (isTimerRequired)
647 {
648 scheduleTimerForOnChangeReport();
649 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200650 else
651 {
652 timer.cancel();
653 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100654 break;
655 }
656 default:
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200657 unregisterFromMetrics = nullptr;
658 timer.cancel();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100659 break;
660 }
661}
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200662
663std::vector<ErrorMessage> Report::verify() const
664{
665 std::vector<ErrorMessage> result;
666
667 if ((reportingType == ReportingType::periodic &&
668 interval == Milliseconds{0}) ||
669 (reportingType != ReportingType::periodic &&
670 interval != Milliseconds{0}))
671 {
672 result.emplace_back(ErrorType::propertyConflict, "Interval");
673 result.emplace_back(ErrorType::propertyConflict, "ReportingType");
674 }
675
676 return result;
677}