xref: /openbmc/telemetry/src/report_manager.cpp (revision c7935fa1)
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"
632305f14SSzymon Dompke #include "utils/dbus_path_utils.hpp"
732305f14SSzymon Dompke #include "utils/make_id_name.hpp"
8d2238194SKrzysztof Grobelny #include "utils/transform.hpp"
9e2362796SWludzik, Jozef 
10e2362796SWludzik, Jozef #include <phosphor-logging/log.hpp>
11cb88cfdfSWludzik, Jozef #include <sdbusplus/exception.hpp>
12a8182bebSKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
13cb88cfdfSWludzik, Jozef 
14a8182bebSKrzysztof Grobelny #include <optional>
15e2362796SWludzik, Jozef #include <stdexcept>
1664b75a5bSKrzysztof Grobelny #include <system_error>
1764b75a5bSKrzysztof Grobelny 
ReportManager(std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,std::unique_ptr<interfaces::JsonStorage> reportStorageIn,const std::shared_ptr<sdbusplus::asio::object_server> & objServerIn)1864b75a5bSKrzysztof Grobelny ReportManager::ReportManager(
192f9f9b87SWludzik, Jozef     std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
20e2362796SWludzik, Jozef     std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
21e6d48874SKrzysztof Grobelny     const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
222f9f9b87SWludzik, Jozef     reportFactory(std::move(reportFactoryIn)),
23e6d48874SKrzysztof Grobelny     reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
2464b75a5bSKrzysztof Grobelny {
25cb88cfdfSWludzik, Jozef     reports.reserve(maxReports);
266ccfcbf5SKrzysztof Grobelny 
27e2362796SWludzik, Jozef     loadFromPersistent();
2864b75a5bSKrzysztof Grobelny 
29cb88cfdfSWludzik, Jozef     reportManagerIface = objServer->add_unique_interface(
30*c7935fa1SPatrick Williams         reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
313a1c297aSPatrick Williams         dbusIface.register_property_r("MaxReports", size_t{},
323a1c297aSPatrick Williams                                       sdbusplus::vtable::property_::const_,
3364b75a5bSKrzysztof Grobelny                                       [](const auto&) { return maxReports; });
34cb88cfdfSWludzik, Jozef         dbusIface.register_property_r(
3564b75a5bSKrzysztof Grobelny             "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
3664b75a5bSKrzysztof Grobelny             [](const auto&) -> uint64_t { return minInterval.count(); });
3760fee077SKrzysztof Grobelny         dbusIface.register_property_r(
3860fee077SKrzysztof Grobelny             "SupportedOperationTypes", std::vector<std::string>{},
3960fee077SKrzysztof Grobelny             sdbusplus::vtable::property_::const_,
4060fee077SKrzysztof Grobelny             [](const auto&) -> std::vector<std::string> {
41fdb06a14SSzymon Dompke             return utils::transform<std::vector>(
423a1c297aSPatrick Williams                 utils::convDataOperationType,
433a1c297aSPatrick Williams                 [](const auto& item) { return std::string(item.first); });
4460fee077SKrzysztof Grobelny         });
45cb88cfdfSWludzik, Jozef         dbusIface.register_method(
463a1c297aSPatrick Williams             "AddReport",
47cff70c14SKrzysztof Grobelny             [this](boost::asio::yield_context& yield, std::string reportId,
48cff70c14SKrzysztof Grobelny                    std::string reportName, std::string reportingType,
49cff70c14SKrzysztof Grobelny                    std::string reportUpdates, uint64_t appendLimit,
50cff70c14SKrzysztof Grobelny                    std::vector<std::string> reportActions, uint64_t interval,
51cff70c14SKrzysztof Grobelny                    ReadingParameters readingParameters, bool enabled) {
52cff70c14SKrzysztof Grobelny             if (reportingType.empty())
5351497a0cSKrzysztof Grobelny             {
54cff70c14SKrzysztof Grobelny                 reportingType = utils::enumToString(ReportingType::onRequest);
5551497a0cSKrzysztof Grobelny             }
5651497a0cSKrzysztof Grobelny 
57cff70c14SKrzysztof Grobelny             if (reportUpdates.empty())
5862c08e9bSKrzysztof Grobelny             {
59cff70c14SKrzysztof Grobelny                 reportUpdates = utils::enumToString(ReportUpdates::overwrite);
6062c08e9bSKrzysztof Grobelny             }
6162c08e9bSKrzysztof Grobelny 
62cff70c14SKrzysztof Grobelny             if (appendLimit == std::numeric_limits<uint64_t>::max())
6362c08e9bSKrzysztof Grobelny             {
64cff70c14SKrzysztof Grobelny                 appendLimit = maxAppendLimit;
6562c08e9bSKrzysztof Grobelny             }
66a8182bebSKrzysztof Grobelny 
67cff70c14SKrzysztof Grobelny             if (interval == std::numeric_limits<uint64_t>::max())
68cff70c14SKrzysztof Grobelny             {
69cff70c14SKrzysztof Grobelny                 interval = 0;
70cff70c14SKrzysztof Grobelny             }
71cff70c14SKrzysztof Grobelny 
72cff70c14SKrzysztof Grobelny             return addReport(yield, reportId, reportName,
73cff70c14SKrzysztof Grobelny                              utils::toReportingType(reportingType),
74*c7935fa1SPatrick Williams                              utils::transform(reportActions,
7551497a0cSKrzysztof Grobelny                                               [](const auto& reportAction) {
763a1c297aSPatrick Williams                 return utils::toReportAction(reportAction);
7751497a0cSKrzysztof Grobelny             }),
78cff70c14SKrzysztof Grobelny                              Milliseconds(interval), appendLimit,
79cff70c14SKrzysztof Grobelny                              utils::toReportUpdates(reportUpdates),
80cff70c14SKrzysztof Grobelny                              readingParameters, enabled)
81d2238194SKrzysztof Grobelny                 .getPath();
82e2362796SWludzik, Jozef         });
83e2362796SWludzik, Jozef     });
84e2362796SWludzik, Jozef }
85e2362796SWludzik, Jozef 
removeReport(const interfaces::Report * report)86e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report)
87e2362796SWludzik, Jozef {
88e2362796SWludzik, Jozef     reports.erase(
89e2362796SWludzik, Jozef         std::remove_if(reports.begin(), reports.end(),
90e2362796SWludzik, Jozef                        [report](const auto& x) { return report == x.get(); }),
91e2362796SWludzik, Jozef         reports.end());
92e2362796SWludzik, Jozef }
93e2362796SWludzik, Jozef 
verifyAddReport(const std::string & reportId,const std::string & reportName,const ReportingType reportingType,Milliseconds interval,const ReportUpdates reportUpdates,const uint64_t appendLimit,const std::vector<LabeledMetricParameters> & readingParams)94dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport(
95b8cc78ddSKrzysztof Grobelny     const std::string& reportId, const std::string& reportName,
96b8cc78ddSKrzysztof Grobelny     const ReportingType reportingType, Milliseconds interval,
97cd5b0b7eSAnkita Vilas Gawade     const ReportUpdates reportUpdates, const uint64_t appendLimit,
98dcc4e193SKrzysztof Grobelny     const std::vector<LabeledMetricParameters>& readingParams)
99e2362796SWludzik, Jozef {
10032305f14SSzymon Dompke     namespace ts = utils::tstring;
10132305f14SSzymon Dompke 
102cb88cfdfSWludzik, Jozef     if (reports.size() >= maxReports)
103cb88cfdfSWludzik, Jozef     {
104cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
105cb88cfdfSWludzik, Jozef             static_cast<int>(std::errc::too_many_files_open),
106cb88cfdfSWludzik, Jozef             "Reached maximal report count");
10764b75a5bSKrzysztof Grobelny     }
10864b75a5bSKrzysztof Grobelny 
109e6c417cfSKrzysztof Grobelny     if (appendLimit > maxAppendLimit &&
110e6c417cfSKrzysztof Grobelny         appendLimit != std::numeric_limits<uint64_t>::max())
111cd5b0b7eSAnkita Vilas Gawade     {
11262c08e9bSKrzysztof Grobelny         throw errors::InvalidArgument("AppendLimit", "Out of range.");
113cd5b0b7eSAnkita Vilas Gawade     }
114cd5b0b7eSAnkita Vilas Gawade 
115973b4bb0SKrzysztof Grobelny     if ((reportingType == ReportingType::periodic && interval < minInterval) ||
116973b4bb0SKrzysztof Grobelny         (reportingType != ReportingType::periodic &&
117973b4bb0SKrzysztof Grobelny          interval != Milliseconds{0}))
118cb88cfdfSWludzik, Jozef     {
11962c08e9bSKrzysztof Grobelny         throw errors::InvalidArgument("Interval");
120cb88cfdfSWludzik, Jozef     }
121bc766b4dSWludzik, Jozef 
122cd5b0b7eSAnkita Vilas Gawade     size_t metricCount = 0;
123cd5b0b7eSAnkita Vilas Gawade     for (auto metricParam : readingParams)
124cd5b0b7eSAnkita Vilas Gawade     {
125cd5b0b7eSAnkita Vilas Gawade         auto metricParamsVec =
126cd5b0b7eSAnkita Vilas Gawade             metricParam.at_label<utils::tstring::SensorPath>();
127cd5b0b7eSAnkita Vilas Gawade         metricCount += metricParamsVec.size();
128cd5b0b7eSAnkita Vilas Gawade     }
129e8fc5751SKrzysztof Grobelny 
130cd5b0b7eSAnkita Vilas Gawade     if (readingParams.size() > maxNumberMetrics ||
131cd5b0b7eSAnkita Vilas Gawade         metricCount > maxNumberMetrics)
132bc766b4dSWludzik, Jozef     {
13362c08e9bSKrzysztof Grobelny         throw errors::InvalidArgument("MetricParams", "Too many.");
134bc766b4dSWludzik, Jozef     }
135e8fc5751SKrzysztof Grobelny 
136dcc4e193SKrzysztof Grobelny     for (const LabeledMetricParameters& item : readingParams)
137e8fc5751SKrzysztof Grobelny     {
138dcc4e193SKrzysztof Grobelny         utils::toOperationType(
139dcc4e193SKrzysztof Grobelny             utils::toUnderlying(item.at_label<ts::OperationType>()));
140e8fc5751SKrzysztof Grobelny     }
141e8fc5751SKrzysztof Grobelny }
142cb88cfdfSWludzik, Jozef 
addReport(boost::asio::yield_context & yield,const std::string & reportId,const std::string & reportName,const ReportingType reportingType,const std::vector<ReportAction> & reportActions,Milliseconds interval,const uint64_t appendLimit,const ReportUpdates reportUpdates,ReadingParameters metricParams,const bool enabled)143d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
144b8cc78ddSKrzysztof Grobelny     boost::asio::yield_context& yield, const std::string& reportId,
145b8cc78ddSKrzysztof Grobelny     const std::string& reportName, const ReportingType reportingType,
14651497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
14751497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
1487e098e93SLukasz Kazmierczak     ReadingParameters metricParams, const bool enabled)
149d2238194SKrzysztof Grobelny {
1503a1c297aSPatrick Williams     auto labeledMetricParams = reportFactory->convertMetricParams(yield,
1513a1c297aSPatrick Williams                                                                   metricParams);
152d2238194SKrzysztof Grobelny 
153b8cc78ddSKrzysztof Grobelny     return addReport(reportId, reportName, reportingType, reportActions,
154b8cc78ddSKrzysztof Grobelny                      interval, appendLimit, reportUpdates,
155493e62ebSKrzysztof Grobelny                      std::move(labeledMetricParams), enabled, Readings{});
156d2238194SKrzysztof Grobelny }
157d2238194SKrzysztof Grobelny 
addReport(const std::string & reportId,const std::string & reportName,const ReportingType reportingType,const std::vector<ReportAction> & reportActions,Milliseconds interval,const uint64_t appendLimit,const ReportUpdates reportUpdates,std::vector<LabeledMetricParameters> labeledMetricParams,const bool enabled,Readings readings)158d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
159b8cc78ddSKrzysztof Grobelny     const std::string& reportId, const std::string& reportName,
160b8cc78ddSKrzysztof Grobelny     const ReportingType reportingType,
16151497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
16251497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
1637e098e93SLukasz Kazmierczak     std::vector<LabeledMetricParameters> labeledMetricParams,
164493e62ebSKrzysztof Grobelny     const bool enabled, Readings readings)
165d2238194SKrzysztof Grobelny {
166b8cc78ddSKrzysztof Grobelny     const auto existingReportIds = utils::transform(
167b8cc78ddSKrzysztof Grobelny         reports, [](const auto& report) { return report->getId(); });
168b8cc78ddSKrzysztof Grobelny 
16932305f14SSzymon Dompke     auto [id, name] = utils::makeIdName(reportId, reportName, reportNameDefault,
17032305f14SSzymon Dompke                                         existingReportIds);
171b8cc78ddSKrzysztof Grobelny 
172b8cc78ddSKrzysztof Grobelny     verifyAddReport(id, name, reportingType, interval, reportUpdates,
173cd5b0b7eSAnkita Vilas Gawade                     appendLimit, labeledMetricParams);
174d2238194SKrzysztof Grobelny 
175493e62ebSKrzysztof Grobelny     reports.emplace_back(
176493e62ebSKrzysztof Grobelny         reportFactory->make(id, name, reportingType, reportActions, interval,
177493e62ebSKrzysztof Grobelny                             appendLimit, reportUpdates, *this, *reportStorage,
178493e62ebSKrzysztof Grobelny                             labeledMetricParams, enabled, std::move(readings)));
179d2238194SKrzysztof Grobelny     return *reports.back();
180cb88cfdfSWludzik, Jozef }
181cb88cfdfSWludzik, Jozef 
loadFromPersistent()182e2362796SWludzik, Jozef void ReportManager::loadFromPersistent()
183cb88cfdfSWludzik, Jozef {
184e2362796SWludzik, Jozef     std::vector<interfaces::JsonStorage::FilePath> paths =
185e2362796SWludzik, Jozef         reportStorage->list();
186e2362796SWludzik, Jozef 
187e2362796SWludzik, Jozef     for (const auto& path : paths)
188e2362796SWludzik, Jozef     {
189e2362796SWludzik, Jozef         std::optional<nlohmann::json> data = reportStorage->load(path);
190e2362796SWludzik, Jozef         try
191e2362796SWludzik, Jozef         {
192e2362796SWludzik, Jozef             size_t version = data->at("Version").get<size_t>();
193e2362796SWludzik, Jozef             if (version != Report::reportVersion)
194e2362796SWludzik, Jozef             {
195e2362796SWludzik, Jozef                 throw std::logic_error("Invalid version");
196e2362796SWludzik, Jozef             }
197b8cc78ddSKrzysztof Grobelny             bool enabled = data->at("Enabled").get<bool>();
198b8cc78ddSKrzysztof Grobelny             std::string& id = data->at("Id").get_ref<std::string&>();
199e2362796SWludzik, Jozef             std::string& name = data->at("Name").get_ref<std::string&>();
20051497a0cSKrzysztof Grobelny 
20151497a0cSKrzysztof Grobelny             uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
20251497a0cSKrzysztof Grobelny             std::vector<ReportAction> reportActions = utils::transform(
20351497a0cSKrzysztof Grobelny                 data->at("ReportActions").get<std::vector<uint32_t>>(),
20451497a0cSKrzysztof Grobelny                 [](const auto reportAction) {
20551497a0cSKrzysztof Grobelny                 return utils::toReportAction(reportAction);
20651497a0cSKrzysztof Grobelny             });
207e2362796SWludzik, Jozef             uint64_t interval = data->at("Interval").get<uint64_t>();
2083eb56865SSzymon Dompke             uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
20951497a0cSKrzysztof Grobelny             uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
210d2238194SKrzysztof Grobelny             auto readingParameters =
211d2238194SKrzysztof Grobelny                 data->at("ReadingParameters")
212d2238194SKrzysztof Grobelny                     .get<std::vector<LabeledMetricParameters>>();
213e2362796SWludzik, Jozef 
214493e62ebSKrzysztof Grobelny             Readings readings = {};
215493e62ebSKrzysztof Grobelny 
216493e62ebSKrzysztof Grobelny             if (auto it = data->find("MetricValues"); it != data->end())
217493e62ebSKrzysztof Grobelny             {
218493e62ebSKrzysztof Grobelny                 const auto labeledReadings = it->get<LabeledReadings>();
219493e62ebSKrzysztof Grobelny                 readings = utils::toReadings(labeledReadings);
220493e62ebSKrzysztof Grobelny             }
221493e62ebSKrzysztof Grobelny 
222b8cc78ddSKrzysztof Grobelny             addReport(id, name, utils::toReportingType(reportingType),
22351497a0cSKrzysztof Grobelny                       reportActions, Milliseconds(interval), appendLimit,
22451497a0cSKrzysztof Grobelny                       utils::toReportUpdates(reportUpdates),
225493e62ebSKrzysztof Grobelny                       std::move(readingParameters), enabled,
226493e62ebSKrzysztof Grobelny                       std::move(readings));
227e2362796SWludzik, Jozef         }
228e2362796SWludzik, Jozef         catch (const std::exception& e)
229e2362796SWludzik, Jozef         {
230e2362796SWludzik, Jozef             phosphor::logging::log<phosphor::logging::level::ERR>(
231e2362796SWludzik, Jozef                 "Failed to load report from storage",
232e2362796SWludzik, Jozef                 phosphor::logging::entry(
233982c5b5bSWludzik, Jozef                     "FILENAME=%s",
234e2362796SWludzik, Jozef                     static_cast<std::filesystem::path>(path).c_str()),
235982c5b5bSWludzik, Jozef                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
236e2362796SWludzik, Jozef             reportStorage->remove(path);
237e2362796SWludzik, Jozef         }
238e2362796SWludzik, Jozef     }
23964b75a5bSKrzysztof Grobelny }
240