blob: 21302b426f5c684b73dc0e1cf706068b8663e72f [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) :
Patrick Williamsf535cad2024-08-16 15:21:20 -040034 id(reportId), path(utils::pathAppend(utils::constants::reportDirPath, id)),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010035 name(reportName), reportingType(reportingTypeIn), interval(intervalIn),
Szymon Dompkefdb06a12022-02-11 11:04:44 +010036 reportActions(reportActionsIn.begin(), reportActionsIn.end()),
Krzysztof Grobelny18e71012022-11-02 13:17:01 +000037 metricCount(getMetricCount(metricsIn)), appendLimit(appendLimitIn),
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010038 reportUpdates(reportUpdatesIn), readings(std::move(readingsIn)),
39 readingsBuffer(std::get<1>(readings),
40 deduceBufferSize(reportUpdates, reportingType)),
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000041 objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010042 triggerIds(collectTriggerIds(ioc)), reportStorage(reportStorageIn),
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020043 clock(std::move(clock)), messanger(ioc)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020044{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000045 readingParameters =
46 toReadingParameters(utils::transform(metrics, [](const auto& metric) {
Patrick Williamsc7935fa2023-10-20 11:19:30 -050047 return metric->dumpConfiguration();
48 }));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000049
Szymon Dompkefdb06a12022-02-11 11:04:44 +010050 reportActions.insert(ReportAction::logToMetricReportsCollection);
51
Wludzik, Jozefe2362792020-10-27 17:23:55 +010052 deleteIface = objServer->add_unique_interface(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010053 getPath(), deleteIfaceName,
54 [this, &ioc, &reportManager](auto& dbusIface) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050055 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
56 if (persistency)
57 {
58 persistency = false;
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010059
Patrick Williams3a1c2972023-05-10 07:51:04 -050060 reportIface->signal_property("Persistency");
61 }
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +010062
Patrick Williams3a1c2972023-05-10 07:51:04 -050063 boost::asio::post(ioc, [this, &reportManager] {
64 reportManager.removeReport(this);
Wludzik, Jozefe2362792020-10-27 17:23:55 +010065 });
66 });
Patrick Williamsc7935fa2023-10-20 11:19:30 -050067 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010068
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +000069 auto errorMessages = verify(reportingType, interval);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020070 state.set<ReportFlags::enabled, ReportFlags::valid>(enabledIn,
71 errorMessages.empty());
72
Szymon Dompkefdb06a12022-02-11 11:04:44 +010073 reportIface = makeReportInterface(reportFactory);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +020074 persistency = storeConfiguration();
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010075
76 messanger.on_receive<messages::TriggerPresenceChangedInd>(
77 [this](const auto& msg) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050078 const auto oldSize = triggerIds.size();
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010079
Patrick Williams3a1c2972023-05-10 07:51:04 -050080 if (msg.presence == messages::Presence::Exist)
81 {
82 if (utils::contains(msg.reportIds, id))
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010083 {
Patrick Williams3a1c2972023-05-10 07:51:04 -050084 triggerIds.insert(msg.triggerId);
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010085 }
Patrick Williams3a1c2972023-05-10 07:51:04 -050086 else if (!utils::contains(msg.reportIds, id))
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010087 {
88 triggerIds.erase(msg.triggerId);
89 }
Patrick Williams3a1c2972023-05-10 07:51:04 -050090 }
91 else if (msg.presence == messages::Presence::Removed)
92 {
93 triggerIds.erase(msg.triggerId);
94 }
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010095
Patrick Williams3a1c2972023-05-10 07:51:04 -050096 if (triggerIds.size() != oldSize)
97 {
98 reportIface->signal_property("Triggers");
99 }
100 });
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100101
102 messanger.on_receive<messages::UpdateReportInd>([this](const auto& msg) {
103 if (utils::contains(msg.reportIds, id))
104 {
105 updateReadings();
106 }
107 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200108}
109
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100110Report::~Report()
111{
112 if (persistency)
113 {
114 if (shouldStoreMetricValues())
115 {
116 storeConfiguration();
117 }
118 }
119 else
120 {
121 reportStorage.remove(reportFileName());
122 }
123}
124
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200125void Report::activate()
126{
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000127 for (auto& metric : metrics)
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200128 {
129 metric->initialize();
130 }
131
132 scheduleTimer();
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200133}
134
135void Report::deactivate()
136{
137 for (auto& metric : metrics)
138 {
139 metric->deinitialize();
140 }
141
142 unregisterFromMetrics = nullptr;
143 timer.cancel();
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200144}
145
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000146uint64_t Report::getMetricCount(
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100147 const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200148{
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000149 uint64_t metricCount = 0;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200150 for (auto& metric : metrics)
151 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000152 metricCount += metric->metricCount();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200153 }
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000154 return metricCount;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200155}
156
157uint64_t Report::deduceBufferSize(const ReportUpdates reportUpdatesIn,
158 const ReportingType reportingTypeIn) const
159{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100160 if (reportUpdatesIn == ReportUpdates::overwrite ||
161 reportingTypeIn == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200162 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000163 return metricCount;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200164 }
165 else
166 {
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000167 return appendLimit;
Szymon Dompke3eb56862021-09-20 15:32:04 +0200168 }
169}
170
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100171void Report::setReadingBuffer(const ReportUpdates newReportUpdates)
172{
Patrick Williams3a1c2972023-05-10 07:51:04 -0500173 const auto newBufferSize = deduceBufferSize(newReportUpdates,
174 reportingType);
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200175 if (readingsBuffer.size() != newBufferSize)
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100176 {
Krzysztof Grobelnya8182be2022-07-04 11:26:20 +0200177 readingsBuffer.clearAndResize(newBufferSize);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100178 }
179}
180
Szymon Dompke3eb56862021-09-20 15:32:04 +0200181void Report::setReportUpdates(const ReportUpdates newReportUpdates)
182{
183 if (reportUpdates != newReportUpdates)
184 {
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100185 setReadingBuffer(newReportUpdates);
Szymon Dompke3eb56862021-09-20 15:32:04 +0200186 reportUpdates = newReportUpdates;
187 }
188}
189
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100190std::unique_ptr<sdbusplus::asio::dbus_interface>
191 Report::makeReportInterface(const interfaces::ReportFactory& reportFactory)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000192{
Patrick Williams3a1c2972023-05-10 07:51:04 -0500193 auto dbusIface = objServer->add_unique_interface(getPath(),
194 reportIfaceName);
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200195 dbusIface->register_property_rw<bool>(
196 "Enabled", sdbusplus::vtable::property_::emits_change,
197 [this](bool newVal, auto& oldValue) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500198 if (newVal != state.get<ReportFlags::enabled>())
199 {
200 state.set<ReportFlags::enabled>(oldValue = newVal);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200201
Patrick Williams3a1c2972023-05-10 07:51:04 -0500202 persistency = storeConfiguration();
203 }
204 return 1;
Patrick Williamsf535cad2024-08-16 15:21:20 -0400205 }, [this](const auto&) { return state.get<ReportFlags::enabled>(); });
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000206 dbusIface->register_method(
207 "SetReportingProperties",
208 [this](std::string newReportingType, uint64_t newInterval) {
209 ReportingType newReportingTypeT = reportingType;
210
211 if (!newReportingType.empty())
Patrick Williams3a1c2972023-05-10 07:51:04 -0500212 {
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000213 newReportingTypeT = utils::toReportingType(newReportingType);
Patrick Williams3a1c2972023-05-10 07:51:04 -0500214 }
215
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000216 Milliseconds newIntervalT = interval;
Patrick Williams3a1c2972023-05-10 07:51:04 -0500217
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000218 if (newInterval != std::numeric_limits<uint64_t>::max())
219 {
220 newIntervalT = Milliseconds(newInterval);
221 }
222
223 auto errorMessages = verify(newReportingTypeT, newIntervalT);
224
225 if (!errorMessages.empty())
226 {
227 if (newIntervalT != interval)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000228 {
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000229 throw errors::InvalidArgument("Interval");
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000230 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200231
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000232 throw errors::InvalidArgument("ReportingType");
Patrick Williams3a1c2972023-05-10 07:51:04 -0500233 }
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000234
235 if (reportingType != newReportingTypeT)
236 {
237 reportingType = newReportingTypeT;
238 reportIface->signal_property("ReportingType");
239 }
240
241 if (interval != newIntervalT)
242 {
243 interval = newIntervalT;
244 reportIface->signal_property("Interval");
245 }
246
247 if (state.set<ReportFlags::valid>(errorMessages.empty()) ==
248 StateEvent::active)
249 {
250 scheduleTimer();
251 }
252
253 persistency = storeConfiguration();
254
255 setReadingBuffer(reportUpdates);
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500256 });
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000257 dbusIface->register_property_r<uint64_t>(
258 "Interval", sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000259 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200260 dbusIface->register_property_rw<bool>(
261 "Persistency", sdbusplus::vtable::property_::emits_change,
262 [this](bool newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500263 if (newVal == persistency)
264 {
Szymon Dompke3e2cc9d2021-12-14 12:00:52 +0100265 return 1;
Patrick Williams3a1c2972023-05-10 07:51:04 -0500266 }
267 if (newVal)
268 {
269 persistency = oldVal = storeConfiguration();
270 }
271 else
272 {
273 reportStorage.remove(reportFileName());
274 persistency = oldVal = false;
275 }
276 return 1;
Patrick Williamsf535cad2024-08-16 15:21:20 -0400277 }, [this](const auto&) { return persistency; });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000278
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100279 dbusIface->register_property_r("Readings", readings,
280 sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000281 [this](const auto&) { return readings; });
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000282 dbusIface->register_property_r<std::string>(
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200283 "ReportingType", sdbusplus::vtable::property_::emits_change,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100284 [this](const auto&) { return utils::enumToString(reportingType); });
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100285 dbusIface->register_property_rw(
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000286 "ReadingParameters", readingParameters,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100287 sdbusplus::vtable::property_::emits_change,
288 [this, &reportFactory](auto newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500289 auto labeledMetricParams = reportFactory.convertMetricParams(newVal);
Michal Orzel5e7cbf42024-08-01 15:44:42 +0200290 ReportManager::verifyMetricParams(labeledMetricParams);
Patrick Williams3a1c2972023-05-10 07:51:04 -0500291 reportFactory.updateMetrics(metrics, state.get<ReportFlags::enabled>(),
292 labeledMetricParams);
293 readingParameters = toReadingParameters(
294 utils::transform(metrics, [](const auto& metric) {
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500295 return metric->dumpConfiguration();
296 }));
Patrick Williams3a1c2972023-05-10 07:51:04 -0500297 metricCount = getMetricCount(metrics);
298 setReadingBuffer(reportUpdates);
299 persistency = storeConfiguration();
300 oldVal = std::move(newVal);
301 return 1;
Patrick Williamsf535cad2024-08-16 15:21:20 -0400302 }, [this](const auto&) { return readingParameters; });
Patrick Williams3a1c2972023-05-10 07:51:04 -0500303 dbusIface->register_property_r<bool>("EmitsReadingsUpdate",
304 sdbusplus::vtable::property_::none,
305 [this](const auto&) {
306 return reportActions.contains(ReportAction::emitsReadingsUpdate);
307 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200308 dbusIface->register_property_r<std::string>(
309 "Name", sdbusplus::vtable::property_::const_,
310 [this](const auto&) { return name; });
Patrick Williams3a1c2972023-05-10 07:51:04 -0500311 dbusIface->register_property_r<bool>("LogToMetricReportsCollection",
312 sdbusplus::vtable::property_::const_,
313 [this](const auto&) {
314 return reportActions.contains(
315 ReportAction::logToMetricReportsCollection);
316 });
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200317 dbusIface->register_property_rw<std::vector<std::string>>(
318 "ReportActions", sdbusplus::vtable::property_::emits_change,
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100319 [this](auto newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500320 auto tmp = utils::transform<std::unordered_set>(
321 newVal, [](const auto& reportAction) {
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500322 return utils::toReportAction(reportAction);
323 });
Patrick Williams3a1c2972023-05-10 07:51:04 -0500324 tmp.insert(ReportAction::logToMetricReportsCollection);
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100325
Patrick Williams3a1c2972023-05-10 07:51:04 -0500326 if (tmp != reportActions)
327 {
328 reportActions = tmp;
329 persistency = storeConfiguration();
330 oldVal = std::move(newVal);
331 }
332 return 1;
Patrick Williamsf535cad2024-08-16 15:21:20 -0400333 }, [this](const auto&) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500334 return utils::transform<std::vector>(reportActions,
335 [](const auto reportAction) {
336 return utils::enumToString(reportAction);
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100337 });
Patrick Williams3a1c2972023-05-10 07:51:04 -0500338 });
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000339 dbusIface->register_property_r<uint64_t>(
340 "AppendLimit", sdbusplus::vtable::property_::emits_change,
341 [this](const auto&) { return appendLimit; });
Patrick Williamsf535cad2024-08-16 15:21:20 -0400342 dbusIface->register_property_rw("ReportUpdates", std::string(),
343 sdbusplus::vtable::property_::emits_change,
344 [this](auto newVal, auto& oldVal) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500345 setReportUpdates(utils::toReportUpdates(newVal));
346 oldVal = newVal;
347 return 1;
Patrick Williamsf535cad2024-08-16 15:21:20 -0400348 }, [this](const auto&) { return utils::enumToString(reportUpdates); });
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100349 dbusIface->register_property_r(
Szymon Dompke1cdd7e42022-06-08 14:43:13 +0200350 "Triggers", std::vector<sdbusplus::message::object_path>{},
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100351 sdbusplus::vtable::property_::emits_change, [this](const auto&) {
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500352 return utils::transform<std::vector>(triggerIds,
353 [](const auto& triggerId) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500354 return utils::pathAppend(utils::constants::triggerDirPath,
355 triggerId);
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100356 });
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500357 });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000358 dbusIface->register_method("Update", [this] {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100359 if (reportingType == ReportingType::onRequest)
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000360 {
361 updateReadings();
362 }
363 });
364 constexpr bool skipPropertiesChangedSignal = true;
365 dbusIface->initialize(skipPropertiesChangedSignal);
366 return dbusIface;
367}
368
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100369void Report::timerProcForPeriodicReport(boost::system::error_code ec,
370 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200371{
372 if (ec)
373 {
374 return;
375 }
376
377 self.updateReadings();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100378 self.scheduleTimerForPeriodicReport(self.interval);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200379}
380
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100381void Report::timerProcForOnChangeReport(boost::system::error_code ec,
382 Report& self)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200383{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100384 if (ec)
385 {
386 return;
387 }
388
389 const auto ensure =
390 utils::Ensure{[&self] { self.onChangeContext = std::nullopt; }};
391
392 self.onChangeContext.emplace(self);
393
394 const auto steadyTimestamp = self.clock->steadyTimestamp();
395
396 for (auto& metric : self.metrics)
397 {
398 metric->updateReadings(steadyTimestamp);
399 }
400
401 self.scheduleTimerForOnChangeReport();
402}
403
404void Report::scheduleTimerForPeriodicReport(Milliseconds timerInterval)
405{
Wojciech Tempczyk38c64092023-10-05 12:28:55 +0200406 try
407 {
408 timer.expires_after(timerInterval);
409 timer.async_wait([this](boost::system::error_code ec) {
410 timerProcForPeriodicReport(ec, *this);
411 });
412 }
413 catch (const boost::system::system_error& exception)
414 {
415 phosphor::logging::log<phosphor::logging::level::ERR>(
416 "Failed to schedule timer for periodic report: ",
417 phosphor::logging::entry("EXCEPTION_MSG=%s", exception.what()));
418 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100419}
420
421void Report::scheduleTimerForOnChangeReport()
422{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100423 constexpr Milliseconds timerInterval{100};
424
425 timer.expires_after(timerInterval);
426 timer.async_wait([this](boost::system::error_code ec) {
427 timerProcForOnChangeReport(ec, *this);
428 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200429}
430
431void Report::updateReadings()
432{
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200433 if (!state.isActive())
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000434 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200435 return;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000436 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200437
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100438 if (reportUpdates == ReportUpdates::overwrite ||
439 reportingType == ReportingType::onRequest)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200440 {
441 readingsBuffer.clear();
442 }
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000443
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200444 for (const auto& metric : metrics)
445 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200446 if (!state.isActive())
447 {
448 break;
449 }
450
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000451 for (const auto& [metadata, value, timestamp] :
Krzysztof Grobelny9e8da542022-02-17 10:40:16 +0100452 metric->getUpdatedReadings())
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200453 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100454 if (reportUpdates == ReportUpdates::appendStopsWhenFull &&
Szymon Dompke3eb56862021-09-20 15:32:04 +0200455 readingsBuffer.isFull())
456 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200457 state.set<ReportFlags::enabled>(false);
458 reportIface->signal_property("Enabled");
Szymon Dompke3eb56862021-09-20 15:32:04 +0200459 break;
460 }
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000461 readingsBuffer.emplace(metadata, value, timestamp);
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200462 }
463 }
Szymon Dompke3eb56862021-09-20 15:32:04 +0200464
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100465 std::get<0>(readings) =
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100466 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100467 .count();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100468
Szymon Dompkefdb06a12022-02-11 11:04:44 +0100469 if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
470 {
471 reportIface->signal_property("Readings");
472 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200473}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100474
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100475bool Report::shouldStoreMetricValues() const
476{
477 return reportingType != ReportingType::onRequest &&
478 reportUpdates == ReportUpdates::appendStopsWhenFull;
479}
480
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100481bool Report::storeConfiguration() const
482{
483 try
484 {
485 nlohmann::json data;
486
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200487 data["Enabled"] = state.get<ReportFlags::enabled>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100488 data["Version"] = reportVersion;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100489 data["Id"] = id;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100490 data["Name"] = name;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100491 data["ReportingType"] = utils::toUnderlying(reportingType);
Patrick Williams3a1c2972023-05-10 07:51:04 -0500492 data["ReportActions"] = utils::transform(reportActions,
493 [](const auto reportAction) {
494 return utils::toUnderlying(reportAction);
495 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100496 data["Interval"] = interval.count();
Krzysztof Grobelny18e71012022-11-02 13:17:01 +0000497 data["AppendLimit"] = appendLimit;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100498 data["ReportUpdates"] = utils::toUnderlying(reportUpdates);
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500499 data["ReadingParameters"] = utils::transform(
500 metrics,
501 [](const auto& metric) { return metric->dumpConfiguration(); });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100502
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100503 if (shouldStoreMetricValues())
504 {
505 data["MetricValues"] = utils::toLabeledReadings(readings);
506 }
507
508 reportStorage.store(reportFileName(), data);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100509 }
510 catch (const std::exception& e)
511 {
512 phosphor::logging::log<phosphor::logging::level::ERR>(
513 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100514 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100515 return false;
516 }
517
518 return true;
519}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100520
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100521interfaces::JsonStorage::FilePath Report::reportFileName() const
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100522{
523 return interfaces::JsonStorage::FilePath{
524 std::to_string(std::hash<std::string>{}(id))};
525}
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100526
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100527std::unordered_set<std::string>
528 Report::collectTriggerIds(boost::asio::io_context& ioc) const
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100529{
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +0100530 utils::Messanger tmp(ioc);
531
532 auto result = std::unordered_set<std::string>();
533
534 tmp.on_receive<messages::CollectTriggerIdResp>(
535 [&result](const auto& msg) { result.insert(msg.triggerId); });
536
537 tmp.send(messages::CollectTriggerIdReq{id});
538
539 return result;
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100540}
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100541
542void Report::metricUpdated()
543{
544 if (onChangeContext)
545 {
546 onChangeContext->metricUpdated();
547 return;
548 }
549
550 updateReadings();
551}
552
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200553void Report::scheduleTimer()
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100554{
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100555 switch (reportingType)
556 {
557 case ReportingType::periodic:
558 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200559 unregisterFromMetrics = nullptr;
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100560 scheduleTimerForPeriodicReport(interval);
561 break;
562 }
563 case ReportingType::onChange:
564 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200565 if (!unregisterFromMetrics)
566 {
567 unregisterFromMetrics = [this] {
568 for (auto& metric : metrics)
569 {
570 metric->unregisterFromUpdates(*this);
571 }
572 };
573
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100574 for (auto& metric : metrics)
575 {
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200576 metric->registerForUpdates(*this);
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100577 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200578 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100579
580 bool isTimerRequired = false;
581
582 for (auto& metric : metrics)
583 {
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100584 if (metric->isTimerRequired())
585 {
586 isTimerRequired = true;
587 }
588 }
589
590 if (isTimerRequired)
591 {
592 scheduleTimerForOnChangeReport();
593 }
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200594 else
595 {
596 timer.cancel();
597 }
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100598 break;
599 }
600 default:
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200601 unregisterFromMetrics = nullptr;
602 timer.cancel();
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100603 break;
604 }
605}
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200606
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000607std::vector<ErrorMessage> Report::verify(ReportingType reportingType,
608 Milliseconds interval)
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200609{
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000610 if (interval != Milliseconds{0} && interval < ReportManager::minInterval)
611 {
612 throw errors::InvalidArgument("Interval");
613 }
614
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200615 std::vector<ErrorMessage> result;
616
617 if ((reportingType == ReportingType::periodic &&
618 interval == Milliseconds{0}) ||
619 (reportingType != ReportingType::periodic &&
620 interval != Milliseconds{0}))
621 {
622 result.emplace_back(ErrorType::propertyConflict, "Interval");
623 result.emplace_back(ErrorType::propertyConflict, "ReportingType");
624 }
625
626 return result;
627}