xref: /openbmc/telemetry/src/report_manager.cpp (revision e6c417cf)
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"
6b8cc78ddSKrzysztof Grobelny #include "utils/generate_id.hpp"
7d2238194SKrzysztof Grobelny #include "utils/transform.hpp"
8e2362796SWludzik, Jozef 
9e2362796SWludzik, Jozef #include <phosphor-logging/log.hpp>
10cb88cfdfSWludzik, Jozef #include <sdbusplus/exception.hpp>
11cb88cfdfSWludzik, Jozef 
12e2362796SWludzik, Jozef #include <stdexcept>
1364b75a5bSKrzysztof Grobelny #include <system_error>
1464b75a5bSKrzysztof Grobelny 
15dcc4e193SKrzysztof Grobelny ReadingParameters
16dcc4e193SKrzysztof Grobelny     convertToReadingParameters(ReadingParametersPastVersion params)
17dcc4e193SKrzysztof Grobelny {
18dcc4e193SKrzysztof Grobelny     return utils::transform(params, [](const auto& param) {
19dcc4e193SKrzysztof Grobelny         using namespace std::chrono_literals;
20dcc4e193SKrzysztof Grobelny 
21b8cc78ddSKrzysztof Grobelny         const auto& [sensorPath, operationType, id, metadata] = param;
22b8cc78ddSKrzysztof Grobelny 
23dcc4e193SKrzysztof Grobelny         return ReadingParameters::value_type(
24b8cc78ddSKrzysztof Grobelny             std::vector<
25b8cc78ddSKrzysztof Grobelny                 std::tuple<sdbusplus::message::object_path, std::string>>{
26b8cc78ddSKrzysztof Grobelny                 {sensorPath, metadata}},
27b8cc78ddSKrzysztof Grobelny             operationType, id, utils::enumToString(CollectionTimeScope::point),
28b8cc78ddSKrzysztof Grobelny             0u);
29dcc4e193SKrzysztof Grobelny     });
30dcc4e193SKrzysztof Grobelny }
31dcc4e193SKrzysztof Grobelny 
3264b75a5bSKrzysztof Grobelny ReportManager::ReportManager(
332f9f9b87SWludzik, Jozef     std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
34e2362796SWludzik, Jozef     std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
35cb88cfdfSWludzik, Jozef     const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
362f9f9b87SWludzik, Jozef     reportFactory(std::move(reportFactoryIn)),
37e2362796SWludzik, Jozef     reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
3864b75a5bSKrzysztof Grobelny {
39cb88cfdfSWludzik, Jozef     reports.reserve(maxReports);
406ccfcbf5SKrzysztof Grobelny 
41e2362796SWludzik, Jozef     loadFromPersistent();
4264b75a5bSKrzysztof Grobelny 
43cb88cfdfSWludzik, Jozef     reportManagerIface = objServer->add_unique_interface(
442f9f9b87SWludzik, Jozef         reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
45cb88cfdfSWludzik, Jozef             dbusIface.register_property_r(
46503c1589SWludzik, Jozef                 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
4764b75a5bSKrzysztof Grobelny                 [](const auto&) { return maxReports; });
48cb88cfdfSWludzik, Jozef             dbusIface.register_property_r(
49b8cc78ddSKrzysztof Grobelny                 "MaxReportIdLength", size_t{},
5032859b63SKarol Niczyj                 sdbusplus::vtable::property_::const_,
51b8cc78ddSKrzysztof Grobelny                 [](const auto&) { return maxReportIdLength; });
5232859b63SKarol Niczyj             dbusIface.register_property_r(
5364b75a5bSKrzysztof Grobelny                 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
5464b75a5bSKrzysztof Grobelny                 [](const auto&) -> uint64_t { return minInterval.count(); });
5564b75a5bSKrzysztof Grobelny 
56cb88cfdfSWludzik, Jozef             dbusIface.register_method(
57e2362796SWludzik, Jozef                 "AddReport", [this](boost::asio::yield_context& yield,
58b8cc78ddSKrzysztof Grobelny                                     const std::string& reportId,
59cb88cfdfSWludzik, Jozef                                     const std::string& reportingType,
60cb88cfdfSWludzik, Jozef                                     const bool emitsReadingsUpdate,
61cb88cfdfSWludzik, Jozef                                     const bool logToMetricReportsCollection,
62cb88cfdfSWludzik, Jozef                                     const uint64_t interval,
63dcc4e193SKrzysztof Grobelny                                     ReadingParametersPastVersion metricParams) {
647e098e93SLukasz Kazmierczak                     constexpr auto enabledDefault = true;
653eb56865SSzymon Dompke                     constexpr uint64_t appendLimitDefault = 0;
663eb56865SSzymon Dompke                     constexpr ReportUpdates reportUpdatesDefault =
6751497a0cSKrzysztof Grobelny                         ReportUpdates::overwrite;
6851497a0cSKrzysztof Grobelny 
6951497a0cSKrzysztof Grobelny                     std::vector<ReportAction> reportActions;
7051497a0cSKrzysztof Grobelny 
7151497a0cSKrzysztof Grobelny                     if (emitsReadingsUpdate)
7251497a0cSKrzysztof Grobelny                     {
7351497a0cSKrzysztof Grobelny                         reportActions.emplace_back(
7451497a0cSKrzysztof Grobelny                             ReportAction::emitsReadingsUpdate);
7551497a0cSKrzysztof Grobelny                     }
7651497a0cSKrzysztof Grobelny                     if (logToMetricReportsCollection)
7751497a0cSKrzysztof Grobelny                     {
7851497a0cSKrzysztof Grobelny                         reportActions.emplace_back(
7951497a0cSKrzysztof Grobelny                             ReportAction::logToMetricReportsCollection);
8051497a0cSKrzysztof Grobelny                     }
8151497a0cSKrzysztof Grobelny 
82b8cc78ddSKrzysztof Grobelny                     return addReport(yield, reportId, reportId,
8351497a0cSKrzysztof Grobelny                                      utils::toReportingType(reportingType),
8451497a0cSKrzysztof Grobelny                                      reportActions, Milliseconds(interval),
8551497a0cSKrzysztof Grobelny                                      appendLimitDefault, reportUpdatesDefault,
86dcc4e193SKrzysztof Grobelny                                      convertToReadingParameters(
877e098e93SLukasz Kazmierczak                                          std::move(metricParams)),
887e098e93SLukasz Kazmierczak                                      enabledDefault)
89dcc4e193SKrzysztof Grobelny                         .getPath();
90dcc4e193SKrzysztof Grobelny                 });
91dcc4e193SKrzysztof Grobelny 
92dcc4e193SKrzysztof Grobelny             dbusIface.register_method(
93dcc4e193SKrzysztof Grobelny                 "AddReportFutureVersion",
94b8cc78ddSKrzysztof Grobelny                 [this](
95b8cc78ddSKrzysztof Grobelny                     boost::asio::yield_context& yield,
96b8cc78ddSKrzysztof Grobelny                     const std::string& reportId, const std::string& reportName,
97dcc4e193SKrzysztof Grobelny                     const std::string& reportingType,
983eb56865SSzymon Dompke                     const std::string& reportUpdates,
9951497a0cSKrzysztof Grobelny                     const uint64_t appendLimit,
10051497a0cSKrzysztof Grobelny                     const std::vector<std::string>& reportActions,
101b8cc78ddSKrzysztof Grobelny                     const uint64_t interval, ReadingParameters metricParams) {
1027e098e93SLukasz Kazmierczak                     constexpr auto enabledDefault = true;
103b8cc78ddSKrzysztof Grobelny                     return addReport(yield, reportId, reportName,
10451497a0cSKrzysztof Grobelny                                      utils::toReportingType(reportingType),
10551497a0cSKrzysztof Grobelny                                      utils::transform(
10651497a0cSKrzysztof Grobelny                                          reportActions,
10751497a0cSKrzysztof Grobelny                                          [](const auto& reportAction) {
10851497a0cSKrzysztof Grobelny                                              return utils::toReportAction(
10951497a0cSKrzysztof Grobelny                                                  reportAction);
11051497a0cSKrzysztof Grobelny                                          }),
1113eb56865SSzymon Dompke                                      Milliseconds(interval), appendLimit,
11251497a0cSKrzysztof Grobelny                                      utils::toReportUpdates(reportUpdates),
11351497a0cSKrzysztof Grobelny                                      std::move(metricParams), enabledDefault)
114d2238194SKrzysztof Grobelny                         .getPath();
115e2362796SWludzik, Jozef                 });
116e2362796SWludzik, Jozef         });
117e2362796SWludzik, Jozef }
118e2362796SWludzik, Jozef 
119e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report)
120e2362796SWludzik, Jozef {
121e2362796SWludzik, Jozef     reports.erase(
122e2362796SWludzik, Jozef         std::remove_if(reports.begin(), reports.end(),
123e2362796SWludzik, Jozef                        [report](const auto& x) { return report == x.get(); }),
124e2362796SWludzik, Jozef         reports.end());
125e2362796SWludzik, Jozef }
126e2362796SWludzik, Jozef 
127dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport(
128b8cc78ddSKrzysztof Grobelny     const std::string& reportId, const std::string& reportName,
129b8cc78ddSKrzysztof Grobelny     const ReportingType reportingType, Milliseconds interval,
130cd5b0b7eSAnkita Vilas Gawade     const ReportUpdates reportUpdates, const uint64_t appendLimit,
131dcc4e193SKrzysztof Grobelny     const std::vector<LabeledMetricParameters>& readingParams)
132e2362796SWludzik, Jozef {
13351497a0cSKrzysztof Grobelny     if (reportingType == ReportingType::onChange)
13451497a0cSKrzysztof Grobelny     {
13551497a0cSKrzysztof Grobelny         throw sdbusplus::exception::SdBusError(
13651497a0cSKrzysztof Grobelny             static_cast<int>(std::errc::invalid_argument),
13751497a0cSKrzysztof Grobelny             "Invalid reportingType");
13851497a0cSKrzysztof Grobelny     }
13951497a0cSKrzysztof Grobelny 
140cb88cfdfSWludzik, Jozef     if (reports.size() >= maxReports)
141cb88cfdfSWludzik, Jozef     {
142cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
143cb88cfdfSWludzik, Jozef             static_cast<int>(std::errc::too_many_files_open),
144cb88cfdfSWludzik, Jozef             "Reached maximal report count");
14564b75a5bSKrzysztof Grobelny     }
14664b75a5bSKrzysztof Grobelny 
147*e6c417cfSKrzysztof Grobelny     if (appendLimit > maxAppendLimit &&
148*e6c417cfSKrzysztof Grobelny         appendLimit != std::numeric_limits<uint64_t>::max())
149cd5b0b7eSAnkita Vilas Gawade     {
150cd5b0b7eSAnkita Vilas Gawade         throw sdbusplus::exception::SdBusError(
151cd5b0b7eSAnkita Vilas Gawade             static_cast<int>(std::errc::invalid_argument),
152cd5b0b7eSAnkita Vilas Gawade             "Append limit out of range");
153cd5b0b7eSAnkita Vilas Gawade     }
154cd5b0b7eSAnkita Vilas Gawade 
15551497a0cSKrzysztof Grobelny     if (reportingType == ReportingType::periodic && interval < minInterval)
156cb88cfdfSWludzik, Jozef     {
157cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
158e2362796SWludzik, Jozef             static_cast<int>(std::errc::invalid_argument), "Invalid interval");
159cb88cfdfSWludzik, Jozef     }
160bc766b4dSWludzik, Jozef 
161cd5b0b7eSAnkita Vilas Gawade     size_t metricCount = 0;
162cd5b0b7eSAnkita Vilas Gawade     for (auto metricParam : readingParams)
163cd5b0b7eSAnkita Vilas Gawade     {
164cd5b0b7eSAnkita Vilas Gawade         auto metricParamsVec =
165cd5b0b7eSAnkita Vilas Gawade             metricParam.at_label<utils::tstring::SensorPath>();
166cd5b0b7eSAnkita Vilas Gawade         metricCount += metricParamsVec.size();
167cd5b0b7eSAnkita Vilas Gawade     }
168e8fc5751SKrzysztof Grobelny 
169cd5b0b7eSAnkita Vilas Gawade     if (readingParams.size() > maxNumberMetrics ||
170cd5b0b7eSAnkita Vilas Gawade         metricCount > maxNumberMetrics)
171bc766b4dSWludzik, Jozef     {
172bc766b4dSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
173bc766b4dSWludzik, Jozef             static_cast<int>(std::errc::argument_list_too_long),
174bc766b4dSWludzik, Jozef             "Too many reading parameters");
175bc766b4dSWludzik, Jozef     }
176e8fc5751SKrzysztof Grobelny 
177e8fc5751SKrzysztof Grobelny     try
178e8fc5751SKrzysztof Grobelny     {
179dcc4e193SKrzysztof Grobelny         namespace ts = utils::tstring;
180dcc4e193SKrzysztof Grobelny 
181dcc4e193SKrzysztof Grobelny         for (const LabeledMetricParameters& item : readingParams)
182e8fc5751SKrzysztof Grobelny         {
183dcc4e193SKrzysztof Grobelny             utils::toOperationType(
184dcc4e193SKrzysztof Grobelny                 utils::toUnderlying(item.at_label<ts::OperationType>()));
185e8fc5751SKrzysztof Grobelny         }
186e8fc5751SKrzysztof Grobelny     }
187e8fc5751SKrzysztof Grobelny     catch (const std::exception& e)
188e8fc5751SKrzysztof Grobelny     {
189e8fc5751SKrzysztof Grobelny         throw sdbusplus::exception::SdBusError(
190e8fc5751SKrzysztof Grobelny             static_cast<int>(std::errc::invalid_argument), e.what());
191e8fc5751SKrzysztof Grobelny     }
192d2238194SKrzysztof Grobelny }
193cb88cfdfSWludzik, Jozef 
194d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
195b8cc78ddSKrzysztof Grobelny     boost::asio::yield_context& yield, const std::string& reportId,
196b8cc78ddSKrzysztof Grobelny     const std::string& reportName, const ReportingType reportingType,
19751497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
19851497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
1997e098e93SLukasz Kazmierczak     ReadingParameters metricParams, const bool enabled)
200d2238194SKrzysztof Grobelny {
201dcc4e193SKrzysztof Grobelny     auto labeledMetricParams =
202dcc4e193SKrzysztof Grobelny         reportFactory->convertMetricParams(yield, metricParams);
203d2238194SKrzysztof Grobelny 
204b8cc78ddSKrzysztof Grobelny     return addReport(reportId, reportName, reportingType, reportActions,
205b8cc78ddSKrzysztof Grobelny                      interval, appendLimit, reportUpdates,
206b8cc78ddSKrzysztof Grobelny                      std::move(labeledMetricParams), enabled);
207d2238194SKrzysztof Grobelny }
208d2238194SKrzysztof Grobelny 
209d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
210b8cc78ddSKrzysztof Grobelny     const std::string& reportId, const std::string& reportName,
211b8cc78ddSKrzysztof Grobelny     const ReportingType reportingType,
21251497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
21351497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
2147e098e93SLukasz Kazmierczak     std::vector<LabeledMetricParameters> labeledMetricParams,
2157e098e93SLukasz Kazmierczak     const bool enabled)
216d2238194SKrzysztof Grobelny {
217b8cc78ddSKrzysztof Grobelny     const auto existingReportIds = utils::transform(
218b8cc78ddSKrzysztof Grobelny         reports, [](const auto& report) { return report->getId(); });
219b8cc78ddSKrzysztof Grobelny 
220a950e42bSKrzysztof Grobelny     auto [id, name] = utils::generateId(reportId, reportName, reportNameDefault,
221a950e42bSKrzysztof Grobelny                                         existingReportIds, maxReportIdLength);
222b8cc78ddSKrzysztof Grobelny 
223b8cc78ddSKrzysztof Grobelny     verifyAddReport(id, name, reportingType, interval, reportUpdates,
224cd5b0b7eSAnkita Vilas Gawade                     appendLimit, labeledMetricParams);
225d2238194SKrzysztof Grobelny 
2263eb56865SSzymon Dompke     reports.emplace_back(reportFactory->make(
227b8cc78ddSKrzysztof Grobelny         id, name, reportingType, reportActions, interval, appendLimit,
22851497a0cSKrzysztof Grobelny         reportUpdates, *this, *reportStorage, labeledMetricParams, enabled));
229d2238194SKrzysztof Grobelny     return *reports.back();
230cb88cfdfSWludzik, Jozef }
231cb88cfdfSWludzik, Jozef 
232e2362796SWludzik, Jozef void ReportManager::loadFromPersistent()
233cb88cfdfSWludzik, Jozef {
234e2362796SWludzik, Jozef     std::vector<interfaces::JsonStorage::FilePath> paths =
235e2362796SWludzik, Jozef         reportStorage->list();
236e2362796SWludzik, Jozef 
237e2362796SWludzik, Jozef     for (const auto& path : paths)
238e2362796SWludzik, Jozef     {
239e2362796SWludzik, Jozef         std::optional<nlohmann::json> data = reportStorage->load(path);
240e2362796SWludzik, Jozef         try
241e2362796SWludzik, Jozef         {
242e2362796SWludzik, Jozef             size_t version = data->at("Version").get<size_t>();
243e2362796SWludzik, Jozef             if (version != Report::reportVersion)
244e2362796SWludzik, Jozef             {
245e2362796SWludzik, Jozef                 throw std::logic_error("Invalid version");
246e2362796SWludzik, Jozef             }
247b8cc78ddSKrzysztof Grobelny             bool enabled = data->at("Enabled").get<bool>();
248b8cc78ddSKrzysztof Grobelny             std::string& id = data->at("Id").get_ref<std::string&>();
249e2362796SWludzik, Jozef             std::string& name = data->at("Name").get_ref<std::string&>();
25051497a0cSKrzysztof Grobelny 
25151497a0cSKrzysztof Grobelny             uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
25251497a0cSKrzysztof Grobelny             std::vector<ReportAction> reportActions = utils::transform(
25351497a0cSKrzysztof Grobelny                 data->at("ReportActions").get<std::vector<uint32_t>>(),
25451497a0cSKrzysztof Grobelny                 [](const auto reportAction) {
25551497a0cSKrzysztof Grobelny                     return utils::toReportAction(reportAction);
25651497a0cSKrzysztof Grobelny                 });
257e2362796SWludzik, Jozef             uint64_t interval = data->at("Interval").get<uint64_t>();
2583eb56865SSzymon Dompke             uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
25951497a0cSKrzysztof Grobelny             uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
260d2238194SKrzysztof Grobelny             auto readingParameters =
261d2238194SKrzysztof Grobelny                 data->at("ReadingParameters")
262d2238194SKrzysztof Grobelny                     .get<std::vector<LabeledMetricParameters>>();
263e2362796SWludzik, Jozef 
264b8cc78ddSKrzysztof Grobelny             addReport(id, name, utils::toReportingType(reportingType),
26551497a0cSKrzysztof Grobelny                       reportActions, Milliseconds(interval), appendLimit,
26651497a0cSKrzysztof Grobelny                       utils::toReportUpdates(reportUpdates),
26751497a0cSKrzysztof Grobelny                       std::move(readingParameters), enabled);
268e2362796SWludzik, Jozef         }
269e2362796SWludzik, Jozef         catch (const std::exception& e)
270e2362796SWludzik, Jozef         {
271e2362796SWludzik, Jozef             phosphor::logging::log<phosphor::logging::level::ERR>(
272e2362796SWludzik, Jozef                 "Failed to load report from storage",
273e2362796SWludzik, Jozef                 phosphor::logging::entry(
274982c5b5bSWludzik, Jozef                     "FILENAME=%s",
275e2362796SWludzik, Jozef                     static_cast<std::filesystem::path>(path).c_str()),
276982c5b5bSWludzik, Jozef                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
277e2362796SWludzik, Jozef             reportStorage->remove(path);
278e2362796SWludzik, Jozef         }
279e2362796SWludzik, Jozef     }
28064b75a5bSKrzysztof Grobelny }
281d960e1f3SWludzik, Jozef 
282b8cc78ddSKrzysztof Grobelny void ReportManager::updateReport(const std::string& id)
283d960e1f3SWludzik, Jozef {
284d960e1f3SWludzik, Jozef     for (auto& report : reports)
285d960e1f3SWludzik, Jozef     {
286b8cc78ddSKrzysztof Grobelny         if (report->getId() == id)
287d960e1f3SWludzik, Jozef         {
288d960e1f3SWludzik, Jozef             report->updateReadings();
289d960e1f3SWludzik, Jozef             return;
290d960e1f3SWludzik, Jozef         }
291d960e1f3SWludzik, Jozef     }
292d960e1f3SWludzik, Jozef }
293