blob: d9d89b8bd45f3a6ec371b53cddf7d62b6fe292ea [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 Grobelnye6d48872022-02-08 13:41:30 +010030 const bool enabledIn, std::unique_ptr<interfaces::Clock> clock) :
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010031 id(reportId),
32 name(reportName), reportingType(reportingTypeIn), interval(intervalIn),
Szymon Dompkefdb06a12022-02-11 11:04:44 +010033 reportActions(reportActionsIn.begin(), reportActionsIn.end()),
Szymon Dompke3eb56862021-09-20 15:32:04 +020034 sensorCount(getSensorCount(metricsIn)),
35 appendLimit(deduceAppendLimit(appendLimitIn)),
36 reportUpdates(reportUpdatesIn),
37 readingsBuffer(deduceBufferSize(reportUpdates, reportingType)),
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000038 objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010039 triggerIds(collectTriggerIds(ioc)), reportStorage(reportStorageIn),
40 enabled(enabledIn), clock(std::move(clock)), messanger(ioc)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020041{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000042 readingParameters =
43 toReadingParameters(utils::transform(metrics, [](const auto& metric) {
44 return metric->dumpConfiguration();
45 }));
46
47 readingParametersPastVersion =
48 utils::transform(readingParameters, [](const auto& item) {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010049 const auto& [sensorData, operationType, id, collectionTimeScope,
50 collectionDuration] = item;
51
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000052 return ReadingParametersPastVersion::value_type(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010053 std::get<0>(sensorData.front()), operationType, id,
54 std::get<1>(sensorData.front()));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000055 });
56
Szymon Dompkefdb06a12022-02-11 11:04:44 +010057 reportActions.insert(ReportAction::logToMetricReportsCollection);
58
Wludzik, Jozefe2362792020-10-27 17:23:55 +010059 deleteIface = objServer->add_unique_interface(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010060 getPath(), deleteIfaceName,
61 [this, &ioc, &reportManager](auto& dbusIface) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010062 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
63 if (persistency)
64 {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010065 reportStorage.remove(fileName());
Wludzik, Jozefe2362792020-10-27 17:23:55 +010066 }
67 boost::asio::post(ioc, [this, &reportManager] {
68 reportManager.removeReport(this);
69 });
70 });
71 });
72
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000073 persistency = storeConfiguration();
Szymon Dompkefdb06a12022-02-11 11:04:44 +010074 reportIface = makeReportInterface(reportFactory);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020075
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010076 updateReportingType(reportingType);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000077
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020078 if (enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000079 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020080 for (auto& metric : this->metrics)
81 {
82 metric->initialize();
83 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000084 }
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010085
86 messanger.on_receive<messages::TriggerPresenceChangedInd>(
87 [this](const auto& msg) {
88 const auto oldSize = triggerIds.size();
89
90 if (msg.presence == messages::Presence::Exist)
91 {
92 if (utils::contains(msg.reportIds, id))
93 {
94 triggerIds.insert(msg.triggerId);
95 }
96 else if (!utils::contains(msg.reportIds, id))
97 {
98 triggerIds.erase(msg.triggerId);
99 }
100 }
101 else if (msg.presence == messages::Presence::Removed)
102 {
103 triggerIds.erase(msg.triggerId);
104 }
105
106 if (triggerIds.size() != oldSize)
107 {
108 reportIface->signal_property("TriggerIds");
109 }
110 });
111
112 messanger.on_receive<messages::UpdateReportInd>([this](const auto& msg) {
113 if (utils::contains(msg.reportIds, id))
114 {
115 updateReadings();
116 }
117 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200118}
119
Szymon Dompke3eb56862021-09-20 15:32:04 +0200120uint64_t Report::getSensorCount(
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100121 const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200122{
123 uint64_t sensorCount = 0;
124 for (auto& metric : metrics)
125 {
126 sensorCount += metric->sensorCount();
127 }
128 return sensorCount;
129}
130
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100131std::optional<uint64_t>
132 Report::deduceAppendLimit(const uint64_t appendLimitIn) const
Szymon Dompke3eb56862021-09-20 15:32:04 +0200133{
134 if (appendLimitIn == std::numeric_limits<uint64_t>::max())
135 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100136 return std::nullopt;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200137 }
138 else
139 {
140 return appendLimitIn;
141 }
142}
143
144uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
145 const ReportingType reportingTypeIn) const
146{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100147 if (reportUpdatesIn == ReportUpdates::overwrite ||
148 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200149 {
150 return sensorCount;
151 }
152 else
153 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100154 return appendLimit.value_or(sensorCount);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200155 }
156}
157
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100158void Report::setReadingBuffer(const ReportUpdates newReportUpdates)
159{
160 if (reportingType != ReportingType::onRequest &&
161 (reportUpdates == ReportUpdates::overwrite ||
162 newReportUpdates == ReportUpdates::overwrite))
163 {
164 readingsBuffer.clearAndResize(
165 deduceBufferSize(newReportUpdates, reportingType));
166 }
167}
168
Szymon Dompke3eb56862021-09-20 15:32:04 +0200169void Report::setReportUpdates(const ReportUpdates newReportUpdates)
170{
171 if (reportUpdates != newReportUpdates)
172 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100173 setReadingBuffer(newReportUpdates);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200174 reportUpdates = newReportUpdates;
175 }
176}
177
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100178std::unique_ptr<sdbusplus::asio::dbus_interface>
179 Report::makeReportInterface(const interfaces::ReportFactory& reportFactory)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000180{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100181 auto dbusIface =
182 objServer->add_unique_interface(getPath(), reportIfaceName);
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000183 dbusIface->register_property_rw(
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200184 "Enabled", enabled, sdbusplus::vtable::property_::emits_change,
185 [this](bool newVal, const auto&) {
186 if (newVal != enabled)
187 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100188 if (true == newVal && ReportingType::periodic == reportingType)
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200189 {
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100190 scheduleTimerForPeriodicReport(interval);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200191 }
192 if (newVal)
193 {
194 for (auto& metric : metrics)
195 {
196 metric->initialize();
197 }
198 }
199 else
200 {
201 for (auto& metric : metrics)
202 {
203 metric->deinitialize();
204 }
205 }
206
207 enabled = newVal;
208 persistency = storeConfiguration();
209 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100210 return 1;
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200211 },
212 [this](const auto&) { return enabled; });
213 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000214 "Interval", interval.count(),
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000215 sdbusplus::vtable::property_::emits_change,
216 [this](uint64_t newVal, auto&) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200217 if (Milliseconds newValT{newVal};
218 newValT >= ReportManager::minInterval)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000219 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200220 if (newValT != interval)
221 {
222 interval = newValT;
223 persistency = storeConfiguration();
224 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100225 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000226 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100227 throw sdbusplus::exception::SdBusError(
228 static_cast<int>(std::errc::invalid_argument),
229 "Invalid interval");
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000230 },
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000231 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000232 dbusIface->register_property_rw(
233 "Persistency", persistency, sdbusplus::vtable::property_::emits_change,
234 [this](bool newVal, const auto&) {
235 if (newVal == persistency)
236 {
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100237 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000238 }
239 if (newVal)
240 {
241 persistency = storeConfiguration();
242 }
243 else
244 {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100245 reportStorage.remove(fileName());
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000246 persistency = false;
247 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100248 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000249 },
250 [this](const auto&) { return persistency; });
251
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100252 dbusIface->register_property_r("Readings", readings,
253 sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000254 [this](const auto&) { return readings; });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100255 dbusIface->register_property_rw(
256 "ReportingType", std::string(),
257 sdbusplus::vtable::property_::emits_change,
258 [this](auto newVal, auto& oldVal) {
259 ReportingType tmp = utils::toReportingType(newVal);
260 if (tmp != reportingType)
261 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100262 if (tmp == ReportingType::periodic)
263 {
264 if (interval < ReportManager::minInterval)
265 {
266 throw sdbusplus::exception::SdBusError(
267 static_cast<int>(std::errc::invalid_argument),
268 "Invalid interval");
269 }
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100270 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100271
272 updateReportingType(tmp);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100273 setReadingBuffer(reportUpdates);
274 persistency = storeConfiguration();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100275 oldVal = std::move(newVal);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100276 }
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100277 return 1;
278 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100279 [this](const auto&) { return utils::enumToString(reportingType); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000280 dbusIface->register_property_r(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000281 "ReadingParameters", readingParametersPastVersion,
282 sdbusplus::vtable::property_::const_,
283 [this](const auto&) { return readingParametersPastVersion; });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100284 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000285 "ReadingParametersFutureVersion", readingParameters,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100286 sdbusplus::vtable::property_::emits_change,
287 [this, &reportFactory](auto newVal, auto& oldVal) {
288 reportFactory.updateMetrics(metrics, enabled, newVal);
289 readingParameters = toReadingParameters(
290 utils::transform(metrics, [](const auto& metric) {
291 return metric->dumpConfiguration();
292 }));
293 persistency = storeConfiguration();
294 oldVal = std::move(newVal);
295 return 1;
296 },
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000297 [this](const auto&) { return readingParameters; });
298 dbusIface->register_property_r(
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100299 "EmitsReadingsUpdate", bool{}, sdbusplus::vtable::property_::none,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100300 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100301 return reportActions.contains(ReportAction::emitsReadingsUpdate);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100302 });
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100303 dbusIface->register_property_r("Name", std::string{},
304 sdbusplus::vtable::property_::const_,
305 [this](const auto&) { return name; });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000306 dbusIface->register_property_r(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100307 "LogToMetricReportsCollection", bool{},
308 sdbusplus::vtable::property_::const_, [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100309 return reportActions.contains(
310 ReportAction::logToMetricReportsCollection);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100311 });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100312 dbusIface->register_property_rw(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100313 "ReportActions", std::vector<std::string>{},
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100314 sdbusplus::vtable::property_::emits_change,
315 [this](auto newVal, auto& oldVal) {
316 auto tmp = utils::transform<std::unordered_set>(
317 newVal, [](const auto& reportAction) {
318 return utils::toReportAction(reportAction);
319 });
320 tmp.insert(ReportAction::logToMetricReportsCollection);
321
322 if (tmp != reportActions)
323 {
324 reportActions = tmp;
325 persistency = storeConfiguration();
326 oldVal = std::move(newVal);
327 }
328 return 1;
329 },
330 [this](const auto&) {
331 return utils::transform<std::vector>(
332 reportActions, [](const auto reportAction) {
333 return utils::enumToString(reportAction);
334 });
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100335 });
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100336 dbusIface->register_property_r(
337 "AppendLimit", appendLimit.value_or(sensorCount),
338 sdbusplus::vtable::property_::emits_change,
339 [this](const auto&) { return appendLimit.value_or(sensorCount); });
Szymon Dompke3eb56862021-09-20 15:32:04 +0200340 dbusIface->register_property_rw(
341 "ReportUpdates", std::string(),
342 sdbusplus::vtable::property_::emits_change,
343 [this](auto newVal, auto& oldVal) {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100344 setReportUpdates(utils::toReportUpdates(newVal));
Szymon Dompke3eb56862021-09-20 15:32:04 +0200345 oldVal = newVal;
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100346 return 1;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200347 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100348 [this](const auto&) { return utils::enumToString(reportUpdates); });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100349 dbusIface->register_property_r(
350 "TriggerIds", std::vector<std::string>{},
351 sdbusplus::vtable::property_::emits_change, [this](const auto&) {
352 return std::vector<std::string>(triggerIds.begin(),
353 triggerIds.end());
354 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000355 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100356 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000357 {
358 updateReadings();
359 }
360 });
361 constexpr bool skipPropertiesChangedSignal = true;
362 dbusIface->initialize(skipPropertiesChangedSignal);
363 return dbusIface;
364}
365
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100366void Report::timerProcForPeriodicReport(boost::system::error_code ec,
367 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200368{
369 if (ec)
370 {
371 return;
372 }
373
374 self.updateReadings();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100375 self.scheduleTimerForPeriodicReport(self.interval);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200376}
377
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100378void Report::timerProcForOnChangeReport(boost::system::error_code ec,
379 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200380{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100381 if (ec)
382 {
383 return;
384 }
385
386 const auto ensure =
387 utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
388
389 self.onChangeContext.emplace(self);
390
391 const auto steadyTimestamp = self.clock->steadyTimestamp();
392
393 for (auto& metric : self.metrics)
394 {
395 metric->updateReadings(steadyTimestamp);
396 }
397
398 self.scheduleTimerForOnChangeReport();
399}
400
401void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
402{
403 if (!enabled)
404 {
405 return;
406 }
407
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200408 timer.expires_after(timerInterval);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100409 timer.async_wait([this](boost::system::error_code ec) {
410 timerProcForPeriodicReport(ec, *this);
411 });
412}
413
414void Report::scheduleTimerForOnChangeReport()
415{
416 if (!enabled)
417 {
418 return;
419 }
420
421 constexpr Milliseconds timerInterval{100};
422
423 timer.expires_after(timerInterval);
424 timer.async_wait([this](boost::system::error_code ec) {
425 timerProcForOnChangeReport(ec, *this);
426 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200427}
428
429void Report::updateReadings()
430{
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200431 if (!enabled)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000432 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200433 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000434 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200435
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100436 if (reportUpdates == ReportUpdates::overwrite ||
437 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200438 {
439 readingsBuffer.clear();
440 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000441
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200442 for (const auto& metric : metrics)
443 {
Szymon Dompke3eb56862021-09-20 15:32:04 +0200444 for (const auto& [id, metadata, value, timestamp] :
445 metric->getReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200446 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100447 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200448 readingsBuffer.isFull())
449 {
450 enabled = false;
Krzysztof Grobelnyfbeb5bf2022-01-03 09:41:29 +0100451 for (auto& m : metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200452 {
Krzysztof Grobelnyfbeb5bf2022-01-03 09:41:29 +0100453 m->deinitialize();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200454 }
455 break;
456 }
457 readingsBuffer.emplace(id, metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200458 }
459 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200460
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100461 readings = {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100462 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
463 .count(),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100464 std::vector<ReadingData>(readingsBuffer.begin(), readingsBuffer.end())};
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100465
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100466 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
467 {
468 reportIface->signal_property("Readings");
469 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200470}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100471
472bool Report::storeConfiguration() const
473{
474 try
475 {
476 nlohmann::json data;
477
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200478 data["Enabled"] = enabled;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100479 data["Version"] = reportVersion;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100480 data["Id"] = id;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100481 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100482 data["ReportingType"] = utils::toUnderlying(reportingType);
483 data["ReportActions"] =
484 utils::transform(reportActions, [](const auto reportAction) {
485 return utils::toUnderlying(reportAction);
486 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100487 data["Interval"] = interval.count();
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100488 data["AppendLimit"] =
489 appendLimit.value_or(std::numeric_limits<uint64_t>::max());
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100490 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000491 data["ReadingParameters"] =
492 utils::transform(metrics, [](const auto& metric) {
493 return metric->dumpConfiguration();
494 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100495
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100496 reportStorage.store(fileName(), data);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100497 }
498 catch (const std::exception& e)
499 {
500 phosphor::logging::log<phosphor::logging::level::ERR>(
501 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100502 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100503 return false;
504 }
505
506 return true;
507}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100508
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100509interfaces::JsonStorage::FilePath Report::fileName() const
510{
511 return interfaces::JsonStorage::FilePath{
512 std::to_string(std::hash<std::string>{}(id))};
513}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100514
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100515std::unordered_set<std::string>
516 Report::collectTriggerIds(boost::asio::io_context& ioc) const
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100517{
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100518 utils::Messanger tmp(ioc);
519
520 auto result = std::unordered_set<std::string>();
521
522 tmp.on_receive<messages::CollectTriggerIdResp>(
523 [&result](const auto& msg) { result.insert(msg.triggerId); });
524
525 tmp.send(messages::CollectTriggerIdReq{id});
526
527 return result;
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100528}
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100529
530void Report::metricUpdated()
531{
532 if (onChangeContext)
533 {
534 onChangeContext->metricUpdated();
535 return;
536 }
537
538 updateReadings();
539}
540
541void Report::updateReportingType(ReportingType newReportingType)
542{
543 if (reportingType != newReportingType)
544 {
545 timer.cancel();
546 unregisterFromMetrics = nullptr;
547 }
548
549 reportingType = newReportingType;
550
551 switch (reportingType)
552 {
553 case ReportingType::periodic:
554 {
555 scheduleTimerForPeriodicReport(interval);
556 break;
557 }
558 case ReportingType::onChange:
559 {
560 unregisterFromMetrics = [this] {
561 for (auto& metric : metrics)
562 {
563 metric->unregisterFromUpdates(*this);
564 }
565 };
566
567 bool isTimerRequired = false;
568
569 for (auto& metric : metrics)
570 {
571 metric->registerForUpdates(*this);
572 if (metric->isTimerRequired())
573 {
574 isTimerRequired = true;
575 }
576 }
577
578 if (isTimerRequired)
579 {
580 scheduleTimerForOnChangeReport();
581 }
582 break;
583 }
584 default:
585 break;
586 }
587}