blob: 540418ad5f15cec67b44ea05b56e2fd70bde22a2 [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"
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +01009#include "utils/ensure.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +010010#include "utils/transform.hpp"
11
12#include <phosphor-logging/log.hpp>
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +020013#include <sdbusplus/vtable.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020014
Szymon Dompke3eb56862021-09-20 15:32:04 +020015#include <limits>
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020016#include <numeric>
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010017#include <optional>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020018
19Report::Report(boost::asio::io_context& ioc,
20 const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010021 const std::string& reportId, const std::string& reportName,
Szymon Dompke3eb56862021-09-20 15:32:04 +020022 const ReportingType reportingTypeIn,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010023 std::vector<ReportAction> reportActionsIn,
Szymon Dompke3eb56862021-09-20 15:32:04 +020024 const Milliseconds intervalIn, const uint64_t appendLimitIn,
25 const ReportUpdates reportUpdatesIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020026 interfaces::ReportManager& reportManager,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010027 interfaces::JsonStorage& reportStorageIn,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020028 std::vector<std::shared_ptr<interfaces::Metric>> metricsIn,
Szymon Dompkefdb06a12022-02-11 11:04:44 +010029 const interfaces::ReportFactory& reportFactory,
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010030 const bool enabledIn, std::unique_ptr<interfaces::Clock> clock,
31 Readings readingsIn) :
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010032 id(reportId),
33 name(reportName), reportingType(reportingTypeIn), interval(intervalIn),
Szymon Dompkefdb06a12022-02-11 11:04:44 +010034 reportActions(reportActionsIn.begin(), reportActionsIn.end()),
Szymon Dompke3eb56862021-09-20 15:32:04 +020035 sensorCount(getSensorCount(metricsIn)),
36 appendLimit(deduceAppendLimit(appendLimitIn)),
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010037 reportUpdates(reportUpdatesIn), readings(std::move(readingsIn)),
38 readingsBuffer(std::get<1>(readings),
39 deduceBufferSize(reportUpdates, reportingType)),
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000040 objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010041 triggerIds(collectTriggerIds(ioc)), reportStorage(reportStorageIn),
42 enabled(enabledIn), clock(std::move(clock)), messanger(ioc)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020043{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000044 readingParameters =
45 toReadingParameters(utils::transform(metrics, [](const auto& metric) {
46 return metric->dumpConfiguration();
47 }));
48
49 readingParametersPastVersion =
50 utils::transform(readingParameters, [](const auto& item) {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010051 const auto& [sensorData, operationType, id, collectionTimeScope,
52 collectionDuration] = item;
53
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000054 return ReadingParametersPastVersion::value_type(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010055 std::get<0>(sensorData.front()), operationType, id,
56 std::get<1>(sensorData.front()));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000057 });
58
Szymon Dompkefdb06a12022-02-11 11:04:44 +010059 reportActions.insert(ReportAction::logToMetricReportsCollection);
60
Wludzik, Jozefe2362792020-10-27 17:23:55 +010061 deleteIface = objServer->add_unique_interface(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010062 getPath(), deleteIfaceName,
63 [this, &ioc, &reportManager](auto& dbusIface) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010064 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
65 if (persistency)
66 {
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010067 persistency = false;
68
69 reportIface->signal_property("Persistency");
Wludzik, Jozefe2362792020-10-27 17:23:55 +010070 }
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010071
Wludzik, Jozefe2362792020-10-27 17:23:55 +010072 boost::asio::post(ioc, [this, &reportManager] {
73 reportManager.removeReport(this);
74 });
75 });
76 });
77
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000078 persistency = storeConfiguration();
Szymon Dompkefdb06a12022-02-11 11:04:44 +010079 reportIface = makeReportInterface(reportFactory);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020080
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010081 updateReportingType(reportingType);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000082
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020083 if (enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000084 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020085 for (auto& metric : this->metrics)
86 {
87 metric->initialize();
88 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000089 }
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010090
91 messanger.on_receive<messages::TriggerPresenceChangedInd>(
92 [this](const auto& msg) {
93 const auto oldSize = triggerIds.size();
94
95 if (msg.presence == messages::Presence::Exist)
96 {
97 if (utils::contains(msg.reportIds, id))
98 {
99 triggerIds.insert(msg.triggerId);
100 }
101 else if (!utils::contains(msg.reportIds, id))
102 {
103 triggerIds.erase(msg.triggerId);
104 }
105 }
106 else if (msg.presence == messages::Presence::Removed)
107 {
108 triggerIds.erase(msg.triggerId);
109 }
110
111 if (triggerIds.size() != oldSize)
112 {
113 reportIface->signal_property("TriggerIds");
114 }
115 });
116
117 messanger.on_receive<messages::UpdateReportInd>([this](const auto& msg) {
118 if (utils::contains(msg.reportIds, id))
119 {
120 updateReadings();
121 }
122 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200123}
124
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100125Report::~Report()
126{
127 if (persistency)
128 {
129 if (shouldStoreMetricValues())
130 {
131 storeConfiguration();
132 }
133 }
134 else
135 {
136 reportStorage.remove(reportFileName());
137 }
138}
139
Szymon Dompke3eb56862021-09-20 15:32:04 +0200140uint64_t Report::getSensorCount(
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100141 const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200142{
143 uint64_t sensorCount = 0;
144 for (auto& metric : metrics)
145 {
146 sensorCount += metric->sensorCount();
147 }
148 return sensorCount;
149}
150
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100151std::optional<uint64_t>
152 Report::deduceAppendLimit(const uint64_t appendLimitIn) const
Szymon Dompke3eb56862021-09-20 15:32:04 +0200153{
154 if (appendLimitIn == std::numeric_limits<uint64_t>::max())
155 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100156 return std::nullopt;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200157 }
158 else
159 {
160 return appendLimitIn;
161 }
162}
163
164uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
165 const ReportingType reportingTypeIn) const
166{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100167 if (reportUpdatesIn == ReportUpdates::overwrite ||
168 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200169 {
170 return sensorCount;
171 }
172 else
173 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100174 return appendLimit.value_or(sensorCount);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200175 }
176}
177
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100178void Report::setReadingBuffer(const ReportUpdates newReportUpdates)
179{
180 if (reportingType != ReportingType::onRequest &&
181 (reportUpdates == ReportUpdates::overwrite ||
182 newReportUpdates == ReportUpdates::overwrite))
183 {
184 readingsBuffer.clearAndResize(
185 deduceBufferSize(newReportUpdates, reportingType));
186 }
187}
188
Szymon Dompke3eb56862021-09-20 15:32:04 +0200189void Report::setReportUpdates(const ReportUpdates newReportUpdates)
190{
191 if (reportUpdates != newReportUpdates)
192 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100193 setReadingBuffer(newReportUpdates);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200194 reportUpdates = newReportUpdates;
195 }
196}
197
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100198std::unique_ptr<sdbusplus::asio::dbus_interface>
199 Report::makeReportInterface(const interfaces::ReportFactory& reportFactory)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000200{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100201 auto dbusIface =
202 objServer->add_unique_interface(getPath(), reportIfaceName);
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000203 dbusIface->register_property_rw(
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200204 "Enabled", enabled, sdbusplus::vtable::property_::emits_change,
205 [this](bool newVal, const auto&) {
206 if (newVal != enabled)
207 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100208 if (true == newVal && ReportingType::periodic == reportingType)
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200209 {
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100210 scheduleTimerForPeriodicReport(interval);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200211 }
212 if (newVal)
213 {
214 for (auto& metric : metrics)
215 {
216 metric->initialize();
217 }
218 }
219 else
220 {
221 for (auto& metric : metrics)
222 {
223 metric->deinitialize();
224 }
225 }
226
227 enabled = newVal;
228 persistency = storeConfiguration();
229 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100230 return 1;
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200231 },
232 [this](const auto&) { return enabled; });
233 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000234 "Interval", interval.count(),
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000235 sdbusplus::vtable::property_::emits_change,
236 [this](uint64_t newVal, auto&) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200237 if (Milliseconds newValT{newVal};
238 newValT >= ReportManager::minInterval)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000239 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200240 if (newValT != interval)
241 {
242 interval = newValT;
243 persistency = storeConfiguration();
244 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100245 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000246 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100247 throw sdbusplus::exception::SdBusError(
248 static_cast<int>(std::errc::invalid_argument),
249 "Invalid interval");
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000250 },
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000251 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000252 dbusIface->register_property_rw(
253 "Persistency", persistency, sdbusplus::vtable::property_::emits_change,
254 [this](bool newVal, const auto&) {
255 if (newVal == persistency)
256 {
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100257 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000258 }
259 if (newVal)
260 {
261 persistency = storeConfiguration();
262 }
263 else
264 {
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100265 reportStorage.remove(reportFileName());
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000266 persistency = false;
267 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100268 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000269 },
270 [this](const auto&) { return persistency; });
271
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100272 dbusIface->register_property_r("Readings", readings,
273 sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000274 [this](const auto&) { return readings; });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100275 dbusIface->register_property_rw(
276 "ReportingType", std::string(),
277 sdbusplus::vtable::property_::emits_change,
278 [this](auto newVal, auto& oldVal) {
279 ReportingType tmp = utils::toReportingType(newVal);
280 if (tmp != reportingType)
281 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100282 if (tmp == ReportingType::periodic)
283 {
284 if (interval < ReportManager::minInterval)
285 {
286 throw sdbusplus::exception::SdBusError(
287 static_cast<int>(std::errc::invalid_argument),
288 "Invalid interval");
289 }
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100290 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100291
292 updateReportingType(tmp);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100293 setReadingBuffer(reportUpdates);
294 persistency = storeConfiguration();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100295 oldVal = std::move(newVal);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100296 }
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100297 return 1;
298 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100299 [this](const auto&) { return utils::enumToString(reportingType); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000300 dbusIface->register_property_r(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000301 "ReadingParameters", readingParametersPastVersion,
302 sdbusplus::vtable::property_::const_,
303 [this](const auto&) { return readingParametersPastVersion; });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100304 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000305 "ReadingParametersFutureVersion", readingParameters,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100306 sdbusplus::vtable::property_::emits_change,
307 [this, &reportFactory](auto newVal, auto& oldVal) {
308 reportFactory.updateMetrics(metrics, enabled, newVal);
309 readingParameters = toReadingParameters(
310 utils::transform(metrics, [](const auto& metric) {
311 return metric->dumpConfiguration();
312 }));
313 persistency = storeConfiguration();
314 oldVal = std::move(newVal);
315 return 1;
316 },
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000317 [this](const auto&) { return readingParameters; });
318 dbusIface->register_property_r(
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100319 "EmitsReadingsUpdate", bool{}, sdbusplus::vtable::property_::none,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100320 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100321 return reportActions.contains(ReportAction::emitsReadingsUpdate);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100322 });
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100323 dbusIface->register_property_r("Name", std::string{},
324 sdbusplus::vtable::property_::const_,
325 [this](const auto&) { return name; });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000326 dbusIface->register_property_r(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100327 "LogToMetricReportsCollection", bool{},
328 sdbusplus::vtable::property_::const_, [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100329 return reportActions.contains(
330 ReportAction::logToMetricReportsCollection);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100331 });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100332 dbusIface->register_property_rw(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100333 "ReportActions", std::vector<std::string>{},
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100334 sdbusplus::vtable::property_::emits_change,
335 [this](auto newVal, auto& oldVal) {
336 auto tmp = utils::transform<std::unordered_set>(
337 newVal, [](const auto& reportAction) {
338 return utils::toReportAction(reportAction);
339 });
340 tmp.insert(ReportAction::logToMetricReportsCollection);
341
342 if (tmp != reportActions)
343 {
344 reportActions = tmp;
345 persistency = storeConfiguration();
346 oldVal = std::move(newVal);
347 }
348 return 1;
349 },
350 [this](const auto&) {
351 return utils::transform<std::vector>(
352 reportActions, [](const auto reportAction) {
353 return utils::enumToString(reportAction);
354 });
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100355 });
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100356 dbusIface->register_property_r(
357 "AppendLimit", appendLimit.value_or(sensorCount),
358 sdbusplus::vtable::property_::emits_change,
359 [this](const auto&) { return appendLimit.value_or(sensorCount); });
Szymon Dompke3eb56862021-09-20 15:32:04 +0200360 dbusIface->register_property_rw(
361 "ReportUpdates", std::string(),
362 sdbusplus::vtable::property_::emits_change,
363 [this](auto newVal, auto& oldVal) {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100364 setReportUpdates(utils::toReportUpdates(newVal));
Szymon Dompke3eb56862021-09-20 15:32:04 +0200365 oldVal = newVal;
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100366 return 1;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200367 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100368 [this](const auto&) { return utils::enumToString(reportUpdates); });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100369 dbusIface->register_property_r(
370 "TriggerIds", std::vector<std::string>{},
371 sdbusplus::vtable::property_::emits_change, [this](const auto&) {
372 return std::vector<std::string>(triggerIds.begin(),
373 triggerIds.end());
374 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000375 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100376 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000377 {
378 updateReadings();
379 }
380 });
381 constexpr bool skipPropertiesChangedSignal = true;
382 dbusIface->initialize(skipPropertiesChangedSignal);
383 return dbusIface;
384}
385
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100386void Report::timerProcForPeriodicReport(boost::system::error_code ec,
387 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200388{
389 if (ec)
390 {
391 return;
392 }
393
394 self.updateReadings();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100395 self.scheduleTimerForPeriodicReport(self.interval);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200396}
397
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100398void Report::timerProcForOnChangeReport(boost::system::error_code ec,
399 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200400{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100401 if (ec)
402 {
403 return;
404 }
405
406 const auto ensure =
407 utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
408
409 self.onChangeContext.emplace(self);
410
411 const auto steadyTimestamp = self.clock->steadyTimestamp();
412
413 for (auto& metric : self.metrics)
414 {
415 metric->updateReadings(steadyTimestamp);
416 }
417
418 self.scheduleTimerForOnChangeReport();
419}
420
421void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
422{
423 if (!enabled)
424 {
425 return;
426 }
427
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200428 timer.expires_after(timerInterval);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100429 timer.async_wait([this](boost::system::error_code ec) {
430 timerProcForPeriodicReport(ec, *this);
431 });
432}
433
434void Report::scheduleTimerForOnChangeReport()
435{
436 if (!enabled)
437 {
438 return;
439 }
440
441 constexpr Milliseconds timerInterval{100};
442
443 timer.expires_after(timerInterval);
444 timer.async_wait([this](boost::system::error_code ec) {
445 timerProcForOnChangeReport(ec, *this);
446 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200447}
448
449void Report::updateReadings()
450{
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200451 if (!enabled)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000452 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200453 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000454 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200455
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100456 if (reportUpdates == ReportUpdates::overwrite ||
457 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200458 {
459 readingsBuffer.clear();
460 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000461
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200462 for (const auto& metric : metrics)
463 {
Szymon Dompke3eb56862021-09-20 15:32:04 +0200464 for (const auto& [id, metadata, value, timestamp] :
Krzysztof Grobelny9e8da542022-02-17 10:40:16 +0100465 metric->getUpdatedReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200466 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100467 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200468 readingsBuffer.isFull())
469 {
470 enabled = false;
Krzysztof Grobelnyfbeb5bf2022-01-03 09:41:29 +0100471 for (auto& m : metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200472 {
Krzysztof Grobelnyfbeb5bf2022-01-03 09:41:29 +0100473 m->deinitialize();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200474 }
475 break;
476 }
477 readingsBuffer.emplace(id, metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200478 }
479 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200480
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100481 std::get<0>(readings) =
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100482 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100483 .count();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100484
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100485 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
486 {
487 reportIface->signal_property("Readings");
488 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200489}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100490
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100491bool Report::shouldStoreMetricValues() const
492{
493 return reportingType != ReportingType::onRequest &&
494 reportUpdates == ReportUpdates::appendStopsWhenFull;
495}
496
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100497bool Report::storeConfiguration() const
498{
499 try
500 {
501 nlohmann::json data;
502
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200503 data["Enabled"] = enabled;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100504 data["Version"] = reportVersion;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100505 data["Id"] = id;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100506 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100507 data["ReportingType"] = utils::toUnderlying(reportingType);
508 data["ReportActions"] =
509 utils::transform(reportActions, [](const auto reportAction) {
510 return utils::toUnderlying(reportAction);
511 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100512 data["Interval"] = interval.count();
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100513 data["AppendLimit"] =
514 appendLimit.value_or(std::numeric_limits<uint64_t>::max());
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100515 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000516 data["ReadingParameters"] =
517 utils::transform(metrics, [](const auto& metric) {
518 return metric->dumpConfiguration();
519 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100520
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100521 if (shouldStoreMetricValues())
522 {
523 data["MetricValues"] = utils::toLabeledReadings(readings);
524 }
525
526 reportStorage.store(reportFileName(), data);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100527 }
528 catch (const std::exception& e)
529 {
530 phosphor::logging::log<phosphor::logging::level::ERR>(
531 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100532 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100533 return false;
534 }
535
536 return true;
537}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100538
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100539interfaces::JsonStorage::FilePath Report::reportFileName() const
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100540{
541 return interfaces::JsonStorage::FilePath{
542 std::to_string(std::hash<std::string>{}(id))};
543}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100544
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100545std::unordered_set<std::string>
546 Report::collectTriggerIds(boost::asio::io_context& ioc) const
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100547{
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100548 utils::Messanger tmp(ioc);
549
550 auto result = std::unordered_set<std::string>();
551
552 tmp.on_receive<messages::CollectTriggerIdResp>(
553 [&result](const auto& msg) { result.insert(msg.triggerId); });
554
555 tmp.send(messages::CollectTriggerIdReq{id});
556
557 return result;
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100558}
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100559
560void Report::metricUpdated()
561{
562 if (onChangeContext)
563 {
564 onChangeContext->metricUpdated();
565 return;
566 }
567
568 updateReadings();
569}
570
571void Report::updateReportingType(ReportingType newReportingType)
572{
573 if (reportingType != newReportingType)
574 {
575 timer.cancel();
576 unregisterFromMetrics = nullptr;
577 }
578
579 reportingType = newReportingType;
580
581 switch (reportingType)
582 {
583 case ReportingType::periodic:
584 {
585 scheduleTimerForPeriodicReport(interval);
586 break;
587 }
588 case ReportingType::onChange:
589 {
590 unregisterFromMetrics = [this] {
591 for (auto& metric : metrics)
592 {
593 metric->unregisterFromUpdates(*this);
594 }
595 };
596
597 bool isTimerRequired = false;
598
599 for (auto& metric : metrics)
600 {
601 metric->registerForUpdates(*this);
602 if (metric->isTimerRequired())
603 {
604 isTimerRequired = true;
605 }
606 }
607
608 if (isTimerRequired)
609 {
610 scheduleTimerForOnChangeReport();
611 }
612 break;
613 }
614 default:
615 break;
616 }
617}