blob: dc8f37b60abf21d183ea3b46b15465e4b7ff6cfb [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,
17 const std::chrono::milliseconds intervalIn,
18 const ReadingParameters& readingParametersIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020019 interfaces::ReportManager& reportManager,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010020 interfaces::JsonStorage& reportStorageIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020021 std::vector<std::shared_ptr<interfaces::Metric>> metrics) :
22 name(reportName),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010023 path(reportDir + name), reportingType(reportingTypeIn),
24 interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn),
25 logToMetricReportsCollection(logToMetricReportsCollectionIn),
26 readingParameters(readingParametersIn), objServer(objServer),
27 metrics(std::move(metrics)), timer(ioc),
28 fileName(std::to_string(std::hash<std::string>{}(name))),
29 reportStorage(reportStorageIn)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020030{
Wludzik, Jozefe2362792020-10-27 17:23:55 +010031 deleteIface = objServer->add_unique_interface(
32 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
33 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
34 if (persistency)
35 {
36 reportStorage.remove(fileName);
37 }
38 boost::asio::post(ioc, [this, &reportManager] {
39 reportManager.removeReport(this);
40 });
41 });
42 });
43
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020044 reportIface = objServer->add_unique_interface(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010045 path, reportIfaceName, [this](auto& dbusIface) {
46 dbusIface.register_property_rw(
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020047 "Interval", static_cast<uint64_t>(interval.count()),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010048 sdbusplus::vtable::property_::emits_change,
49 [this](uint64_t newVal, auto&) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020050 std::chrono::milliseconds newValT(newVal);
51 if (newValT < ReportManager::minInterval)
52 {
53 return false;
54 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020055 interval = newValT;
56 return true;
Wludzik, Jozefe2362792020-10-27 17:23:55 +010057 },
58 [this](const auto&) {
59 return static_cast<uint64_t>(interval.count());
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020060 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010061 persistency = storeConfiguration();
62 dbusIface.register_property_rw(
63 "Persistency", persistency,
64 sdbusplus::vtable::property_::emits_change,
65 [this](bool newVal, const auto&) {
66 if (newVal == persistency)
67 {
68 return true;
69 }
70 if (newVal)
71 {
72 persistency = storeConfiguration();
73 }
74 else
75 {
76 reportStorage.remove(fileName);
77 persistency = false;
78 }
79 return true;
80 },
81 [this](const auto&) { return persistency; });
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +020082
83 auto readingsFlag = sdbusplus::vtable::property_::none;
84 if (emitsReadingsUpdate)
85 {
86 readingsFlag = sdbusplus::vtable::property_::emits_change;
87 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020088 dbusIface.register_property_r(
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +020089 "Readings", readings, readingsFlag,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020090 [this](const auto&) { return readings; });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010091 dbusIface.register_property_r(
92 "ReportingType", reportingType,
93 sdbusplus::vtable::property_::const_,
94 [this](const auto&) { return reportingType; });
95 dbusIface.register_property_r(
96 "ReadingParameters", readingParameters,
97 sdbusplus::vtable::property_::const_,
98 [this](const auto&) { return readingParameters; });
99 dbusIface.register_property_r(
100 "EmitsReadingsUpdate", emitsReadingsUpdate,
101 sdbusplus::vtable::property_::const_,
102 [this](const auto&) { return emitsReadingsUpdate; });
103 dbusIface.register_property_r(
104 "LogToMetricReportsCollection", logToMetricReportsCollection,
105 sdbusplus::vtable::property_::const_,
106 [this](const auto&) { return logToMetricReportsCollection; });
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +0100107 dbusIface.register_method("Update", [this] {
108 if (reportingType == "OnRequest")
109 {
110 updateReadings();
111 }
112 });
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200113 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200114
115 if (reportingType == "Periodic")
116 {
117 scheduleTimer(interval);
118 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000119
120 for (auto& metric : this->metrics)
121 {
122 metric->initialize();
123 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200124}
125
126void Report::timerProc(boost::system::error_code ec, Report& self)
127{
128 if (ec)
129 {
130 return;
131 }
132
133 self.updateReadings();
134 self.scheduleTimer(self.interval);
135}
136
137void Report::scheduleTimer(std::chrono::milliseconds timerInterval)
138{
139 timer.expires_after(timerInterval);
140 timer.async_wait(
141 [this](boost::system::error_code ec) { timerProc(ec, *this); });
142}
143
144void Report::updateReadings()
145{
146 auto numElements = std::accumulate(
147 metrics.begin(), metrics.end(), 0u, [](auto sum, const auto& metric) {
148 return sum + metric->getReadings().size();
149 });
150
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100151 std::tuple_element_t<1, Readings> readingsCache(numElements);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200152
153 auto it = readingsCache.begin();
154
155 for (const auto& metric : metrics)
156 {
157 for (const auto& reading : metric->getReadings())
158 {
159 *(it++) = std::make_tuple(reading.id, reading.metadata,
160 reading.value, reading.timestamp);
161 }
162 }
163
164 std::get<0>(readings) = std::time(0);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100165 std::get<1>(readings) = std::move(readingsCache);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100166
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200167 reportIface->signal_property("Readings");
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200168}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100169
170bool Report::storeConfiguration() const
171{
172 try
173 {
174 nlohmann::json data;
175
176 data["Version"] = reportVersion;
177 data["Name"] = name;
178 data["ReportingType"] = reportingType;
179 data["EmitsReadingsUpdate"] = emitsReadingsUpdate;
180 data["LogToMetricReportsCollection"] = logToMetricReportsCollection;
181 data["Interval"] = interval.count();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000182 data["ReadingParameters"] =
183 utils::transform(metrics, [](const auto& metric) {
184 return metric->dumpConfiguration();
185 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100186
187 reportStorage.store(fileName, data);
188 }
189 catch (const std::exception& e)
190 {
191 phosphor::logging::log<phosphor::logging::level::ERR>(
192 "Failed to store a report in storage",
193 phosphor::logging::entry("msg=", e.what()));
194 return false;
195 }
196
197 return true;
198}