blob: be98c6dd918a608d07ef64191110acd88b814069 [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),
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020042 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 Grobelny973b4bb2022-04-25 17:07:27 +020078 errorMessages = verify();
79 state.set<ReportFlags::enabled, ReportFlags::valid>(enabledIn,
80 errorMessages.empty());
81
Szymon Dompkefdb06a12022-02-11 11:04:44 +010082 reportIface = makeReportInterface(reportFactory);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020083 persistency = storeConfiguration();
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010084
85 messanger.on_receive<messages::TriggerPresenceChangedInd>(
86 [this](const auto& msg) {
87 const auto oldSize = triggerIds.size();
88
89 if (msg.presence == messages::Presence::Exist)
90 {
91 if (utils::contains(msg.reportIds, id))
92 {
93 triggerIds.insert(msg.triggerId);
94 }
95 else if (!utils::contains(msg.reportIds, id))
96 {
97 triggerIds.erase(msg.triggerId);
98 }
99 }
100 else if (msg.presence == messages::Presence::Removed)
101 {
102 triggerIds.erase(msg.triggerId);
103 }
104
105 if (triggerIds.size() != oldSize)
106 {
107 reportIface->signal_property("TriggerIds");
108 }
109 });
110
111 messanger.on_receive<messages::UpdateReportInd>([this](const auto& msg) {
112 if (utils::contains(msg.reportIds, id))
113 {
114 updateReadings();
115 }
116 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200117}
118
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100119Report::~Report()
120{
121 if (persistency)
122 {
123 if (shouldStoreMetricValues())
124 {
125 storeConfiguration();
126 }
127 }
128 else
129 {
130 reportStorage.remove(reportFileName());
131 }
132}
133
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200134void Report::activate()
135{
136 for (auto& metric : this->metrics)
137 {
138 metric->initialize();
139 }
140
141 scheduleTimer();
142
143 if (reportIface)
144 {
145 reportIface->signal_property("errors");
146 }
147}
148
149void Report::deactivate()
150{
151 for (auto& metric : metrics)
152 {
153 metric->deinitialize();
154 }
155
156 unregisterFromMetrics = nullptr;
157 timer.cancel();
158
159 if (reportIface)
160 {
161 reportIface->signal_property("Errors");
162 }
163}
164
Szymon Dompke3eb56862021-09-20 15:32:04 +0200165uint64_t Report::getSensorCount(
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100166 const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200167{
168 uint64_t sensorCount = 0;
169 for (auto& metric : metrics)
170 {
171 sensorCount += metric->sensorCount();
172 }
173 return sensorCount;
174}
175
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100176std::optional<uint64_t>
177 Report::deduceAppendLimit(const uint64_t appendLimitIn) const
Szymon Dompke3eb56862021-09-20 15:32:04 +0200178{
179 if (appendLimitIn == std::numeric_limits<uint64_t>::max())
180 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100181 return std::nullopt;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200182 }
183 else
184 {
185 return appendLimitIn;
186 }
187}
188
189uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
190 const ReportingType reportingTypeIn) const
191{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100192 if (reportUpdatesIn == ReportUpdates::overwrite ||
193 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200194 {
195 return sensorCount;
196 }
197 else
198 {
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100199 return appendLimit.value_or(sensorCount);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200200 }
201}
202
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100203void Report::setReadingBuffer(const ReportUpdates newReportUpdates)
204{
205 if (reportingType != ReportingType::onRequest &&
206 (reportUpdates == ReportUpdates::overwrite ||
207 newReportUpdates == ReportUpdates::overwrite))
208 {
209 readingsBuffer.clearAndResize(
210 deduceBufferSize(newReportUpdates, reportingType));
211 }
212}
213
Szymon Dompke3eb56862021-09-20 15:32:04 +0200214void Report::setReportUpdates(const ReportUpdates newReportUpdates)
215{
216 if (reportUpdates != newReportUpdates)
217 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100218 setReadingBuffer(newReportUpdates);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200219 reportUpdates = newReportUpdates;
220 }
221}
222
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100223std::unique_ptr<sdbusplus::asio::dbus_interface>
224 Report::makeReportInterface(const interfaces::ReportFactory& reportFactory)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000225{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100226 auto dbusIface =
227 objServer->add_unique_interface(getPath(), reportIfaceName);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200228 dbusIface->register_property_rw<bool>(
229 "Enabled", sdbusplus::vtable::property_::emits_change,
230 [this](bool newVal, auto& oldValue) {
231 if (newVal != state.get<ReportFlags::enabled>())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200232 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200233 state.set<ReportFlags::enabled>(oldValue = newVal);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200234
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200235 persistency = storeConfiguration();
236 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100237 return 1;
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200238 },
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200239 [this](const auto&) { return state.get<ReportFlags::enabled>(); });
240 dbusIface->register_property_r<
241 std::vector<std::tuple<std::string, std::string>>>(
242 "ErrorMessages", sdbusplus::vtable::property_::emits_change,
243 [this](const auto&) {
244 return utils::transform(errorMessages, [](const auto& em) {
245 return std::tuple<std::string, std::string>(
246 utils::enumToString(em.error), em.arg0);
247 });
248 });
249 dbusIface->register_property_rw<uint64_t>(
250 "Interval", sdbusplus::vtable::property_::emits_change,
251 [this](uint64_t newVal, auto& oldVal) {
252 const Milliseconds newValT{newVal};
253 if (newValT < ReportManager::minInterval &&
254 newValT != Milliseconds{0})
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000255 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200256 throw sdbusplus::exception::SdBusError(
257 static_cast<int>(std::errc::invalid_argument),
258 "Invalid interval");
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000259 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200260
261 if (newValT != interval)
262 {
263 oldVal = newVal;
264 interval = newValT;
265
266 errorMessages = verify();
267 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
268 StateEvent::active)
269 {
270 scheduleTimer();
271 }
272
273 persistency = storeConfiguration();
274 }
275 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000276 },
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000277 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200278 dbusIface->register_property_rw<bool>(
279 "Persistency", sdbusplus::vtable::property_::emits_change,
280 [this](bool newVal, auto& oldVal) {
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000281 if (newVal == persistency)
282 {
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100283 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000284 }
285 if (newVal)
286 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200287 persistency = oldVal = storeConfiguration();
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000288 }
289 else
290 {
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100291 reportStorage.remove(reportFileName());
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200292 persistency = oldVal = false;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000293 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100294 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000295 },
296 [this](const auto&) { return persistency; });
297
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100298 dbusIface->register_property_r("Readings", readings,
299 sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000300 [this](const auto&) { return readings; });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200301 dbusIface->register_property_rw<std::string>(
302 "ReportingType", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100303 [this](auto newVal, auto& oldVal) {
304 ReportingType tmp = utils::toReportingType(newVal);
305 if (tmp != reportingType)
306 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200307 reportingType = tmp;
308 oldVal = std::move(newVal);
309
310 errorMessages = verify();
311 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
312 StateEvent::active)
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100313 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200314 scheduleTimer();
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100315 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100316
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100317 persistency = storeConfiguration();
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200318
319 setReadingBuffer(reportUpdates);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100320 }
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100321 return 1;
322 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100323 [this](const auto&) { return utils::enumToString(reportingType); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000324 dbusIface->register_property_r(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000325 "ReadingParameters", readingParametersPastVersion,
326 sdbusplus::vtable::property_::const_,
327 [this](const auto&) { return readingParametersPastVersion; });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100328 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000329 "ReadingParametersFutureVersion", readingParameters,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100330 sdbusplus::vtable::property_::emits_change,
331 [this, &reportFactory](auto newVal, auto& oldVal) {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200332 reportFactory.updateMetrics(
333 metrics, state.get<ReportFlags::enabled>(), newVal);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100334 readingParameters = toReadingParameters(
335 utils::transform(metrics, [](const auto& metric) {
336 return metric->dumpConfiguration();
337 }));
338 persistency = storeConfiguration();
339 oldVal = std::move(newVal);
340 return 1;
341 },
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000342 [this](const auto&) { return readingParameters; });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200343 dbusIface->register_property_r<bool>(
344 "EmitsReadingsUpdate", sdbusplus::vtable::property_::none,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100345 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100346 return reportActions.contains(ReportAction::emitsReadingsUpdate);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100347 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200348 dbusIface->register_property_r<std::string>(
349 "Name", sdbusplus::vtable::property_::const_,
350 [this](const auto&) { return name; });
351 dbusIface->register_property_r<bool>(
352 "LogToMetricReportsCollection", sdbusplus::vtable::property_::const_,
353 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100354 return reportActions.contains(
355 ReportAction::logToMetricReportsCollection);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100356 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200357 dbusIface->register_property_rw<std::vector<std::string>>(
358 "ReportActions", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100359 [this](auto newVal, auto& oldVal) {
360 auto tmp = utils::transform<std::unordered_set>(
361 newVal, [](const auto& reportAction) {
362 return utils::toReportAction(reportAction);
363 });
364 tmp.insert(ReportAction::logToMetricReportsCollection);
365
366 if (tmp != reportActions)
367 {
368 reportActions = tmp;
369 persistency = storeConfiguration();
370 oldVal = std::move(newVal);
371 }
372 return 1;
373 },
374 [this](const auto&) {
375 return utils::transform<std::vector>(
376 reportActions, [](const auto reportAction) {
377 return utils::enumToString(reportAction);
378 });
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100379 });
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100380 dbusIface->register_property_r(
381 "AppendLimit", appendLimit.value_or(sensorCount),
382 sdbusplus::vtable::property_::emits_change,
383 [this](const auto&) { return appendLimit.value_or(sensorCount); });
Szymon Dompke3eb56862021-09-20 15:32:04 +0200384 dbusIface->register_property_rw(
385 "ReportUpdates", std::string(),
386 sdbusplus::vtable::property_::emits_change,
387 [this](auto newVal, auto& oldVal) {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100388 setReportUpdates(utils::toReportUpdates(newVal));
Szymon Dompke3eb56862021-09-20 15:32:04 +0200389 oldVal = newVal;
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100390 return 1;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200391 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100392 [this](const auto&) { return utils::enumToString(reportUpdates); });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100393 dbusIface->register_property_r(
394 "TriggerIds", std::vector<std::string>{},
395 sdbusplus::vtable::property_::emits_change, [this](const auto&) {
396 return std::vector<std::string>(triggerIds.begin(),
397 triggerIds.end());
398 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000399 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100400 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000401 {
402 updateReadings();
403 }
404 });
405 constexpr bool skipPropertiesChangedSignal = true;
406 dbusIface->initialize(skipPropertiesChangedSignal);
407 return dbusIface;
408}
409
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100410void Report::timerProcForPeriodicReport(boost::system::error_code ec,
411 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200412{
413 if (ec)
414 {
415 return;
416 }
417
418 self.updateReadings();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100419 self.scheduleTimerForPeriodicReport(self.interval);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200420}
421
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100422void Report::timerProcForOnChangeReport(boost::system::error_code ec,
423 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200424{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100425 if (ec)
426 {
427 return;
428 }
429
430 const auto ensure =
431 utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
432
433 self.onChangeContext.emplace(self);
434
435 const auto steadyTimestamp = self.clock->steadyTimestamp();
436
437 for (auto& metric : self.metrics)
438 {
439 metric->updateReadings(steadyTimestamp);
440 }
441
442 self.scheduleTimerForOnChangeReport();
443}
444
445void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
446{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200447 timer.expires_after(timerInterval);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100448 timer.async_wait([this](boost::system::error_code ec) {
449 timerProcForPeriodicReport(ec, *this);
450 });
451}
452
453void Report::scheduleTimerForOnChangeReport()
454{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100455 constexpr Milliseconds timerInterval{100};
456
457 timer.expires_after(timerInterval);
458 timer.async_wait([this](boost::system::error_code ec) {
459 timerProcForOnChangeReport(ec, *this);
460 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200461}
462
463void Report::updateReadings()
464{
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200465 if (!state.isActive())
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000466 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200467 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000468 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200469
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100470 if (reportUpdates == ReportUpdates::overwrite ||
471 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200472 {
473 readingsBuffer.clear();
474 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000475
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200476 for (const auto& metric : metrics)
477 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200478 if (!state.isActive())
479 {
480 break;
481 }
482
Szymon Dompke3eb56862021-09-20 15:32:04 +0200483 for (const auto& [id, metadata, value, timestamp] :
Krzysztof Grobelny9e8da542022-02-17 10:40:16 +0100484 metric->getUpdatedReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200485 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100486 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200487 readingsBuffer.isFull())
488 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200489 state.set<ReportFlags::enabled>(false);
490 reportIface->signal_property("Enabled");
Szymon Dompke3eb56862021-09-20 15:32:04 +0200491 break;
492 }
493 readingsBuffer.emplace(id, metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200494 }
495 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200496
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100497 std::get<0>(readings) =
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100498 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100499 .count();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100500
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100501 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
502 {
503 reportIface->signal_property("Readings");
504 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200505}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100506
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100507bool Report::shouldStoreMetricValues() const
508{
509 return reportingType != ReportingType::onRequest &&
510 reportUpdates == ReportUpdates::appendStopsWhenFull;
511}
512
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100513bool Report::storeConfiguration() const
514{
515 try
516 {
517 nlohmann::json data;
518
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200519 data["Enabled"] = state.get<ReportFlags::enabled>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100520 data["Version"] = reportVersion;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100521 data["Id"] = id;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100522 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100523 data["ReportingType"] = utils::toUnderlying(reportingType);
524 data["ReportActions"] =
525 utils::transform(reportActions, [](const auto reportAction) {
526 return utils::toUnderlying(reportAction);
527 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100528 data["Interval"] = interval.count();
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100529 data["AppendLimit"] =
530 appendLimit.value_or(std::numeric_limits<uint64_t>::max());
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100531 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000532 data["ReadingParameters"] =
533 utils::transform(metrics, [](const auto& metric) {
534 return metric->dumpConfiguration();
535 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100536
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100537 if (shouldStoreMetricValues())
538 {
539 data["MetricValues"] = utils::toLabeledReadings(readings);
540 }
541
542 reportStorage.store(reportFileName(), data);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100543 }
544 catch (const std::exception& e)
545 {
546 phosphor::logging::log<phosphor::logging::level::ERR>(
547 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100548 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100549 return false;
550 }
551
552 return true;
553}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100554
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100555interfaces::JsonStorage::FilePath Report::reportFileName() const
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100556{
557 return interfaces::JsonStorage::FilePath{
558 std::to_string(std::hash<std::string>{}(id))};
559}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100560
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100561std::unordered_set<std::string>
562 Report::collectTriggerIds(boost::asio::io_context& ioc) const
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100563{
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100564 utils::Messanger tmp(ioc);
565
566 auto result = std::unordered_set<std::string>();
567
568 tmp.on_receive<messages::CollectTriggerIdResp>(
569 [&result](const auto& msg) { result.insert(msg.triggerId); });
570
571 tmp.send(messages::CollectTriggerIdReq{id});
572
573 return result;
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100574}
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100575
576void Report::metricUpdated()
577{
578 if (onChangeContext)
579 {
580 onChangeContext->metricUpdated();
581 return;
582 }
583
584 updateReadings();
585}
586
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200587void Report::scheduleTimer()
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100588{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100589 switch (reportingType)
590 {
591 case ReportingType::periodic:
592 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200593 unregisterFromMetrics = nullptr;
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100594 scheduleTimerForPeriodicReport(interval);
595 break;
596 }
597 case ReportingType::onChange:
598 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200599 if (!unregisterFromMetrics)
600 {
601 unregisterFromMetrics = [this] {
602 for (auto& metric : metrics)
603 {
604 metric->unregisterFromUpdates(*this);
605 }
606 };
607
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100608 for (auto& metric : metrics)
609 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200610 metric->registerForUpdates(*this);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100611 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200612 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100613
614 bool isTimerRequired = false;
615
616 for (auto& metric : metrics)
617 {
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100618 if (metric->isTimerRequired())
619 {
620 isTimerRequired = true;
621 }
622 }
623
624 if (isTimerRequired)
625 {
626 scheduleTimerForOnChangeReport();
627 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200628 else
629 {
630 timer.cancel();
631 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100632 break;
633 }
634 default:
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200635 unregisterFromMetrics = nullptr;
636 timer.cancel();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100637 break;
638 }
639}
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200640
641std::vector<ErrorMessage> Report::verify() const
642{
643 std::vector<ErrorMessage> result;
644
645 if ((reportingType == ReportingType::periodic &&
646 interval == Milliseconds{0}) ||
647 (reportingType != ReportingType::periodic &&
648 interval != Milliseconds{0}))
649 {
650 result.emplace_back(ErrorType::propertyConflict, "Interval");
651 result.emplace_back(ErrorType::propertyConflict, "ReportingType");
652 }
653
654 return result;
655}