blob: c480675cd4d108e746bb244b2830b1bdc45b60e2 [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
Szymon Dompkefdb06a12022-02-11 11:04:44 +010051 reportActions.insert(ReportAction::logToMetricReportsCollection);
52
Wludzik, Jozefe2362792020-10-27 17:23:55 +010053 deleteIface = objServer->add_unique_interface(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010054 getPath(), deleteIfaceName,
55 [this, &ioc, &reportManager](auto& dbusIface) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050056 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
57 if (persistency)
58 {
59 persistency = false;
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010060
Patrick Williams3a1c2972023-05-10 07:51:04 -050061 reportIface->signal_property("Persistency");
62 }
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010063
Patrick Williams3a1c2972023-05-10 07:51:04 -050064 boost::asio::post(ioc, [this, &reportManager] {
65 reportManager.removeReport(this);
Wludzik, Jozefe2362792020-10-27 17:23:55 +010066 });
67 });
Patrick Williams3a1c2972023-05-10 07:51:04 -050068 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010069
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +000070 auto errorMessages = verify(reportingType, interval);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020071 state.set<ReportFlags::enabled, ReportFlags::valid>(enabledIn,
72 errorMessages.empty());
73
Szymon Dompkefdb06a12022-02-11 11:04:44 +010074 reportIface = makeReportInterface(reportFactory);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020075 persistency = storeConfiguration();
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010076
77 messanger.on_receive<messages::TriggerPresenceChangedInd>(
78 [this](const auto& msg) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050079 const auto oldSize = triggerIds.size();
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010080
Patrick Williams3a1c2972023-05-10 07:51:04 -050081 if (msg.presence == messages::Presence::Exist)
82 {
83 if (utils::contains(msg.reportIds, id))
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010084 {
Patrick Williams3a1c2972023-05-10 07:51:04 -050085 triggerIds.insert(msg.triggerId);
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010086 }
Patrick Williams3a1c2972023-05-10 07:51:04 -050087 else if (!utils::contains(msg.reportIds, id))
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010088 {
89 triggerIds.erase(msg.triggerId);
90 }
Patrick Williams3a1c2972023-05-10 07:51:04 -050091 }
92 else if (msg.presence == messages::Presence::Removed)
93 {
94 triggerIds.erase(msg.triggerId);
95 }
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010096
Patrick Williams3a1c2972023-05-10 07:51:04 -050097 if (triggerIds.size() != oldSize)
98 {
99 reportIface->signal_property("Triggers");
100 }
101 });
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100102
103 messanger.on_receive<messages::UpdateReportInd>([this](const auto& msg) {
104 if (utils::contains(msg.reportIds, id))
105 {
106 updateReadings();
107 }
108 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200109}
110
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100111Report::~Report()
112{
113 if (persistency)
114 {
115 if (shouldStoreMetricValues())
116 {
117 storeConfiguration();
118 }
119 }
120 else
121 {
122 reportStorage.remove(reportFileName());
123 }
124}
125
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200126void Report::activate()
127{
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000128 for (auto& metric : metrics)
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200129 {
130 metric->initialize();
131 }
132
133 scheduleTimer();
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200134}
135
136void Report::deactivate()
137{
138 for (auto& metric : metrics)
139 {
140 metric->deinitialize();
141 }
142
143 unregisterFromMetrics = nullptr;
144 timer.cancel();
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200145}
146
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000147uint64_t Report::getMetricCount(
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100148 const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200149{
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000150 uint64_t metricCount = 0;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200151 for (auto& metric : metrics)
152 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000153 metricCount += metric->metricCount();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200154 }
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000155 return metricCount;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200156}
157
158uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
159 const ReportingType reportingTypeIn) const
160{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100161 if (reportUpdatesIn == ReportUpdates::overwrite ||
162 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200163 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000164 return metricCount;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200165 }
166 else
167 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000168 return appendLimit;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200169 }
170}
171
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100172void Report::setReadingBuffer(const ReportUpdates newReportUpdates)
173{
Patrick Williams3a1c2972023-05-10 07:51:04 -0500174 const auto newBufferSize = deduceBufferSize(newReportUpdates,
175 reportingType);
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200176 if (readingsBuffer.size() != newBufferSize)
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100177 {
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200178 readingsBuffer.clearAndResize(newBufferSize);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100179 }
180}
181
Szymon Dompke3eb56862021-09-20 15:32:04 +0200182void Report::setReportUpdates(const ReportUpdates newReportUpdates)
183{
184 if (reportUpdates != newReportUpdates)
185 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100186 setReadingBuffer(newReportUpdates);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200187 reportUpdates = newReportUpdates;
188 }
189}
190
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100191std::unique_ptr<sdbusplus::asio::dbus_interface>
192 Report::makeReportInterface(const interfaces::ReportFactory& reportFactory)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000193{
Patrick Williams3a1c2972023-05-10 07:51:04 -0500194 auto dbusIface = objServer->add_unique_interface(getPath(),
195 reportIfaceName);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200196 dbusIface->register_property_rw<bool>(
197 "Enabled", sdbusplus::vtable::property_::emits_change,
198 [this](bool newVal, auto& oldValue) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500199 if (newVal != state.get<ReportFlags::enabled>())
200 {
201 state.set<ReportFlags::enabled>(oldValue = newVal);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200202
Patrick Williams3a1c2972023-05-10 07:51:04 -0500203 persistency = storeConfiguration();
204 }
205 return 1;
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200206 },
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200207 [this](const auto&) { return state.get<ReportFlags::enabled>(); });
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000208 dbusIface->register_method(
209 "SetReportingProperties",
210 [this](std::string newReportingType, uint64_t newInterval) {
211 ReportingType newReportingTypeT = reportingType;
212
213 if (!newReportingType.empty())
Patrick Williams3a1c2972023-05-10 07:51:04 -0500214 {
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000215 newReportingTypeT = utils::toReportingType(newReportingType);
Patrick Williams3a1c2972023-05-10 07:51:04 -0500216 }
217
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000218 Milliseconds newIntervalT = interval;
Patrick Williams3a1c2972023-05-10 07:51:04 -0500219
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000220 if (newInterval != std::numeric_limits<uint64_t>::max())
221 {
222 newIntervalT = Milliseconds(newInterval);
223 }
224
225 auto errorMessages = verify(newReportingTypeT, newIntervalT);
226
227 if (!errorMessages.empty())
228 {
229 if (newIntervalT != interval)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000230 {
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000231 throw errors::InvalidArgument("Interval");
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000232 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200233
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000234 throw errors::InvalidArgument("ReportingType");
Patrick Williams3a1c2972023-05-10 07:51:04 -0500235 }
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000236
237 if (reportingType != newReportingTypeT)
238 {
239 reportingType = newReportingTypeT;
240 reportIface->signal_property("ReportingType");
241 }
242
243 if (interval != newIntervalT)
244 {
245 interval = newIntervalT;
246 reportIface->signal_property("Interval");
247 }
248
249 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
250 StateEvent::active)
251 {
252 scheduleTimer();
253 }
254
255 persistency = storeConfiguration();
256
257 setReadingBuffer(reportUpdates);
258 });
259 dbusIface->register_property_r<uint64_t>(
260 "Interval", sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000261 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200262 dbusIface->register_property_rw<bool>(
263 "Persistency", sdbusplus::vtable::property_::emits_change,
264 [this](bool newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500265 if (newVal == persistency)
266 {
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100267 return 1;
Patrick Williams3a1c2972023-05-10 07:51:04 -0500268 }
269 if (newVal)
270 {
271 persistency = oldVal = storeConfiguration();
272 }
273 else
274 {
275 reportStorage.remove(reportFileName());
276 persistency = oldVal = false;
277 }
278 return 1;
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000279 },
280 [this](const auto&) { return persistency; });
281
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100282 dbusIface->register_property_r("Readings", readings,
283 sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000284 [this](const auto&) { return readings; });
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000285 dbusIface->register_property_r<std::string>(
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200286 "ReportingType", sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100287 [this](const auto&) { return utils::enumToString(reportingType); });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100288 dbusIface->register_property_rw(
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000289 "ReadingParameters", readingParameters,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100290 sdbusplus::vtable::property_::emits_change,
291 [this, &reportFactory](auto newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500292 auto labeledMetricParams = reportFactory.convertMetricParams(newVal);
Patrick Williams3a1c2972023-05-10 07:51:04 -0500293 reportFactory.updateMetrics(metrics, state.get<ReportFlags::enabled>(),
294 labeledMetricParams);
295 readingParameters = toReadingParameters(
296 utils::transform(metrics, [](const auto& metric) {
297 return metric->dumpConfiguration();
298 }));
299 metricCount = getMetricCount(metrics);
300 setReadingBuffer(reportUpdates);
301 persistency = storeConfiguration();
302 oldVal = std::move(newVal);
303 return 1;
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100304 },
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000305 [this](const auto&) { return readingParameters; });
Patrick Williams3a1c2972023-05-10 07:51:04 -0500306 dbusIface->register_property_r<bool>("EmitsReadingsUpdate",
307 sdbusplus::vtable::property_::none,
308 [this](const auto&) {
309 return reportActions.contains(ReportAction::emitsReadingsUpdate);
310 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200311 dbusIface->register_property_r<std::string>(
312 "Name", sdbusplus::vtable::property_::const_,
313 [this](const auto&) { return name; });
Patrick Williams3a1c2972023-05-10 07:51:04 -0500314 dbusIface->register_property_r<bool>("LogToMetricReportsCollection",
315 sdbusplus::vtable::property_::const_,
316 [this](const auto&) {
317 return reportActions.contains(
318 ReportAction::logToMetricReportsCollection);
319 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200320 dbusIface->register_property_rw<std::vector<std::string>>(
321 "ReportActions", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100322 [this](auto newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500323 auto tmp = utils::transform<std::unordered_set>(
324 newVal, [](const auto& reportAction) {
325 return utils::toReportAction(reportAction);
326 });
327 tmp.insert(ReportAction::logToMetricReportsCollection);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100328
Patrick Williams3a1c2972023-05-10 07:51:04 -0500329 if (tmp != reportActions)
330 {
331 reportActions = tmp;
332 persistency = storeConfiguration();
333 oldVal = std::move(newVal);
334 }
335 return 1;
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100336 },
337 [this](const auto&) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500338 return utils::transform<std::vector>(reportActions,
339 [](const auto reportAction) {
340 return utils::enumToString(reportAction);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100341 });
Patrick Williams3a1c2972023-05-10 07:51:04 -0500342 });
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000343 dbusIface->register_property_r<uint64_t>(
344 "AppendLimit", sdbusplus::vtable::property_::emits_change,
345 [this](const auto&) { return appendLimit; });
Szymon Dompke3eb56862021-09-20 15:32:04 +0200346 dbusIface->register_property_rw(
347 "ReportUpdates", std::string(),
348 sdbusplus::vtable::property_::emits_change,
349 [this](auto newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500350 setReportUpdates(utils::toReportUpdates(newVal));
351 oldVal = newVal;
352 return 1;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200353 },
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100354 [this](const auto&) { return utils::enumToString(reportUpdates); });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100355 dbusIface->register_property_r(
Szymon Dompke1cdd7e42022-06-08 14:43:13 +0200356 "Triggers", std::vector<sdbusplus::message::object_path>{},
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100357 sdbusplus::vtable::property_::emits_change, [this](const auto&) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500358 return utils::transform<std::vector>(triggerIds,
359 [](const auto& triggerId) {
360 return utils::pathAppend(utils::constants::triggerDirPath,
361 triggerId);
362 });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100363 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000364 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100365 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000366 {
367 updateReadings();
368 }
369 });
370 constexpr bool skipPropertiesChangedSignal = true;
371 dbusIface->initialize(skipPropertiesChangedSignal);
372 return dbusIface;
373}
374
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100375void Report::timerProcForPeriodicReport(boost::system::error_code ec,
376 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200377{
378 if (ec)
379 {
380 return;
381 }
382
383 self.updateReadings();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100384 self.scheduleTimerForPeriodicReport(self.interval);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200385}
386
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100387void Report::timerProcForOnChangeReport(boost::system::error_code ec,
388 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200389{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100390 if (ec)
391 {
392 return;
393 }
394
395 const auto ensure =
396 utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
397
398 self.onChangeContext.emplace(self);
399
400 const auto steadyTimestamp = self.clock->steadyTimestamp();
401
402 for (auto& metric : self.metrics)
403 {
404 metric->updateReadings(steadyTimestamp);
405 }
406
407 self.scheduleTimerForOnChangeReport();
408}
409
410void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
411{
Wojciech Tempczyk38c64092023-10-05 12:28:55 +0200412 try
413 {
414 timer.expires_after(timerInterval);
415 timer.async_wait([this](boost::system::error_code ec) {
416 timerProcForPeriodicReport(ec, *this);
417 });
418 }
419 catch (const boost::system::system_error& exception)
420 {
421 phosphor::logging::log<phosphor::logging::level::ERR>(
422 "Failed to schedule timer for periodic report: ",
423 phosphor::logging::entry("EXCEPTION_MSG=%s", exception.what()));
424 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100425}
426
427void Report::scheduleTimerForOnChangeReport()
428{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100429 constexpr Milliseconds timerInterval{100};
430
431 timer.expires_after(timerInterval);
432 timer.async_wait([this](boost::system::error_code ec) {
433 timerProcForOnChangeReport(ec, *this);
434 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200435}
436
437void Report::updateReadings()
438{
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200439 if (!state.isActive())
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000440 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200441 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000442 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200443
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100444 if (reportUpdates == ReportUpdates::overwrite ||
445 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200446 {
447 readingsBuffer.clear();
448 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000449
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200450 for (const auto& metric : metrics)
451 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200452 if (!state.isActive())
453 {
454 break;
455 }
456
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000457 for (const auto& [metadata, value, timestamp] :
Krzysztof Grobelny9e8da542022-02-17 10:40:16 +0100458 metric->getUpdatedReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200459 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100460 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200461 readingsBuffer.isFull())
462 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200463 state.set<ReportFlags::enabled>(false);
464 reportIface->signal_property("Enabled");
Szymon Dompke3eb56862021-09-20 15:32:04 +0200465 break;
466 }
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000467 readingsBuffer.emplace(metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200468 }
469 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200470
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100471 std::get<0>(readings) =
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100472 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100473 .count();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100474
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100475 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
476 {
477 reportIface->signal_property("Readings");
478 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200479}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100480
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100481bool Report::shouldStoreMetricValues() const
482{
483 return reportingType != ReportingType::onRequest &&
484 reportUpdates == ReportUpdates::appendStopsWhenFull;
485}
486
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100487bool Report::storeConfiguration() const
488{
489 try
490 {
491 nlohmann::json data;
492
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200493 data["Enabled"] = state.get<ReportFlags::enabled>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100494 data["Version"] = reportVersion;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100495 data["Id"] = id;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100496 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100497 data["ReportingType"] = utils::toUnderlying(reportingType);
Patrick Williams3a1c2972023-05-10 07:51:04 -0500498 data["ReportActions"] = utils::transform(reportActions,
499 [](const auto reportAction) {
500 return utils::toUnderlying(reportAction);
501 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100502 data["Interval"] = interval.count();
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000503 data["AppendLimit"] = appendLimit;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100504 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Patrick Williams3a1c2972023-05-10 07:51:04 -0500505 data["ReadingParameters"] = utils::transform(metrics,
506 [](const auto& metric) {
507 return metric->dumpConfiguration();
508 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100509
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100510 if (shouldStoreMetricValues())
511 {
512 data["MetricValues"] = utils::toLabeledReadings(readings);
513 }
514
515 reportStorage.store(reportFileName(), data);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100516 }
517 catch (const std::exception& e)
518 {
519 phosphor::logging::log<phosphor::logging::level::ERR>(
520 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100521 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100522 return false;
523 }
524
525 return true;
526}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100527
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100528interfaces::JsonStorage::FilePath Report::reportFileName() const
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100529{
530 return interfaces::JsonStorage::FilePath{
531 std::to_string(std::hash<std::string>{}(id))};
532}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100533
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100534std::unordered_set<std::string>
535 Report::collectTriggerIds(boost::asio::io_context& ioc) const
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100536{
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100537 utils::Messanger tmp(ioc);
538
539 auto result = std::unordered_set<std::string>();
540
541 tmp.on_receive<messages::CollectTriggerIdResp>(
542 [&result](const auto& msg) { result.insert(msg.triggerId); });
543
544 tmp.send(messages::CollectTriggerIdReq{id});
545
546 return result;
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100547}
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100548
549void Report::metricUpdated()
550{
551 if (onChangeContext)
552 {
553 onChangeContext->metricUpdated();
554 return;
555 }
556
557 updateReadings();
558}
559
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200560void Report::scheduleTimer()
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100561{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100562 switch (reportingType)
563 {
564 case ReportingType::periodic:
565 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200566 unregisterFromMetrics = nullptr;
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100567 scheduleTimerForPeriodicReport(interval);
568 break;
569 }
570 case ReportingType::onChange:
571 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200572 if (!unregisterFromMetrics)
573 {
574 unregisterFromMetrics = [this] {
575 for (auto& metric : metrics)
576 {
577 metric->unregisterFromUpdates(*this);
578 }
579 };
580
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100581 for (auto& metric : metrics)
582 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200583 metric->registerForUpdates(*this);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100584 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200585 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100586
587 bool isTimerRequired = false;
588
589 for (auto& metric : metrics)
590 {
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100591 if (metric->isTimerRequired())
592 {
593 isTimerRequired = true;
594 }
595 }
596
597 if (isTimerRequired)
598 {
599 scheduleTimerForOnChangeReport();
600 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200601 else
602 {
603 timer.cancel();
604 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100605 break;
606 }
607 default:
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200608 unregisterFromMetrics = nullptr;
609 timer.cancel();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100610 break;
611 }
612}
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200613
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000614std::vector<ErrorMessage> Report::verify(ReportingType reportingType,
615 Milliseconds interval)
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200616{
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000617 if (interval != Milliseconds{0} && interval < ReportManager::minInterval)
618 {
619 throw errors::InvalidArgument("Interval");
620 }
621
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200622 std::vector<ErrorMessage> result;
623
624 if ((reportingType == ReportingType::periodic &&
625 interval == Milliseconds{0}) ||
626 (reportingType != ReportingType::periodic &&
627 interval != Milliseconds{0}))
628 {
629 result.emplace_back(ErrorType::propertyConflict, "Interval");
630 result.emplace_back(ErrorType::propertyConflict, "ReportingType");
631 }
632
633 return result;
634}