blob: 4d91787dfece61e691900503ece453834f55701d [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{
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010031 for (auto& metric : this->metrics)
32 {
33 metric->initialize();
34 }
35
Wludzik, Jozefe2362792020-10-27 17:23:55 +010036 deleteIface = objServer->add_unique_interface(
37 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
38 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
39 if (persistency)
40 {
41 reportStorage.remove(fileName);
42 }
43 boost::asio::post(ioc, [this, &reportManager] {
44 reportManager.removeReport(this);
45 });
46 });
47 });
48
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020049 reportIface = objServer->add_unique_interface(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010050 path, reportIfaceName, [this](auto& dbusIface) {
51 dbusIface.register_property_rw(
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020052 "Interval", static_cast<uint64_t>(interval.count()),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010053 sdbusplus::vtable::property_::emits_change,
54 [this](uint64_t newVal, auto&) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020055 std::chrono::milliseconds newValT(newVal);
56 if (newValT < ReportManager::minInterval)
57 {
58 return false;
59 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020060 interval = newValT;
61 return true;
Wludzik, Jozefe2362792020-10-27 17:23:55 +010062 },
63 [this](const auto&) {
64 return static_cast<uint64_t>(interval.count());
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020065 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010066 persistency = storeConfiguration();
67 dbusIface.register_property_rw(
68 "Persistency", persistency,
69 sdbusplus::vtable::property_::emits_change,
70 [this](bool newVal, const auto&) {
71 if (newVal == persistency)
72 {
73 return true;
74 }
75 if (newVal)
76 {
77 persistency = storeConfiguration();
78 }
79 else
80 {
81 reportStorage.remove(fileName);
82 persistency = false;
83 }
84 return true;
85 },
86 [this](const auto&) { return persistency; });
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +020087
88 auto readingsFlag = sdbusplus::vtable::property_::none;
89 if (emitsReadingsUpdate)
90 {
91 readingsFlag = sdbusplus::vtable::property_::emits_change;
92 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020093 dbusIface.register_property_r(
Wludzik, Jozefb1ff1f62020-10-23 13:20:52 +020094 "Readings", readings, readingsFlag,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020095 [this](const auto&) { return readings; });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010096 dbusIface.register_property_r(
97 "ReportingType", reportingType,
98 sdbusplus::vtable::property_::const_,
99 [this](const auto&) { return reportingType; });
100 dbusIface.register_property_r(
101 "ReadingParameters", readingParameters,
102 sdbusplus::vtable::property_::const_,
103 [this](const auto&) { return readingParameters; });
104 dbusIface.register_property_r(
105 "EmitsReadingsUpdate", emitsReadingsUpdate,
106 sdbusplus::vtable::property_::const_,
107 [this](const auto&) { return emitsReadingsUpdate; });
108 dbusIface.register_property_r(
109 "LogToMetricReportsCollection", logToMetricReportsCollection,
110 sdbusplus::vtable::property_::const_,
111 [this](const auto&) { return logToMetricReportsCollection; });
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +0100112 dbusIface.register_method("Update", [this] {
113 if (reportingType == "OnRequest")
114 {
115 updateReadings();
116 }
117 });
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200118 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200119
120 if (reportingType == "Periodic")
121 {
122 scheduleTimer(interval);
123 }
124}
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();
182 data["ReadingParameters"] = utils::transform(
183 metrics, [](const auto& metric) { return metric->to_json(); });
184
185 reportStorage.store(fileName, data);
186 }
187 catch (const std::exception& e)
188 {
189 phosphor::logging::log<phosphor::logging::level::ERR>(
190 "Failed to store a report in storage",
191 phosphor::logging::entry("msg=", e.what()));
192 return false;
193 }
194
195 return true;
196}