blob: 9e69b62de99a30b5669bf77d5c141e05cace96a1 [file] [log] [blame]
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02001#include "report.hpp"
2
Krzysztof Grobelny62c08e92022-09-16 10:28:53 +02003#include "errors.hpp"
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +01004#include "messages/collect_trigger_id.hpp"
5#include "messages/trigger_presence_changed_ind.hpp"
6#include "messages/update_report_ind.hpp"
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02007#include "report_manager.hpp"
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +01008#include "utils/clock.hpp"
Krzysztof Grobelny51497a02021-11-09 14:56:22 +01009#include "utils/contains.hpp"
Szymon Dompke1cdd7e42022-06-08 14:43:13 +020010#include "utils/dbus_path_utils.hpp"
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010011#include "utils/ensure.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +010012#include "utils/transform.hpp"
13
14#include <phosphor-logging/log.hpp>
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +020015#include <sdbusplus/vtable.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020016
Szymon Dompke3eb56862021-09-20 15:32:04 +020017#include <limits>
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020018#include <numeric>
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +010019#include <optional>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020020
21Report::Report(boost::asio::io_context& ioc,
22 const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010023 const std::string& reportId, const std::string& reportName,
Szymon Dompke3eb56862021-09-20 15:32:04 +020024 const ReportingType reportingTypeIn,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010025 std::vector<ReportAction> reportActionsIn,
Szymon Dompke3eb56862021-09-20 15:32:04 +020026 const Milliseconds intervalIn, const uint64_t appendLimitIn,
27 const ReportUpdates reportUpdatesIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020028 interfaces::ReportManager& reportManager,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010029 interfaces::JsonStorage& reportStorageIn,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020030 std::vector<std::shared_ptr<interfaces::Metric>> metricsIn,
Szymon Dompkefdb06a12022-02-11 11:04:44 +010031 const interfaces::ReportFactory& reportFactory,
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010032 const bool enabledIn, std::unique_ptr<interfaces::Clock> clock,
33 Readings readingsIn) :
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010034 id(reportId),
Szymon Dompke1cdd7e42022-06-08 14:43:13 +020035 path(utils::pathAppend(utils::constants::reportDirPath, id)),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010036 name(reportName), reportingType(reportingTypeIn), interval(intervalIn),
Szymon Dompkefdb06a12022-02-11 11:04:44 +010037 reportActions(reportActionsIn.begin(), reportActionsIn.end()),
Krzysztof Grobelny18e71012022-11-02 13:17:01 +000038 metricCount(getMetricCount(metricsIn)), appendLimit(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 {
Krzysztof Grobelny62c08e92022-09-16 10:28:53 +0200147 reportIface->signal_property("ErrorMessages");
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200148 }
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 {
Krzysztof Grobelny62c08e92022-09-16 10:28:53 +0200163 reportIface->signal_property("ErrorMessages");
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200164 }
165}
166
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000167uint64_t Report::getMetricCount(
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{
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000170 uint64_t metricCount = 0;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200171 for (auto& metric : metrics)
172 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000173 metricCount += metric->metricCount();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200174 }
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000175 return metricCount;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200176}
177
178uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
179 const ReportingType reportingTypeIn) const
180{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100181 if (reportUpdatesIn == ReportUpdates::overwrite ||
182 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200183 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000184 return metricCount;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200185 }
186 else
187 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000188 return appendLimit;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200189 }
190}
191
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100192void Report::setReadingBuffer(const ReportUpdates newReportUpdates)
193{
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200194 const auto newBufferSize =
195 deduceBufferSize(newReportUpdates, reportingType);
196 if (readingsBuffer.size() != newBufferSize)
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100197 {
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200198 readingsBuffer.clearAndResize(newBufferSize);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100199 }
200}
201
Szymon Dompke3eb56862021-09-20 15:32:04 +0200202void Report::setReportUpdates(const ReportUpdates newReportUpdates)
203{
204 if (reportUpdates != newReportUpdates)
205 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100206 setReadingBuffer(newReportUpdates);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200207 reportUpdates = newReportUpdates;
208 }
209}
210
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100211std::unique_ptr<sdbusplus::asio::dbus_interface>
212 Report::makeReportInterface(const interfaces::ReportFactory& reportFactory)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000213{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100214 auto dbusIface =
215 objServer->add_unique_interface(getPath(), reportIfaceName);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200216 dbusIface->register_property_rw<bool>(
217 "Enabled", sdbusplus::vtable::property_::emits_change,
218 [this](bool newVal, auto& oldValue) {
219 if (newVal != state.get<ReportFlags::enabled>())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200220 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200221 state.set<ReportFlags::enabled>(oldValue = newVal);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200222
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200223 persistency = storeConfiguration();
224 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100225 return 1;
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200226 },
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200227 [this](const auto&) { return state.get<ReportFlags::enabled>(); });
228 dbusIface->register_property_r<
229 std::vector<std::tuple<std::string, std::string>>>(
230 "ErrorMessages", sdbusplus::vtable::property_::emits_change,
231 [this](const auto&) {
232 return utils::transform(errorMessages, [](const auto& em) {
233 return std::tuple<std::string, std::string>(
234 utils::enumToString(em.error), em.arg0);
235 });
236 });
237 dbusIface->register_property_rw<uint64_t>(
238 "Interval", sdbusplus::vtable::property_::emits_change,
239 [this](uint64_t newVal, auto& oldVal) {
240 const Milliseconds newValT{newVal};
241 if (newValT < ReportManager::minInterval &&
242 newValT != Milliseconds{0})
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000243 {
Krzysztof Grobelny62c08e92022-09-16 10:28:53 +0200244 throw errors::InvalidArgument("Interval");
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000245 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200246
247 if (newValT != interval)
248 {
249 oldVal = newVal;
250 interval = newValT;
251
252 errorMessages = verify();
253 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
254 StateEvent::active)
255 {
256 scheduleTimer();
257 }
258
259 persistency = storeConfiguration();
260 }
261 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000262 },
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000263 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200264 dbusIface->register_property_rw<bool>(
265 "Persistency", sdbusplus::vtable::property_::emits_change,
266 [this](bool newVal, auto& oldVal) {
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000267 if (newVal == persistency)
268 {
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100269 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000270 }
271 if (newVal)
272 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200273 persistency = oldVal = storeConfiguration();
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000274 }
275 else
276 {
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100277 reportStorage.remove(reportFileName());
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200278 persistency = oldVal = false;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000279 }
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100280 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000281 },
282 [this](const auto&) { return persistency; });
283
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100284 dbusIface->register_property_r("Readings", readings,
285 sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000286 [this](const auto&) { return readings; });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200287 dbusIface->register_property_rw<std::string>(
288 "ReportingType", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100289 [this](auto newVal, auto& oldVal) {
290 ReportingType tmp = utils::toReportingType(newVal);
291 if (tmp != reportingType)
292 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200293 reportingType = tmp;
294 oldVal = std::move(newVal);
295
296 errorMessages = verify();
297 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
298 StateEvent::active)
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100299 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200300 scheduleTimer();
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100301 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100302
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100303 persistency = storeConfiguration();
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200304
305 setReadingBuffer(reportUpdates);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100306 }
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100307 return 1;
308 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100309 [this](const auto&) { return utils::enumToString(reportingType); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000310 dbusIface->register_property_r(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000311 "ReadingParameters", readingParametersPastVersion,
312 sdbusplus::vtable::property_::const_,
313 [this](const auto&) { return readingParametersPastVersion; });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100314 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000315 "ReadingParametersFutureVersion", readingParameters,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100316 sdbusplus::vtable::property_::emits_change,
317 [this, &reportFactory](auto newVal, auto& oldVal) {
Szymon Dompke32305f12022-07-05 15:37:21 +0200318 auto labeledMetricParams =
319 reportFactory.convertMetricParams(newVal);
320 ReportManager::verifyMetricParameters(labeledMetricParams);
321 reportFactory.updateMetrics(metrics,
322 state.get<ReportFlags::enabled>(),
323 labeledMetricParams);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100324 readingParameters = toReadingParameters(
325 utils::transform(metrics, [](const auto& metric) {
326 return metric->dumpConfiguration();
327 }));
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000328 metricCount = getMetricCount(metrics);
Szymon Dompke892f7c82022-10-12 09:54:22 +0200329 setReadingBuffer(reportUpdates);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100330 persistency = storeConfiguration();
331 oldVal = std::move(newVal);
332 return 1;
333 },
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000334 [this](const auto&) { return readingParameters; });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200335 dbusIface->register_property_r<bool>(
336 "EmitsReadingsUpdate", sdbusplus::vtable::property_::none,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100337 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100338 return reportActions.contains(ReportAction::emitsReadingsUpdate);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100339 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200340 dbusIface->register_property_r<std::string>(
341 "Name", sdbusplus::vtable::property_::const_,
342 [this](const auto&) { return name; });
343 dbusIface->register_property_r<bool>(
344 "LogToMetricReportsCollection", sdbusplus::vtable::property_::const_,
345 [this](const auto&) {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100346 return reportActions.contains(
347 ReportAction::logToMetricReportsCollection);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100348 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200349 dbusIface->register_property_rw<std::vector<std::string>>(
350 "ReportActions", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100351 [this](auto newVal, auto& oldVal) {
352 auto tmp = utils::transform<std::unordered_set>(
353 newVal, [](const auto& reportAction) {
354 return utils::toReportAction(reportAction);
355 });
356 tmp.insert(ReportAction::logToMetricReportsCollection);
357
358 if (tmp != reportActions)
359 {
360 reportActions = tmp;
361 persistency = storeConfiguration();
362 oldVal = std::move(newVal);
363 }
364 return 1;
365 },
366 [this](const auto&) {
367 return utils::transform<std::vector>(
368 reportActions, [](const auto reportAction) {
369 return utils::enumToString(reportAction);
370 });
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100371 });
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000372 dbusIface->register_property_r<uint64_t>(
373 "AppendLimit", sdbusplus::vtable::property_::emits_change,
374 [this](const auto&) { return appendLimit; });
Szymon Dompke3eb56862021-09-20 15:32:04 +0200375 dbusIface->register_property_rw(
376 "ReportUpdates", std::string(),
377 sdbusplus::vtable::property_::emits_change,
378 [this](auto newVal, auto& oldVal) {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100379 setReportUpdates(utils::toReportUpdates(newVal));
Szymon Dompke3eb56862021-09-20 15:32:04 +0200380 oldVal = newVal;
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100381 return 1;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200382 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100383 [this](const auto&) { return utils::enumToString(reportUpdates); });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100384 dbusIface->register_property_r(
Szymon Dompke1cdd7e42022-06-08 14:43:13 +0200385 "Triggers", std::vector<sdbusplus::message::object_path>{},
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100386 sdbusplus::vtable::property_::emits_change, [this](const auto&) {
Szymon Dompke1cdd7e42022-06-08 14:43:13 +0200387 return utils::transform<std::vector>(
388 triggerIds, [](const auto& triggerId) {
389 return utils::pathAppend(utils::constants::triggerDirPath,
390 triggerId);
391 });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100392 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000393 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100394 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000395 {
396 updateReadings();
397 }
398 });
399 constexpr bool skipPropertiesChangedSignal = true;
400 dbusIface->initialize(skipPropertiesChangedSignal);
401 return dbusIface;
402}
403
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100404void Report::timerProcForPeriodicReport(boost::system::error_code ec,
405 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200406{
407 if (ec)
408 {
409 return;
410 }
411
412 self.updateReadings();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100413 self.scheduleTimerForPeriodicReport(self.interval);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200414}
415
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100416void Report::timerProcForOnChangeReport(boost::system::error_code ec,
417 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200418{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100419 if (ec)
420 {
421 return;
422 }
423
424 const auto ensure =
425 utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
426
427 self.onChangeContext.emplace(self);
428
429 const auto steadyTimestamp = self.clock->steadyTimestamp();
430
431 for (auto& metric : self.metrics)
432 {
433 metric->updateReadings(steadyTimestamp);
434 }
435
436 self.scheduleTimerForOnChangeReport();
437}
438
439void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
440{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200441 timer.expires_after(timerInterval);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100442 timer.async_wait([this](boost::system::error_code ec) {
443 timerProcForPeriodicReport(ec, *this);
444 });
445}
446
447void Report::scheduleTimerForOnChangeReport()
448{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100449 constexpr Milliseconds timerInterval{100};
450
451 timer.expires_after(timerInterval);
452 timer.async_wait([this](boost::system::error_code ec) {
453 timerProcForOnChangeReport(ec, *this);
454 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200455}
456
457void Report::updateReadings()
458{
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200459 if (!state.isActive())
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000460 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200461 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000462 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200463
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100464 if (reportUpdates == ReportUpdates::overwrite ||
465 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200466 {
467 readingsBuffer.clear();
468 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000469
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200470 for (const auto& metric : metrics)
471 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200472 if (!state.isActive())
473 {
474 break;
475 }
476
Szymon Dompke3eb56862021-09-20 15:32:04 +0200477 for (const auto& [id, metadata, value, timestamp] :
Krzysztof Grobelny9e8da542022-02-17 10:40:16 +0100478 metric->getUpdatedReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200479 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100480 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200481 readingsBuffer.isFull())
482 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200483 state.set<ReportFlags::enabled>(false);
484 reportIface->signal_property("Enabled");
Szymon Dompke3eb56862021-09-20 15:32:04 +0200485 break;
486 }
487 readingsBuffer.emplace(id, metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200488 }
489 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200490
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100491 std::get<0>(readings) =
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100492 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100493 .count();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100494
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100495 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
496 {
497 reportIface->signal_property("Readings");
498 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200499}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100500
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100501bool Report::shouldStoreMetricValues() const
502{
503 return reportingType != ReportingType::onRequest &&
504 reportUpdates == ReportUpdates::appendStopsWhenFull;
505}
506
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100507bool Report::storeConfiguration() const
508{
509 try
510 {
511 nlohmann::json data;
512
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200513 data["Enabled"] = state.get<ReportFlags::enabled>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100514 data["Version"] = reportVersion;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100515 data["Id"] = id;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100516 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100517 data["ReportingType"] = utils::toUnderlying(reportingType);
518 data["ReportActions"] =
519 utils::transform(reportActions, [](const auto reportAction) {
520 return utils::toUnderlying(reportAction);
521 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100522 data["Interval"] = interval.count();
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000523 data["AppendLimit"] = appendLimit;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100524 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000525 data["ReadingParameters"] =
526 utils::transform(metrics, [](const auto& metric) {
527 return metric->dumpConfiguration();
528 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100529
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100530 if (shouldStoreMetricValues())
531 {
532 data["MetricValues"] = utils::toLabeledReadings(readings);
533 }
534
535 reportStorage.store(reportFileName(), data);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100536 }
537 catch (const std::exception& e)
538 {
539 phosphor::logging::log<phosphor::logging::level::ERR>(
540 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100541 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100542 return false;
543 }
544
545 return true;
546}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100547
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100548interfaces::JsonStorage::FilePath Report::reportFileName() const
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100549{
550 return interfaces::JsonStorage::FilePath{
551 std::to_string(std::hash<std::string>{}(id))};
552}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100553
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100554std::unordered_set<std::string>
555 Report::collectTriggerIds(boost::asio::io_context& ioc) const
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100556{
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100557 utils::Messanger tmp(ioc);
558
559 auto result = std::unordered_set<std::string>();
560
561 tmp.on_receive<messages::CollectTriggerIdResp>(
562 [&result](const auto& msg) { result.insert(msg.triggerId); });
563
564 tmp.send(messages::CollectTriggerIdReq{id});
565
566 return result;
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100567}
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100568
569void Report::metricUpdated()
570{
571 if (onChangeContext)
572 {
573 onChangeContext->metricUpdated();
574 return;
575 }
576
577 updateReadings();
578}
579
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200580void Report::scheduleTimer()
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100581{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100582 switch (reportingType)
583 {
584 case ReportingType::periodic:
585 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200586 unregisterFromMetrics = nullptr;
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100587 scheduleTimerForPeriodicReport(interval);
588 break;
589 }
590 case ReportingType::onChange:
591 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200592 if (!unregisterFromMetrics)
593 {
594 unregisterFromMetrics = [this] {
595 for (auto& metric : metrics)
596 {
597 metric->unregisterFromUpdates(*this);
598 }
599 };
600
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100601 for (auto& metric : metrics)
602 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200603 metric->registerForUpdates(*this);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100604 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200605 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100606
607 bool isTimerRequired = false;
608
609 for (auto& metric : metrics)
610 {
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100611 if (metric->isTimerRequired())
612 {
613 isTimerRequired = true;
614 }
615 }
616
617 if (isTimerRequired)
618 {
619 scheduleTimerForOnChangeReport();
620 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200621 else
622 {
623 timer.cancel();
624 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100625 break;
626 }
627 default:
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200628 unregisterFromMetrics = nullptr;
629 timer.cancel();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100630 break;
631 }
632}
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200633
634std::vector<ErrorMessage> Report::verify() const
635{
636 std::vector<ErrorMessage> result;
637
638 if ((reportingType == ReportingType::periodic &&
639 interval == Milliseconds{0}) ||
640 (reportingType != ReportingType::periodic &&
641 interval != Milliseconds{0}))
642 {
643 result.emplace_back(ErrorType::propertyConflict, "Interval");
644 result.emplace_back(ErrorType::propertyConflict, "ReportingType");
645 }
646
647 return result;
648}