blob: 7aef423807f97c8437c3aba70612e37bd7495c5c [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
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000044 persistency = storeConfiguration();
45 reportIface = makeReportInterface();
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020046
47 if (reportingType == "Periodic")
48 {
49 scheduleTimer(interval);
50 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000051
52 for (auto& metric : this->metrics)
53 {
54 metric->initialize();
55 }
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020056}
57
Krzysztof Grobelny85db8bd2021-05-28 12:13:23 +000058std::unique_ptr<sdbusplus::asio::dbus_interface> Report::makeReportInterface()
59{
60 auto dbusIface = objServer->add_unique_interface(path, reportIfaceName);
61 dbusIface->register_property_rw(
62 "Interval", static_cast<uint64_t>(interval.count()),
63 sdbusplus::vtable::property_::emits_change,
64 [this](uint64_t newVal, auto&) {
65 std::chrono::milliseconds newValT(newVal);
66 if (newValT < ReportManager::minInterval)
67 {
68 return false;
69 }
70 interval = newValT;
71 return true;
72 },
73 [this](const auto&) {
74 return static_cast<uint64_t>(interval.count());
75 });
76 dbusIface->register_property_rw(
77 "Persistency", persistency, sdbusplus::vtable::property_::emits_change,
78 [this](bool newVal, const auto&) {
79 if (newVal == persistency)
80 {
81 return true;
82 }
83 if (newVal)
84 {
85 persistency = storeConfiguration();
86 }
87 else
88 {
89 reportStorage.remove(fileName);
90 persistency = false;
91 }
92 return true;
93 },
94 [this](const auto&) { return persistency; });
95
96 auto readingsFlag = sdbusplus::vtable::property_::none;
97 if (emitsReadingsUpdate)
98 {
99 readingsFlag = sdbusplus::vtable::property_::emits_change;
100 }
101 dbusIface->register_property_r("Readings", readings, readingsFlag,
102 [this](const auto&) { return readings; });
103 dbusIface->register_property_r(
104 "ReportingType", reportingType, sdbusplus::vtable::property_::const_,
105 [this](const auto&) { return reportingType; });
106 dbusIface->register_property_r(
107 "ReadingParameters", readingParameters,
108 sdbusplus::vtable::property_::const_,
109 [this](const auto&) { return readingParameters; });
110 dbusIface->register_property_r(
111 "EmitsReadingsUpdate", emitsReadingsUpdate,
112 sdbusplus::vtable::property_::const_,
113 [this](const auto&) { return emitsReadingsUpdate; });
114 dbusIface->register_property_r(
115 "LogToMetricReportsCollection", logToMetricReportsCollection,
116 sdbusplus::vtable::property_::const_,
117 [this](const auto&) { return logToMetricReportsCollection; });
118 dbusIface->register_method("Update", [this] {
119 if (reportingType == "OnRequest")
120 {
121 updateReadings();
122 }
123 });
124 constexpr bool skipPropertiesChangedSignal = true;
125 dbusIface->initialize(skipPropertiesChangedSignal);
126 return dbusIface;
127}
128
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200129void Report::timerProc(boost::system::error_code ec, Report& self)
130{
131 if (ec)
132 {
133 return;
134 }
135
136 self.updateReadings();
137 self.scheduleTimer(self.interval);
138}
139
140void Report::scheduleTimer(std::chrono::milliseconds timerInterval)
141{
142 timer.expires_after(timerInterval);
143 timer.async_wait(
144 [this](boost::system::error_code ec) { timerProc(ec, *this); });
145}
146
147void Report::updateReadings()
148{
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000149 std::tuple_element_t<1, Readings> readingsCache(metrics.size());
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200150
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000151 std::transform(std::begin(metrics), std::end(metrics),
152 std::begin(readingsCache), [](const auto& metric) {
153 const auto& reading = metric->getReading();
154 return std::make_tuple(reading.id, reading.metadata,
155 reading.value, reading.timestamp);
156 });
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200157
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();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000176 data["ReadingParameters"] =
177 utils::transform(metrics, [](const auto& metric) {
178 return metric->dumpConfiguration();
179 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100180
181 reportStorage.store(fileName, data);
182 }
183 catch (const std::exception& e)
184 {
185 phosphor::logging::log<phosphor::logging::level::ERR>(
186 "Failed to store a report in storage",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100187 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100188 return false;
189 }
190
191 return true;
192}