blob: 8a7297e55ce2b5e51e281a29c58d8e35003cfe1c [file] [log] [blame]
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02001#include "report.hpp"
2
3#include "report_manager.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01004#include "utils/transform.hpp"
5
6#include <phosphor-logging/log.hpp>
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +02007#include <sdbusplus/vtable.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02008
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +02009#include <numeric>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020010
11Report::Report(boost::asio::io_context& ioc,
12 const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010013 const std::string& reportName,
14 const std::string& reportingTypeIn,
15 const bool emitsReadingsUpdateIn,
16 const bool logToMetricReportsCollectionIn,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000017 const Milliseconds intervalIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020018 interfaces::ReportManager& reportManager,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010019 interfaces::JsonStorage& reportStorageIn,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000020 std::vector<std::shared_ptr<interfaces::Metric>> metricsIn) :
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020021 name(reportName),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010022 path(reportDir + name), reportingType(reportingTypeIn),
23 interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn),
24 logToMetricReportsCollection(logToMetricReportsCollectionIn),
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000025 objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010026 fileName(std::to_string(std::hash<std::string>{}(name))),
27 reportStorage(reportStorageIn)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020028{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000029 readingParameters =
30 toReadingParameters(utils::transform(metrics, [](const auto& metric) {
31 return metric->dumpConfiguration();
32 }));
33
34 readingParametersPastVersion =
35 utils::transform(readingParameters, [](const auto& item) {
36 return ReadingParametersPastVersion::value_type(
37 std::get<0>(item).front(), std::get<1>(item), std::get<2>(item),
38 std::get<3>(item));
39 });
40
Wludzik, Jozefe2362792020-10-27 17:23:55 +010041 deleteIface = objServer->add_unique_interface(
42 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
43 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
44 if (persistency)
45 {
46 reportStorage.remove(fileName);
47 }
48 boost::asio::post(ioc, [this, &reportManager] {
49 reportManager.removeReport(this);
50 });
51 });
52 });
53
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000054 persistency = storeConfiguration();
55 reportIface = makeReportInterface();
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020056
57 if (reportingType == "Periodic")
58 {
59 scheduleTimer(interval);
60 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000061
62 for (auto& metric : this->metrics)
63 {
64 metric->initialize();
65 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020066}
67
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000068std::unique_ptr<sdbusplus::asio::dbus_interface> Report::makeReportInterface()
69{
70 auto dbusIface = objServer->add_unique_interface(path, reportIfaceName);
71 dbusIface->register_property_rw(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000072 "Interval", interval.count(),
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000073 sdbusplus::vtable::property_::emits_change,
74 [this](uint64_t newVal, auto&) {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000075 Milliseconds newValT(newVal);
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000076 if (newValT < ReportManager::minInterval)
77 {
78 return false;
79 }
80 interval = newValT;
81 return true;
82 },
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000083 [this](const auto&) { return interval.count(); });
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000084 dbusIface->register_property_rw(
85 "Persistency", persistency, sdbusplus::vtable::property_::emits_change,
86 [this](bool newVal, const auto&) {
87 if (newVal == persistency)
88 {
89 return true;
90 }
91 if (newVal)
92 {
93 persistency = storeConfiguration();
94 }
95 else
96 {
97 reportStorage.remove(fileName);
98 persistency = false;
99 }
100 return true;
101 },
102 [this](const auto&) { return persistency; });
103
104 auto readingsFlag = sdbusplus::vtable::property_::none;
105 if (emitsReadingsUpdate)
106 {
107 readingsFlag = sdbusplus::vtable::property_::emits_change;
108 }
109 dbusIface->register_property_r("Readings", readings, readingsFlag,
110 [this](const auto&) { return readings; });
111 dbusIface->register_property_r(
112 "ReportingType", reportingType, sdbusplus::vtable::property_::const_,
113 [this](const auto&) { return reportingType; });
114 dbusIface->register_property_r(
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000115 "ReadingParameters", readingParametersPastVersion,
116 sdbusplus::vtable::property_::const_,
117 [this](const auto&) { return readingParametersPastVersion; });
118 dbusIface->register_property_r(
119 "ReadingParametersFutureVersion", readingParameters,
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +0000120 sdbusplus::vtable::property_::const_,
121 [this](const auto&) { return readingParameters; });
122 dbusIface->register_property_r(
123 "EmitsReadingsUpdate", emitsReadingsUpdate,
124 sdbusplus::vtable::property_::const_,
125 [this](const auto&) { return emitsReadingsUpdate; });
126 dbusIface->register_property_r(
127 "LogToMetricReportsCollection", logToMetricReportsCollection,
128 sdbusplus::vtable::property_::const_,
129 [this](const auto&) { return logToMetricReportsCollection; });
130 dbusIface->register_method("Update", [this] {
131 if (reportingType == "OnRequest")
132 {
133 updateReadings();
134 }
135 });
136 constexpr bool skipPropertiesChangedSignal = true;
137 dbusIface->initialize(skipPropertiesChangedSignal);
138 return dbusIface;
139}
140
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200141void Report::timerProc(boost::system::error_code ec, Report& self)
142{
143 if (ec)
144 {
145 return;
146 }
147
148 self.updateReadings();
149 self.scheduleTimer(self.interval);
150}
151
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000152void Report::scheduleTimer(Milliseconds timerInterval)
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200153{
154 timer.expires_after(timerInterval);
155 timer.async_wait(
156 [this](boost::system::error_code ec) { timerProc(ec, *this); });
157}
158
159void Report::updateReadings()
160{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000161 using ReadingsValue = std::tuple_element_t<1, Readings>;
162 std::get<ReadingsValue>(cachedReadings).clear();
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200163
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000164 for (const auto& metric : metrics)
165 {
166 for (const auto& reading : metric->getReadings())
167 {
168 std::get<1>(cachedReadings)
169 .emplace_back(reading.id, reading.metadata, reading.value,
170 reading.timestamp);
171 }
172 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200173
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000174 using ReadingsTimestamp = std::tuple_element_t<0, Readings>;
175 std::get<ReadingsTimestamp>(cachedReadings) = std::time(0);
176
177 std::swap(readings, cachedReadings);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100178
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200179 reportIface->signal_property("Readings");
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200180}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100181
182bool Report::storeConfiguration() const
183{
184 try
185 {
186 nlohmann::json data;
187
188 data["Version"] = reportVersion;
189 data["Name"] = name;
190 data["ReportingType"] = reportingType;
191 data["EmitsReadingsUpdate"] = emitsReadingsUpdate;
192 data["LogToMetricReportsCollection"] = logToMetricReportsCollection;
193 data["Interval"] = interval.count();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000194 data["ReadingParameters"] =
195 utils::transform(metrics, [](const auto& metric) {
196 return metric->dumpConfiguration();
197 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100198
199 reportStorage.store(fileName, data);
200 }
201 catch (const std::exception& e)
202 {
203 phosphor::logging::log<phosphor::logging::level::ERR>(
204 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100205 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100206 return false;
207 }
208
209 return true;
210}