xref: /openbmc/telemetry/src/report_manager.cpp (revision 973b4bb0)
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,
35e6d48874SKrzysztof Grobelny     const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
362f9f9b87SWludzik, Jozef     reportFactory(std::move(reportFactoryIn)),
37e6d48874SKrzysztof Grobelny     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(); });
5560fee077SKrzysztof Grobelny             dbusIface.register_property_r(
5660fee077SKrzysztof Grobelny                 "SupportedOperationTypes", std::vector<std::string>{},
5760fee077SKrzysztof Grobelny                 sdbusplus::vtable::property_::const_,
5860fee077SKrzysztof Grobelny                 [](const auto&) -> std::vector<std::string> {
59fdb06a14SSzymon Dompke                     return utils::transform<std::vector>(
6060fee077SKrzysztof Grobelny                         utils::convDataOperationType, [](const auto& item) {
6160fee077SKrzysztof Grobelny                             return std::string(item.first);
6260fee077SKrzysztof Grobelny                         });
6360fee077SKrzysztof Grobelny                 });
6464b75a5bSKrzysztof Grobelny 
65cb88cfdfSWludzik, Jozef             dbusIface.register_method(
66e2362796SWludzik, Jozef                 "AddReport", [this](boost::asio::yield_context& yield,
67b8cc78ddSKrzysztof Grobelny                                     const std::string& reportId,
68cb88cfdfSWludzik, Jozef                                     const std::string& reportingType,
69cb88cfdfSWludzik, Jozef                                     const bool emitsReadingsUpdate,
70cb88cfdfSWludzik, Jozef                                     const bool logToMetricReportsCollection,
71cb88cfdfSWludzik, Jozef                                     const uint64_t interval,
72dcc4e193SKrzysztof Grobelny                                     ReadingParametersPastVersion metricParams) {
737e098e93SLukasz Kazmierczak                     constexpr auto enabledDefault = true;
743eb56865SSzymon Dompke                     constexpr uint64_t appendLimitDefault = 0;
753eb56865SSzymon Dompke                     constexpr ReportUpdates reportUpdatesDefault =
7651497a0cSKrzysztof Grobelny                         ReportUpdates::overwrite;
7751497a0cSKrzysztof Grobelny 
7851497a0cSKrzysztof Grobelny                     std::vector<ReportAction> reportActions;
7951497a0cSKrzysztof Grobelny 
8051497a0cSKrzysztof Grobelny                     if (emitsReadingsUpdate)
8151497a0cSKrzysztof Grobelny                     {
8251497a0cSKrzysztof Grobelny                         reportActions.emplace_back(
8351497a0cSKrzysztof Grobelny                             ReportAction::emitsReadingsUpdate);
8451497a0cSKrzysztof Grobelny                     }
8551497a0cSKrzysztof Grobelny                     if (logToMetricReportsCollection)
8651497a0cSKrzysztof Grobelny                     {
8751497a0cSKrzysztof Grobelny                         reportActions.emplace_back(
8851497a0cSKrzysztof Grobelny                             ReportAction::logToMetricReportsCollection);
8951497a0cSKrzysztof Grobelny                     }
9051497a0cSKrzysztof Grobelny 
91b8cc78ddSKrzysztof Grobelny                     return addReport(yield, reportId, reportId,
9251497a0cSKrzysztof Grobelny                                      utils::toReportingType(reportingType),
9351497a0cSKrzysztof Grobelny                                      reportActions, Milliseconds(interval),
9451497a0cSKrzysztof Grobelny                                      appendLimitDefault, reportUpdatesDefault,
95dcc4e193SKrzysztof Grobelny                                      convertToReadingParameters(
967e098e93SLukasz Kazmierczak                                          std::move(metricParams)),
977e098e93SLukasz Kazmierczak                                      enabledDefault)
98dcc4e193SKrzysztof Grobelny                         .getPath();
99dcc4e193SKrzysztof Grobelny                 });
100dcc4e193SKrzysztof Grobelny 
101dcc4e193SKrzysztof Grobelny             dbusIface.register_method(
102dcc4e193SKrzysztof Grobelny                 "AddReportFutureVersion",
103b8cc78ddSKrzysztof Grobelny                 [this](
104b8cc78ddSKrzysztof Grobelny                     boost::asio::yield_context& yield,
105b8cc78ddSKrzysztof Grobelny                     const std::string& reportId, const std::string& reportName,
106dcc4e193SKrzysztof Grobelny                     const std::string& reportingType,
1073eb56865SSzymon Dompke                     const std::string& reportUpdates,
10851497a0cSKrzysztof Grobelny                     const uint64_t appendLimit,
10951497a0cSKrzysztof Grobelny                     const std::vector<std::string>& reportActions,
110b8cc78ddSKrzysztof Grobelny                     const uint64_t interval, ReadingParameters metricParams) {
1117e098e93SLukasz Kazmierczak                     constexpr auto enabledDefault = true;
112b8cc78ddSKrzysztof Grobelny                     return addReport(yield, reportId, reportName,
11351497a0cSKrzysztof Grobelny                                      utils::toReportingType(reportingType),
11451497a0cSKrzysztof Grobelny                                      utils::transform(
11551497a0cSKrzysztof Grobelny                                          reportActions,
11651497a0cSKrzysztof Grobelny                                          [](const auto& reportAction) {
11751497a0cSKrzysztof Grobelny                                              return utils::toReportAction(
11851497a0cSKrzysztof Grobelny                                                  reportAction);
11951497a0cSKrzysztof Grobelny                                          }),
1203eb56865SSzymon Dompke                                      Milliseconds(interval), appendLimit,
12151497a0cSKrzysztof Grobelny                                      utils::toReportUpdates(reportUpdates),
12251497a0cSKrzysztof Grobelny                                      std::move(metricParams), enabledDefault)
123d2238194SKrzysztof Grobelny                         .getPath();
124e2362796SWludzik, Jozef                 });
125e2362796SWludzik, Jozef         });
126e2362796SWludzik, Jozef }
127e2362796SWludzik, Jozef 
128e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report)
129e2362796SWludzik, Jozef {
130e2362796SWludzik, Jozef     reports.erase(
131e2362796SWludzik, Jozef         std::remove_if(reports.begin(), reports.end(),
132e2362796SWludzik, Jozef                        [report](const auto& x) { return report == x.get(); }),
133e2362796SWludzik, Jozef         reports.end());
134e2362796SWludzik, Jozef }
135e2362796SWludzik, Jozef 
136dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport(
137b8cc78ddSKrzysztof Grobelny     const std::string& reportId, const std::string& reportName,
138b8cc78ddSKrzysztof Grobelny     const ReportingType reportingType, Milliseconds interval,
139cd5b0b7eSAnkita Vilas Gawade     const ReportUpdates reportUpdates, const uint64_t appendLimit,
140dcc4e193SKrzysztof Grobelny     const std::vector<LabeledMetricParameters>& readingParams)
141e2362796SWludzik, Jozef {
142cb88cfdfSWludzik, Jozef     if (reports.size() >= maxReports)
143cb88cfdfSWludzik, Jozef     {
144cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
145cb88cfdfSWludzik, Jozef             static_cast<int>(std::errc::too_many_files_open),
146cb88cfdfSWludzik, Jozef             "Reached maximal report count");
14764b75a5bSKrzysztof Grobelny     }
14864b75a5bSKrzysztof Grobelny 
149e6c417cfSKrzysztof Grobelny     if (appendLimit > maxAppendLimit &&
150e6c417cfSKrzysztof Grobelny         appendLimit != std::numeric_limits<uint64_t>::max())
151cd5b0b7eSAnkita Vilas Gawade     {
152cd5b0b7eSAnkita Vilas Gawade         throw sdbusplus::exception::SdBusError(
153cd5b0b7eSAnkita Vilas Gawade             static_cast<int>(std::errc::invalid_argument),
154cd5b0b7eSAnkita Vilas Gawade             "Append limit out of range");
155cd5b0b7eSAnkita Vilas Gawade     }
156cd5b0b7eSAnkita Vilas Gawade 
157*973b4bb0SKrzysztof Grobelny     if ((reportingType == ReportingType::periodic && interval < minInterval) ||
158*973b4bb0SKrzysztof Grobelny         (reportingType != ReportingType::periodic &&
159*973b4bb0SKrzysztof Grobelny          interval != Milliseconds{0}))
160cb88cfdfSWludzik, Jozef     {
161cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
162e2362796SWludzik, Jozef             static_cast<int>(std::errc::invalid_argument), "Invalid interval");
163cb88cfdfSWludzik, Jozef     }
164bc766b4dSWludzik, Jozef 
165cd5b0b7eSAnkita Vilas Gawade     size_t metricCount = 0;
166cd5b0b7eSAnkita Vilas Gawade     for (auto metricParam : readingParams)
167cd5b0b7eSAnkita Vilas Gawade     {
168cd5b0b7eSAnkita Vilas Gawade         auto metricParamsVec =
169cd5b0b7eSAnkita Vilas Gawade             metricParam.at_label<utils::tstring::SensorPath>();
170cd5b0b7eSAnkita Vilas Gawade         metricCount += metricParamsVec.size();
171cd5b0b7eSAnkita Vilas Gawade     }
172e8fc5751SKrzysztof Grobelny 
173cd5b0b7eSAnkita Vilas Gawade     if (readingParams.size() > maxNumberMetrics ||
174cd5b0b7eSAnkita Vilas Gawade         metricCount > maxNumberMetrics)
175bc766b4dSWludzik, Jozef     {
176bc766b4dSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
177bc766b4dSWludzik, Jozef             static_cast<int>(std::errc::argument_list_too_long),
178bc766b4dSWludzik, Jozef             "Too many reading parameters");
179bc766b4dSWludzik, Jozef     }
180e8fc5751SKrzysztof Grobelny 
181e8fc5751SKrzysztof Grobelny     try
182e8fc5751SKrzysztof Grobelny     {
183dcc4e193SKrzysztof Grobelny         namespace ts = utils::tstring;
184dcc4e193SKrzysztof Grobelny 
185dcc4e193SKrzysztof Grobelny         for (const LabeledMetricParameters& item : readingParams)
186e8fc5751SKrzysztof Grobelny         {
187dcc4e193SKrzysztof Grobelny             utils::toOperationType(
188dcc4e193SKrzysztof Grobelny                 utils::toUnderlying(item.at_label<ts::OperationType>()));
189e8fc5751SKrzysztof Grobelny         }
190e8fc5751SKrzysztof Grobelny     }
191e8fc5751SKrzysztof Grobelny     catch (const std::exception& e)
192e8fc5751SKrzysztof Grobelny     {
193e8fc5751SKrzysztof Grobelny         throw sdbusplus::exception::SdBusError(
194e8fc5751SKrzysztof Grobelny             static_cast<int>(std::errc::invalid_argument), e.what());
195e8fc5751SKrzysztof Grobelny     }
196d2238194SKrzysztof Grobelny }
197cb88cfdfSWludzik, Jozef 
198d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
199b8cc78ddSKrzysztof Grobelny     boost::asio::yield_context& yield, const std::string& reportId,
200b8cc78ddSKrzysztof Grobelny     const std::string& reportName, const ReportingType reportingType,
20151497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
20251497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
2037e098e93SLukasz Kazmierczak     ReadingParameters metricParams, const bool enabled)
204d2238194SKrzysztof Grobelny {
205dcc4e193SKrzysztof Grobelny     auto labeledMetricParams =
206dcc4e193SKrzysztof Grobelny         reportFactory->convertMetricParams(yield, metricParams);
207d2238194SKrzysztof Grobelny 
208b8cc78ddSKrzysztof Grobelny     return addReport(reportId, reportName, reportingType, reportActions,
209b8cc78ddSKrzysztof Grobelny                      interval, appendLimit, reportUpdates,
210493e62ebSKrzysztof Grobelny                      std::move(labeledMetricParams), enabled, Readings{});
211d2238194SKrzysztof Grobelny }
212d2238194SKrzysztof Grobelny 
213d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
214b8cc78ddSKrzysztof Grobelny     const std::string& reportId, const std::string& reportName,
215b8cc78ddSKrzysztof Grobelny     const ReportingType reportingType,
21651497a0cSKrzysztof Grobelny     const std::vector<ReportAction>& reportActions, Milliseconds interval,
21751497a0cSKrzysztof Grobelny     const uint64_t appendLimit, const ReportUpdates reportUpdates,
2187e098e93SLukasz Kazmierczak     std::vector<LabeledMetricParameters> labeledMetricParams,
219493e62ebSKrzysztof Grobelny     const bool enabled, Readings readings)
220d2238194SKrzysztof Grobelny {
221b8cc78ddSKrzysztof Grobelny     const auto existingReportIds = utils::transform(
222b8cc78ddSKrzysztof Grobelny         reports, [](const auto& report) { return report->getId(); });
223b8cc78ddSKrzysztof Grobelny 
224a950e42bSKrzysztof Grobelny     auto [id, name] = utils::generateId(reportId, reportName, reportNameDefault,
225a950e42bSKrzysztof Grobelny                                         existingReportIds, maxReportIdLength);
226b8cc78ddSKrzysztof Grobelny 
227b8cc78ddSKrzysztof Grobelny     verifyAddReport(id, name, reportingType, interval, reportUpdates,
228cd5b0b7eSAnkita Vilas Gawade                     appendLimit, labeledMetricParams);
229d2238194SKrzysztof Grobelny 
230493e62ebSKrzysztof Grobelny     reports.emplace_back(
231493e62ebSKrzysztof Grobelny         reportFactory->make(id, name, reportingType, reportActions, interval,
232493e62ebSKrzysztof Grobelny                             appendLimit, reportUpdates, *this, *reportStorage,
233493e62ebSKrzysztof Grobelny                             labeledMetricParams, enabled, std::move(readings)));
234d2238194SKrzysztof Grobelny     return *reports.back();
235cb88cfdfSWludzik, Jozef }
236cb88cfdfSWludzik, Jozef 
237e2362796SWludzik, Jozef void ReportManager::loadFromPersistent()
238cb88cfdfSWludzik, Jozef {
239e2362796SWludzik, Jozef     std::vector<interfaces::JsonStorage::FilePath> paths =
240e2362796SWludzik, Jozef         reportStorage->list();
241e2362796SWludzik, Jozef 
242e2362796SWludzik, Jozef     for (const auto& path : paths)
243e2362796SWludzik, Jozef     {
244e2362796SWludzik, Jozef         std::optional<nlohmann::json> data = reportStorage->load(path);
245e2362796SWludzik, Jozef         try
246e2362796SWludzik, Jozef         {
247e2362796SWludzik, Jozef             size_t version = data->at("Version").get<size_t>();
248e2362796SWludzik, Jozef             if (version != Report::reportVersion)
249e2362796SWludzik, Jozef             {
250e2362796SWludzik, Jozef                 throw std::logic_error("Invalid version");
251e2362796SWludzik, Jozef             }
252b8cc78ddSKrzysztof Grobelny             bool enabled = data->at("Enabled").get<bool>();
253b8cc78ddSKrzysztof Grobelny             std::string& id = data->at("Id").get_ref<std::string&>();
254e2362796SWludzik, Jozef             std::string& name = data->at("Name").get_ref<std::string&>();
25551497a0cSKrzysztof Grobelny 
25651497a0cSKrzysztof Grobelny             uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
25751497a0cSKrzysztof Grobelny             std::vector<ReportAction> reportActions = utils::transform(
25851497a0cSKrzysztof Grobelny                 data->at("ReportActions").get<std::vector<uint32_t>>(),
25951497a0cSKrzysztof Grobelny                 [](const auto reportAction) {
26051497a0cSKrzysztof Grobelny                     return utils::toReportAction(reportAction);
26151497a0cSKrzysztof Grobelny                 });
262e2362796SWludzik, Jozef             uint64_t interval = data->at("Interval").get<uint64_t>();
2633eb56865SSzymon Dompke             uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
26451497a0cSKrzysztof Grobelny             uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
265d2238194SKrzysztof Grobelny             auto readingParameters =
266d2238194SKrzysztof Grobelny                 data->at("ReadingParameters")
267d2238194SKrzysztof Grobelny                     .get<std::vector<LabeledMetricParameters>>();
268e2362796SWludzik, Jozef 
269493e62ebSKrzysztof Grobelny             Readings readings = {};
270493e62ebSKrzysztof Grobelny 
271493e62ebSKrzysztof Grobelny             if (auto it = data->find("MetricValues"); it != data->end())
272493e62ebSKrzysztof Grobelny             {
273493e62ebSKrzysztof Grobelny                 const auto labeledReadings = it->get<LabeledReadings>();
274493e62ebSKrzysztof Grobelny                 readings = utils::toReadings(labeledReadings);
275493e62ebSKrzysztof Grobelny             }
276493e62ebSKrzysztof Grobelny 
277b8cc78ddSKrzysztof Grobelny             addReport(id, name, utils::toReportingType(reportingType),
27851497a0cSKrzysztof Grobelny                       reportActions, Milliseconds(interval), appendLimit,
27951497a0cSKrzysztof Grobelny                       utils::toReportUpdates(reportUpdates),
280493e62ebSKrzysztof Grobelny                       std::move(readingParameters), enabled,
281493e62ebSKrzysztof Grobelny                       std::move(readings));
282e2362796SWludzik, Jozef         }
283e2362796SWludzik, Jozef         catch (const std::exception& e)
284e2362796SWludzik, Jozef         {
285e2362796SWludzik, Jozef             phosphor::logging::log<phosphor::logging::level::ERR>(
286e2362796SWludzik, Jozef                 "Failed to load report from storage",
287e2362796SWludzik, Jozef                 phosphor::logging::entry(
288982c5b5bSWludzik, Jozef                     "FILENAME=%s",
289e2362796SWludzik, Jozef                     static_cast<std::filesystem::path>(path).c_str()),
290982c5b5bSWludzik, Jozef                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
291e2362796SWludzik, Jozef             reportStorage->remove(path);
292e2362796SWludzik, Jozef         }
293e2362796SWludzik, Jozef     }
29464b75a5bSKrzysztof Grobelny }
295