blob: b2ac26113c9f8614450f07627e407a57994b0bc2 [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{
Wludzik, Jozefe2362792020-10-27 17:23:55 +010030 deleteIface = objServer->add_unique_interface(
31 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
32 dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
33 if (persistency)
34 {
35 reportStorage.remove(fileName);
36 }
37 boost::asio::post(ioc, [this, &reportManager] {
38 reportManager.removeReport(this);
39 });
40 });
41 });
42
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020043 reportIface = objServer->add_unique_interface(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010044 path, reportIfaceName, [this](auto& dbusIface) {
45 dbusIface.register_property_rw(
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020046 "Interval", static_cast<uint64_t>(interval.count()),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010047 sdbusplus::vtable::property_::emits_change,
48 [this](uint64_t newVal, auto&) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020049 std::chrono::milliseconds newValT(newVal);
50 if (newValT < ReportManager::minInterval)
51 {
52 return false;
53 }
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020054 interval = newValT;
55 return true;
Wludzik, Jozefe2362792020-10-27 17:23:55 +010056 },
57 [this](const auto&) {
58 return static_cast<uint64_t>(interval.count());
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020059 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010060 persistency = storeConfiguration();
61 dbusIface.register_property_rw(
62 "Persistency", persistency,
63 sdbusplus::vtable::property_::emits_change,
64 [this](bool newVal, const auto&) {
65 if (newVal == persistency)
66 {
67 return true;
68 }
69 if (newVal)
70 {
71 persistency = storeConfiguration();
72 }
73 else
74 {
75 reportStorage.remove(fileName);
76 persistency = false;
77 }
78 return true;
79 },
80 [this](const auto&) { return persistency; });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020081 dbusIface.register_property_r(
82 "Readings", readings,
83 sdbusplus::vtable::property_::emits_change,
84 [this](const auto&) { return readings; });
Wludzik, Jozefe2362792020-10-27 17:23:55 +010085 dbusIface.register_property_r(
86 "ReportingType", reportingType,
87 sdbusplus::vtable::property_::const_,
88 [this](const auto&) { return reportingType; });
89 dbusIface.register_property_r(
90 "ReadingParameters", readingParameters,
91 sdbusplus::vtable::property_::const_,
92 [this](const auto&) { return readingParameters; });
93 dbusIface.register_property_r(
94 "EmitsReadingsUpdate", emitsReadingsUpdate,
95 sdbusplus::vtable::property_::const_,
96 [this](const auto&) { return emitsReadingsUpdate; });
97 dbusIface.register_property_r(
98 "LogToMetricReportsCollection", logToMetricReportsCollection,
99 sdbusplus::vtable::property_::const_,
100 [this](const auto&) { return logToMetricReportsCollection; });
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200101 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200102
103 if (reportingType == "Periodic")
104 {
105 scheduleTimer(interval);
106 }
107}
108
109void Report::timerProc(boost::system::error_code ec, Report& self)
110{
111 if (ec)
112 {
113 return;
114 }
115
116 self.updateReadings();
117 self.scheduleTimer(self.interval);
118}
119
120void Report::scheduleTimer(std::chrono::milliseconds timerInterval)
121{
122 timer.expires_after(timerInterval);
123 timer.async_wait(
124 [this](boost::system::error_code ec) { timerProc(ec, *this); });
125}
126
127void Report::updateReadings()
128{
129 auto numElements = std::accumulate(
130 metrics.begin(), metrics.end(), 0u, [](auto sum, const auto& metric) {
131 return sum + metric->getReadings().size();
132 });
133
134 readingsCache.resize(numElements);
135
136 auto it = readingsCache.begin();
137
138 for (const auto& metric : metrics)
139 {
140 for (const auto& reading : metric->getReadings())
141 {
142 *(it++) = std::make_tuple(reading.id, reading.metadata,
143 reading.value, reading.timestamp);
144 }
145 }
146
147 std::get<0>(readings) = std::time(0);
148 std::get<1>(readings) = readingsCache;
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100149
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200150 reportIface->signal_property("Readings");
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200151}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100152
153bool Report::storeConfiguration() const
154{
155 try
156 {
157 nlohmann::json data;
158
159 data["Version"] = reportVersion;
160 data["Name"] = name;
161 data["ReportingType"] = reportingType;
162 data["EmitsReadingsUpdate"] = emitsReadingsUpdate;
163 data["LogToMetricReportsCollection"] = logToMetricReportsCollection;
164 data["Interval"] = interval.count();
165 data["ReadingParameters"] = utils::transform(
166 metrics, [](const auto& metric) { return metric->to_json(); });
167
168 reportStorage.store(fileName, data);
169 }
170 catch (const std::exception& e)
171 {
172 phosphor::logging::log<phosphor::logging::level::ERR>(
173 "Failed to store a report in storage",
174 phosphor::logging::entry("msg=", e.what()));
175 return false;
176 }
177
178 return true;
179}