blob: c1b7d5f06972fdd35155f0fad9176ab3a5bb96fa [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, Jozefcb88cfd2020-09-28 16:38:57 +02007
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +02008#include <numeric>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02009
10Report::Report(boost::asio::io_context& ioc,
11 const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010012 const std::string& reportName,
13 const std::string& reportingTypeIn,
14 const bool emitsReadingsUpdateIn,
15 const bool logToMetricReportsCollectionIn,
16 const std::chrono::milliseconds intervalIn,
17 const ReadingParameters& readingParametersIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020018 interfaces::ReportManager& reportManager,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010019 interfaces::JsonStorage& reportStorageIn,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020020 std::vector<std::shared_ptr<interfaces::Metric>> metrics) :
21 name(reportName),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010022 path(reportDir + name), reportingType(reportingTypeIn),
23 interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn),
24 logToMetricReportsCollection(logToMetricReportsCollectionIn),
25 readingParameters(readingParametersIn), objServer(objServer),
26 metrics(std::move(metrics)), timer(ioc),
27 fileName(std::to_string(std::hash<std::string>{}(name))),
28 reportStorage(reportStorageIn)
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020029{
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010030 for (auto& metric : this->metrics)
31 {
32 metric->initialize();
33 }
34
Wludzik, Jozefe2362792020-10-27 17:23:55 +010035 deleteIface = objServer->add_unique_interface(
36 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
37 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
38 if (persistency)
39 {
40 reportStorage.remove(fileName);
41 }
42 boost::asio::post(ioc, [this, &reportManager] {
43 reportManager.removeReport(this);
44 });
45 });
46 });
47
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020048 reportIface = objServer->add_unique_interface(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010049 path, reportIfaceName, [this](auto& dbusIface) {
50 dbusIface.register_property_rw(
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020051 "Interval", static_cast<uint64_t>(interval.count()),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010052 sdbusplus::vtable::property_::emits_change,
53 [this](uint64_t newVal, auto&) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020054 std::chrono::milliseconds newValT(newVal);
55 if (newValT < ReportManager::minInterval)
56 {
57 return false;
58 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020059 interval = newValT;
60 return true;
Wludzik, Jozefe2362792020-10-27 17:23:55 +010061 },
62 [this](const auto&) {
63 return static_cast<uint64_t>(interval.count());
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020064 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010065 persistency = storeConfiguration();
66 dbusIface.register_property_rw(
67 "Persistency", persistency,
68 sdbusplus::vtable::property_::emits_change,
69 [this](bool newVal, const auto&) {
70 if (newVal == persistency)
71 {
72 return true;
73 }
74 if (newVal)
75 {
76 persistency = storeConfiguration();
77 }
78 else
79 {
80 reportStorage.remove(fileName);
81 persistency = false;
82 }
83 return true;
84 },
85 [this](const auto&) { return persistency; });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020086 dbusIface.register_property_r(
87 "Readings", readings,
88 sdbusplus::vtable::property_::emits_change,
89 [this](const auto&) { return readings; });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010090 dbusIface.register_property_r(
91 "ReportingType", reportingType,
92 sdbusplus::vtable::property_::const_,
93 [this](const auto&) { return reportingType; });
94 dbusIface.register_property_r(
95 "ReadingParameters", readingParameters,
96 sdbusplus::vtable::property_::const_,
97 [this](const auto&) { return readingParameters; });
98 dbusIface.register_property_r(
99 "EmitsReadingsUpdate", emitsReadingsUpdate,
100 sdbusplus::vtable::property_::const_,
101 [this](const auto&) { return emitsReadingsUpdate; });
102 dbusIface.register_property_r(
103 "LogToMetricReportsCollection", logToMetricReportsCollection,
104 sdbusplus::vtable::property_::const_,
105 [this](const auto&) { return logToMetricReportsCollection; });
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +0100106 dbusIface.register_method("Update", [this] {
107 if (reportingType == "OnRequest")
108 {
109 updateReadings();
110 }
111 });
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200112 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200113
114 if (reportingType == "Periodic")
115 {
116 scheduleTimer(interval);
117 }
118}
119
120void Report::timerProc(boost::system::error_code ec, Report& self)
121{
122 if (ec)
123 {
124 return;
125 }
126
127 self.updateReadings();
128 self.scheduleTimer(self.interval);
129}
130
131void Report::scheduleTimer(std::chrono::milliseconds timerInterval)
132{
133 timer.expires_after(timerInterval);
134 timer.async_wait(
135 [this](boost::system::error_code ec) { timerProc(ec, *this); });
136}
137
138void Report::updateReadings()
139{
140 auto numElements = std::accumulate(
141 metrics.begin(), metrics.end(), 0u, [](auto sum, const auto& metric) {
142 return sum + metric->getReadings().size();
143 });
144
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100145 std::tuple_element_t<1, Readings> readingsCache(numElements);
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200146
147 auto it = readingsCache.begin();
148
149 for (const auto& metric : metrics)
150 {
151 for (const auto& reading : metric->getReadings())
152 {
153 *(it++) = std::make_tuple(reading.id, reading.metadata,
154 reading.value, reading.timestamp);
155 }
156 }
157
158 std::get<0>(readings) = std::time(0);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100159 std::get<1>(readings) = std::move(readingsCache);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100160
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200161 reportIface->signal_property("Readings");
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200162}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100163
164bool Report::storeConfiguration() const
165{
166 try
167 {
168 nlohmann::json data;
169
170 data["Version"] = reportVersion;
171 data["Name"] = name;
172 data["ReportingType"] = reportingType;
173 data["EmitsReadingsUpdate"] = emitsReadingsUpdate;
174 data["LogToMetricReportsCollection"] = logToMetricReportsCollection;
175 data["Interval"] = interval.count();
176 data["ReadingParameters"] = utils::transform(
177 metrics, [](const auto& metric) { return metric->to_json(); });
178
179 reportStorage.store(fileName, data);
180 }
181 catch (const std::exception& e)
182 {
183 phosphor::logging::log<phosphor::logging::level::ERR>(
184 "Failed to store a report in storage",
185 phosphor::logging::entry("msg=", e.what()));
186 return false;
187 }
188
189 return true;
190}