xref: /openbmc/telemetry/src/report_manager.cpp (revision 51497a0c)
164b75a5bSKrzysztof Grobelny #include "report_manager.hpp"
264b75a5bSKrzysztof Grobelny 
3e2362796SWludzik, Jozef #include "report.hpp"
4dcc4e193SKrzysztof Grobelny #include "types/report_types.hpp"
5e8fc5751SKrzysztof Grobelny #include "utils/conversion.hpp"
6d2238194SKrzysztof Grobelny #include "utils/transform.hpp"
7e2362796SWludzik, Jozef 
8e2362796SWludzik, Jozef #include <phosphor-logging/log.hpp>
9cb88cfdfSWludzik, Jozef #include <sdbusplus/exception.hpp>
10cb88cfdfSWludzik, Jozef 
11e2362796SWludzik, Jozef #include <stdexcept>
1264b75a5bSKrzysztof Grobelny #include <system_error>
1364b75a5bSKrzysztof Grobelny 
14dcc4e193SKrzysztof Grobelny ReadingParameters
15dcc4e193SKrzysztof Grobelny     convertToReadingParameters(ReadingParametersPastVersion params)
16dcc4e193SKrzysztof Grobelny {
17dcc4e193SKrzysztof Grobelny     return utils::transform(params, [](const auto& param) {
18dcc4e193SKrzysztof Grobelny         using namespace std::chrono_literals;
19dcc4e193SKrzysztof Grobelny 
20dcc4e193SKrzysztof Grobelny         return ReadingParameters::value_type(
21dcc4e193SKrzysztof Grobelny             std::vector{{std::get<0>(param)}}, std::get<1>(param),
22dcc4e193SKrzysztof Grobelny             std::get<2>(param), std::get<3>(param),
23dcc4e193SKrzysztof Grobelny             utils::enumToString(CollectionTimeScope::point), 0u);
24dcc4e193SKrzysztof Grobelny     });
25dcc4e193SKrzysztof Grobelny }
26dcc4e193SKrzysztof Grobelny 
2764b75a5bSKrzysztof Grobelny ReportManager::ReportManager(
282f9f9b87SWludzik, Jozef     std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
29e2362796SWludzik, Jozef     std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
30cb88cfdfSWludzik, Jozef     const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
312f9f9b87SWludzik, Jozef     reportFactory(std::move(reportFactoryIn)),
32e2362796SWludzik, Jozef     reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
3364b75a5bSKrzysztof Grobelny {
34cb88cfdfSWludzik, Jozef     reports.reserve(maxReports);
356ccfcbf5SKrzysztof Grobelny 
36e2362796SWludzik, Jozef     loadFromPersistent();
3764b75a5bSKrzysztof Grobelny 
38cb88cfdfSWludzik, Jozef     reportManagerIface = objServer->add_unique_interface(
392f9f9b87SWludzik, Jozef         reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
40cb88cfdfSWludzik, Jozef             dbusIface.register_property_r(
41503c1589SWludzik, Jozef                 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
4264b75a5bSKrzysztof Grobelny                 [](const auto&) { return maxReports; });
43cb88cfdfSWludzik, Jozef             dbusIface.register_property_r(
4432859b63SKarol Niczyj                 "MaxReportNameLength", size_t{},
4532859b63SKarol Niczyj                 sdbusplus::vtable::property_::const_,
4632859b63SKarol Niczyj                 [](const auto&) { return maxReportNameLength; });
4732859b63SKarol Niczyj             dbusIface.register_property_r(
4864b75a5bSKrzysztof Grobelny                 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
4964b75a5bSKrzysztof Grobelny                 [](const auto&) -> uint64_t { return minInterval.count(); });
5064b75a5bSKrzysztof Grobelny 
51cb88cfdfSWludzik, Jozef             dbusIface.register_method(
52e2362796SWludzik, Jozef                 "AddReport", [this](boost::asio::yield_context& yield,
53e2362796SWludzik, Jozef                                     const std::string& reportName,
54cb88cfdfSWludzik, Jozef                                     const std::string& reportingType,
55cb88cfdfSWludzik, Jozef                                     const bool emitsReadingsUpdate,
56cb88cfdfSWludzik, Jozef                                     const bool logToMetricReportsCollection,
57cb88cfdfSWludzik, Jozef                                     const uint64_t interval,
58dcc4e193SKrzysztof Grobelny                                     ReadingParametersPastVersion metricParams) {
597e098e93SLukasz Kazmierczak                     constexpr auto enabledDefault = true;
603eb56865SSzymon Dompke                     constexpr uint64_t appendLimitDefault = 0;
613eb56865SSzymon Dompke                     constexpr ReportUpdates reportUpdatesDefault =
62*51497a0cSKrzysztof Grobelny                         ReportUpdates::overwrite;
63*51497a0cSKrzysztof Grobelny 
64*51497a0cSKrzysztof Grobelny                     std::vector<ReportAction> reportActions;
65*51497a0cSKrzysztof Grobelny 
66*51497a0cSKrzysztof Grobelny                     if (emitsReadingsUpdate)
67*51497a0cSKrzysztof Grobelny                     {
68*51497a0cSKrzysztof Grobelny                         reportActions.emplace_back(
69*51497a0cSKrzysztof Grobelny                             ReportAction::emitsReadingsUpdate);
70*51497a0cSKrzysztof Grobelny                     }
71*51497a0cSKrzysztof Grobelny                     if (logToMetricReportsCollection)
72*51497a0cSKrzysztof Grobelny                     {
73*51497a0cSKrzysztof Grobelny                         reportActions.emplace_back(
74*51497a0cSKrzysztof Grobelny                             ReportAction::logToMetricReportsCollection);
75*51497a0cSKrzysztof Grobelny                     }
76*51497a0cSKrzysztof Grobelny 
77*51497a0cSKrzysztof Grobelny                     return addReport(yield, reportName,
78*51497a0cSKrzysztof Grobelny                                      utils::toReportingType(reportingType),
79*51497a0cSKrzysztof Grobelny                                      reportActions, Milliseconds(interval),
80*51497a0cSKrzysztof Grobelny                                      appendLimitDefault, reportUpdatesDefault,
81dcc4e193SKrzysztof Grobelny                                      convertToReadingParameters(
827e098e93SLukasz Kazmierczak                                          std::move(metricParams)),
837e098e93SLukasz Kazmierczak                                      enabledDefault)
84dcc4e193SKrzysztof Grobelny                         .getPath();
85dcc4e193SKrzysztof Grobelny                 });
86dcc4e193SKrzysztof Grobelny 
87dcc4e193SKrzysztof Grobelny             dbusIface.register_method(
88dcc4e193SKrzysztof Grobelny                 "AddReportFutureVersion",
89*51497a0cSKrzysztof Grobelny                 [this](boost::asio::yield_context& yield,
90dcc4e193SKrzysztof Grobelny                        const std::string& reportName,
91dcc4e193SKrzysztof Grobelny                        const std::string& reportingType,
923eb56865SSzymon Dompke                        const std::string& reportUpdates,
93*51497a0cSKrzysztof Grobelny                        const uint64_t appendLimit,
94*51497a0cSKrzysztof Grobelny                        const std::vector<std::string>& reportActions,
95*51497a0cSKrzysztof Grobelny                        const uint64_t interval,
96*51497a0cSKrzysztof Grobelny                        ReadingParameters metricParams) {
977e098e93SLukasz Kazmierczak                     constexpr auto enabledDefault = true;
98*51497a0cSKrzysztof Grobelny                     return addReport(yield, reportName,
99*51497a0cSKrzysztof Grobelny                                      utils::toReportingType(reportingType),
100*51497a0cSKrzysztof Grobelny                                      utils::transform(
101*51497a0cSKrzysztof Grobelny                                          reportActions,
102*51497a0cSKrzysztof Grobelny                                          [](const auto& reportAction) {
103*51497a0cSKrzysztof Grobelny                                              return utils::toReportAction(
104*51497a0cSKrzysztof Grobelny                                                  reportAction);
105*51497a0cSKrzysztof Grobelny                                          }),
1063eb56865SSzymon Dompke                                      Milliseconds(interval), appendLimit,
107*51497a0cSKrzysztof Grobelny                                      utils::toReportUpdates(reportUpdates),
108*51497a0cSKrzysztof Grobelny                                      std::move(metricParams), enabledDefault)
109d2238194SKrzysztof Grobelny                         .getPath();
110e2362796SWludzik, Jozef                 });
111e2362796SWludzik, Jozef         });
112e2362796SWludzik, Jozef }
113e2362796SWludzik, Jozef 
114e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report)
115e2362796SWludzik, Jozef {
116e2362796SWludzik, Jozef     reports.erase(
117e2362796SWludzik, Jozef         std::remove_if(reports.begin(), reports.end(),
118e2362796SWludzik, Jozef                        [report](const auto& x) { return report == x.get(); }),
119e2362796SWludzik, Jozef         reports.end());
120e2362796SWludzik, Jozef }
121e2362796SWludzik, Jozef 
12232859b63SKarol Niczyj void ReportManager::verifyReportNameLength(const std::string& reportName)
12332859b63SKarol Niczyj {
12432859b63SKarol Niczyj     if (reportName.length() > maxReportNameLength)
12532859b63SKarol Niczyj     {
12632859b63SKarol Niczyj         throw sdbusplus::exception::SdBusError(
12732859b63SKarol Niczyj             static_cast<int>(std::errc::invalid_argument),
128e28aa53dSSzymon Dompke             "Report name exceeds maximum length");
12932859b63SKarol Niczyj     }
13032859b63SKarol Niczyj }
13132859b63SKarol Niczyj 
132dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport(
133*51497a0cSKrzysztof Grobelny     const std::string& reportName, const ReportingType reportingType,
134*51497a0cSKrzysztof Grobelny     Milliseconds interval, const ReportUpdates reportUpdates,
135dcc4e193SKrzysztof Grobelny     const std::vector<LabeledMetricParameters>& readingParams)
136e2362796SWludzik, Jozef {
137*51497a0cSKrzysztof Grobelny     if (reportingType == ReportingType::onChange)
138*51497a0cSKrzysztof Grobelny     {
139*51497a0cSKrzysztof Grobelny         throw sdbusplus::exception::SdBusError(
140*51497a0cSKrzysztof Grobelny             static_cast<int>(std::errc::invalid_argument),
141*51497a0cSKrzysztof Grobelny             "Invalid reportingType");
142*51497a0cSKrzysztof Grobelny     }
143*51497a0cSKrzysztof Grobelny 
144cb88cfdfSWludzik, Jozef     if (reports.size() >= maxReports)
145cb88cfdfSWludzik, Jozef     {
146cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
147cb88cfdfSWludzik, Jozef             static_cast<int>(std::errc::too_many_files_open),
148cb88cfdfSWludzik, Jozef             "Reached maximal report count");
14964b75a5bSKrzysztof Grobelny     }
15064b75a5bSKrzysztof Grobelny 
15132859b63SKarol Niczyj     verifyReportNameLength(reportName);
15232859b63SKarol Niczyj 
153cb88cfdfSWludzik, Jozef     for (const auto& report : reports)
15464b75a5bSKrzysztof Grobelny     {
1552f9f9b87SWludzik, Jozef         if (report->getName() == reportName)
156cb88cfdfSWludzik, Jozef         {
157cb88cfdfSWludzik, Jozef             throw sdbusplus::exception::SdBusError(
158e2362796SWludzik, Jozef                 static_cast<int>(std::errc::file_exists), "Duplicate report");
159cb88cfdfSWludzik, Jozef         }
160cb88cfdfSWludzik, Jozef     }
161cb88cfdfSWludzik, Jozef 
1623eb56865SSzymon Dompke     verifyReportUpdates(reportUpdates);
1633eb56865SSzymon Dompke 
164*51497a0cSKrzysztof Grobelny     if (reportingType == ReportingType::periodic && interval < minInterval)
165cb88cfdfSWludzik, Jozef     {
166cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
167e2362796SWludzik, Jozef             static_cast<int>(std::errc::invalid_argument), "Invalid interval");
168cb88cfdfSWludzik, Jozef     }
169bc766b4dSWludzik, Jozef 
170503c1589SWludzik, Jozef     if (readingParams.size() > maxReadingParams)
171e8fc5751SKrzysztof Grobelny 
172bc766b4dSWludzik, Jozef     {
173bc766b4dSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
174bc766b4dSWludzik, Jozef             static_cast<int>(std::errc::argument_list_too_long),
175bc766b4dSWludzik, Jozef             "Too many reading parameters");
176bc766b4dSWludzik, Jozef     }
177e8fc5751SKrzysztof Grobelny 
178e8fc5751SKrzysztof Grobelny     try
179e8fc5751SKrzysztof Grobelny     {
180dcc4e193SKrzysztof Grobelny         namespace ts = utils::tstring;
181dcc4e193SKrzysztof Grobelny 
182dcc4e193SKrzysztof Grobelny         for (const LabeledMetricParameters& item : readingParams)
183e8fc5751SKrzysztof Grobelny         {
184dcc4e193SKrzysztof Grobelny             utils::toOperationType(
185dcc4e193SKrzysztof Grobelny                 utils::toUnderlying(item.at_label<ts::OperationType>()));
186e8fc5751SKrzysztof Grobelny         }
187e8fc5751SKrzysztof Grobelny     }
188e8fc5751SKrzysztof Grobelny     catch (const std::exception& e)
189e8fc5751SKrzysztof Grobelny     {
190e8fc5751SKrzysztof Grobelny         throw sdbusplus::exception::SdBusError(
191e8fc5751SKrzysztof Grobelny             static_cast<int>(std::errc::invalid_argument), e.what());
192e8fc5751SKrzysztof Grobelny     }
193d2238194SKrzysztof Grobelny }
194cb88cfdfSWludzik, Jozef 
195d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
196d2238194SKrzysztof Grobelny     boost::asio::yield_context& yield, const std::string& reportName,
197*51497a0cSKrzysztof Grobelny     const ReportingType reportingType,
198*51497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
199*51497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
2007e098e93SLukasz Kazmierczak     ReadingParameters metricParams, const bool enabled)
201d2238194SKrzysztof Grobelny {
202dcc4e193SKrzysztof Grobelny     auto labeledMetricParams =
203dcc4e193SKrzysztof Grobelny         reportFactory->convertMetricParams(yield, metricParams);
204d2238194SKrzysztof Grobelny 
205*51497a0cSKrzysztof Grobelny     return addReport(reportName, reportingType, reportActions, interval,
206*51497a0cSKrzysztof Grobelny                      appendLimit, reportUpdates, std::move(labeledMetricParams),
207*51497a0cSKrzysztof Grobelny                      enabled);
208d2238194SKrzysztof Grobelny }
209d2238194SKrzysztof Grobelny 
210d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
211*51497a0cSKrzysztof Grobelny     const std::string& reportName, const ReportingType reportingType,
212*51497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
213*51497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
2147e098e93SLukasz Kazmierczak     std::vector<LabeledMetricParameters> labeledMetricParams,
2157e098e93SLukasz Kazmierczak     const bool enabled)
216d2238194SKrzysztof Grobelny {
2173eb56865SSzymon Dompke     verifyAddReport(reportName, reportingType, interval, reportUpdates,
2183eb56865SSzymon Dompke                     labeledMetricParams);
219d2238194SKrzysztof Grobelny 
2203eb56865SSzymon Dompke     reports.emplace_back(reportFactory->make(
221*51497a0cSKrzysztof Grobelny         reportName, reportingType, reportActions, interval, appendLimit,
222*51497a0cSKrzysztof Grobelny         reportUpdates, *this, *reportStorage, labeledMetricParams, enabled));
223d2238194SKrzysztof Grobelny     return *reports.back();
224cb88cfdfSWludzik, Jozef }
225cb88cfdfSWludzik, Jozef 
226e2362796SWludzik, Jozef void ReportManager::loadFromPersistent()
227cb88cfdfSWludzik, Jozef {
228e2362796SWludzik, Jozef     std::vector<interfaces::JsonStorage::FilePath> paths =
229e2362796SWludzik, Jozef         reportStorage->list();
230e2362796SWludzik, Jozef 
231e2362796SWludzik, Jozef     for (const auto& path : paths)
232e2362796SWludzik, Jozef     {
233e2362796SWludzik, Jozef         std::optional<nlohmann::json> data = reportStorage->load(path);
234e2362796SWludzik, Jozef         try
235e2362796SWludzik, Jozef         {
2367e098e93SLukasz Kazmierczak             bool enabled = data->at("Enabled").get<bool>();
237e2362796SWludzik, Jozef             size_t version = data->at("Version").get<size_t>();
238e2362796SWludzik, Jozef             if (version != Report::reportVersion)
239e2362796SWludzik, Jozef             {
240e2362796SWludzik, Jozef                 throw std::logic_error("Invalid version");
241e2362796SWludzik, Jozef             }
242e2362796SWludzik, Jozef             std::string& name = data->at("Name").get_ref<std::string&>();
243*51497a0cSKrzysztof Grobelny 
244*51497a0cSKrzysztof Grobelny             uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
245*51497a0cSKrzysztof Grobelny             std::vector<ReportAction> reportActions = utils::transform(
246*51497a0cSKrzysztof Grobelny                 data->at("ReportActions").get<std::vector<uint32_t>>(),
247*51497a0cSKrzysztof Grobelny                 [](const auto reportAction) {
248*51497a0cSKrzysztof Grobelny                     return utils::toReportAction(reportAction);
249*51497a0cSKrzysztof Grobelny                 });
250e2362796SWludzik, Jozef             uint64_t interval = data->at("Interval").get<uint64_t>();
2513eb56865SSzymon Dompke             uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
252*51497a0cSKrzysztof Grobelny             uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
253d2238194SKrzysztof Grobelny             auto readingParameters =
254d2238194SKrzysztof Grobelny                 data->at("ReadingParameters")
255d2238194SKrzysztof Grobelny                     .get<std::vector<LabeledMetricParameters>>();
256e2362796SWludzik, Jozef 
257*51497a0cSKrzysztof Grobelny             addReport(name, utils::toReportingType(reportingType),
258*51497a0cSKrzysztof Grobelny                       reportActions, Milliseconds(interval), appendLimit,
259*51497a0cSKrzysztof Grobelny                       utils::toReportUpdates(reportUpdates),
260*51497a0cSKrzysztof Grobelny                       std::move(readingParameters), enabled);
261e2362796SWludzik, Jozef         }
262e2362796SWludzik, Jozef         catch (const std::exception& e)
263e2362796SWludzik, Jozef         {
264e2362796SWludzik, Jozef             phosphor::logging::log<phosphor::logging::level::ERR>(
265e2362796SWludzik, Jozef                 "Failed to load report from storage",
266e2362796SWludzik, Jozef                 phosphor::logging::entry(
267982c5b5bSWludzik, Jozef                     "FILENAME=%s",
268e2362796SWludzik, Jozef                     static_cast<std::filesystem::path>(path).c_str()),
269982c5b5bSWludzik, Jozef                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
270e2362796SWludzik, Jozef             reportStorage->remove(path);
271e2362796SWludzik, Jozef         }
272e2362796SWludzik, Jozef     }
27364b75a5bSKrzysztof Grobelny }
274d960e1f3SWludzik, Jozef 
275d960e1f3SWludzik, Jozef void ReportManager::updateReport(const std::string& name)
276d960e1f3SWludzik, Jozef {
277d960e1f3SWludzik, Jozef     for (auto& report : reports)
278d960e1f3SWludzik, Jozef     {
279d960e1f3SWludzik, Jozef         if (report->getName() == name)
280d960e1f3SWludzik, Jozef         {
281d960e1f3SWludzik, Jozef             report->updateReadings();
282d960e1f3SWludzik, Jozef             return;
283d960e1f3SWludzik, Jozef         }
284d960e1f3SWludzik, Jozef     }
285d960e1f3SWludzik, Jozef }
2863eb56865SSzymon Dompke 
287*51497a0cSKrzysztof Grobelny void ReportManager::verifyReportUpdates(const ReportUpdates reportUpdates)
2883eb56865SSzymon Dompke {
2893eb56865SSzymon Dompke     if (std::find(supportedReportUpdates.begin(), supportedReportUpdates.end(),
2903eb56865SSzymon Dompke                   reportUpdates) == supportedReportUpdates.end())
2913eb56865SSzymon Dompke     {
2923eb56865SSzymon Dompke         throw sdbusplus::exception::SdBusError(
2933eb56865SSzymon Dompke             static_cast<int>(std::errc::invalid_argument),
2943eb56865SSzymon Dompke             "Invalid ReportUpdates");
2953eb56865SSzymon Dompke     }
2963eb56865SSzymon Dompke }
297