xref: /openbmc/telemetry/src/report_manager.cpp (revision e28aa53d)
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;
60dcc4e193SKrzysztof Grobelny                     return addReport(yield, reportName, reportingType,
61dcc4e193SKrzysztof Grobelny                                      emitsReadingsUpdate,
62dcc4e193SKrzysztof Grobelny                                      logToMetricReportsCollection,
63dcc4e193SKrzysztof Grobelny                                      Milliseconds(interval),
64dcc4e193SKrzysztof Grobelny                                      convertToReadingParameters(
657e098e93SLukasz Kazmierczak                                          std::move(metricParams)),
667e098e93SLukasz Kazmierczak                                      enabledDefault)
67dcc4e193SKrzysztof Grobelny                         .getPath();
68dcc4e193SKrzysztof Grobelny                 });
69dcc4e193SKrzysztof Grobelny 
70dcc4e193SKrzysztof Grobelny             dbusIface.register_method(
71dcc4e193SKrzysztof Grobelny                 "AddReportFutureVersion",
72dcc4e193SKrzysztof Grobelny                 [this](boost::asio::yield_context& yield,
73dcc4e193SKrzysztof Grobelny                        const std::string& reportName,
74dcc4e193SKrzysztof Grobelny                        const std::string& reportingType,
75dcc4e193SKrzysztof Grobelny                        const bool emitsReadingsUpdate,
76dcc4e193SKrzysztof Grobelny                        const bool logToMetricReportsCollection,
77dcc4e193SKrzysztof Grobelny                        const uint64_t interval,
78d2238194SKrzysztof Grobelny                        ReadingParameters metricParams) {
797e098e93SLukasz Kazmierczak                     constexpr auto enabledDefault = true;
80e2362796SWludzik, Jozef                     return addReport(yield, reportName, reportingType,
81e2362796SWludzik, Jozef                                      emitsReadingsUpdate,
82e2362796SWludzik, Jozef                                      logToMetricReportsCollection,
83dcc4e193SKrzysztof Grobelny                                      Milliseconds(interval),
847e098e93SLukasz Kazmierczak                                      std::move(metricParams), enabledDefault)
85d2238194SKrzysztof Grobelny                         .getPath();
86e2362796SWludzik, Jozef                 });
87e2362796SWludzik, Jozef         });
88e2362796SWludzik, Jozef }
89e2362796SWludzik, Jozef 
90e2362796SWludzik, Jozef void ReportManager::removeReport(const interfaces::Report* report)
91e2362796SWludzik, Jozef {
92e2362796SWludzik, Jozef     reports.erase(
93e2362796SWludzik, Jozef         std::remove_if(reports.begin(), reports.end(),
94e2362796SWludzik, Jozef                        [report](const auto& x) { return report == x.get(); }),
95e2362796SWludzik, Jozef         reports.end());
96e2362796SWludzik, Jozef }
97e2362796SWludzik, Jozef 
9832859b63SKarol Niczyj void ReportManager::verifyReportNameLength(const std::string& reportName)
9932859b63SKarol Niczyj {
10032859b63SKarol Niczyj     if (reportName.length() > maxReportNameLength)
10132859b63SKarol Niczyj     {
10232859b63SKarol Niczyj         throw sdbusplus::exception::SdBusError(
10332859b63SKarol Niczyj             static_cast<int>(std::errc::invalid_argument),
104*e28aa53dSSzymon Dompke             "Report name exceeds maximum length");
10532859b63SKarol Niczyj     }
10632859b63SKarol Niczyj }
10732859b63SKarol Niczyj 
108dcc4e193SKrzysztof Grobelny void ReportManager::verifyAddReport(
109dcc4e193SKrzysztof Grobelny     const std::string& reportName, const std::string& reportingType,
110dcc4e193SKrzysztof Grobelny     Milliseconds interval,
111dcc4e193SKrzysztof Grobelny     const std::vector<LabeledMetricParameters>& readingParams)
112e2362796SWludzik, Jozef {
113cb88cfdfSWludzik, Jozef     if (reports.size() >= maxReports)
114cb88cfdfSWludzik, Jozef     {
115cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
116cb88cfdfSWludzik, Jozef             static_cast<int>(std::errc::too_many_files_open),
117cb88cfdfSWludzik, Jozef             "Reached maximal report count");
11864b75a5bSKrzysztof Grobelny     }
11964b75a5bSKrzysztof Grobelny 
12032859b63SKarol Niczyj     verifyReportNameLength(reportName);
12132859b63SKarol Niczyj 
122cb88cfdfSWludzik, Jozef     for (const auto& report : reports)
12364b75a5bSKrzysztof Grobelny     {
1242f9f9b87SWludzik, Jozef         if (report->getName() == reportName)
125cb88cfdfSWludzik, Jozef         {
126cb88cfdfSWludzik, Jozef             throw sdbusplus::exception::SdBusError(
127e2362796SWludzik, Jozef                 static_cast<int>(std::errc::file_exists), "Duplicate report");
128cb88cfdfSWludzik, Jozef         }
129cb88cfdfSWludzik, Jozef     }
130cb88cfdfSWludzik, Jozef 
131bc766b4dSWludzik, Jozef     auto found = std::find(supportedReportingType.begin(),
132bc766b4dSWludzik, Jozef                            supportedReportingType.end(), reportingType);
133bc766b4dSWludzik, Jozef     if (found == supportedReportingType.end())
134bc766b4dSWludzik, Jozef     {
135bc766b4dSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
136bc766b4dSWludzik, Jozef             static_cast<int>(std::errc::invalid_argument),
137bc766b4dSWludzik, Jozef             "Invalid reportingType");
138bc766b4dSWludzik, Jozef     }
139bc766b4dSWludzik, Jozef 
140bc766b4dSWludzik, Jozef     if (reportingType == "Periodic" && interval < minInterval)
141cb88cfdfSWludzik, Jozef     {
142cb88cfdfSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
143e2362796SWludzik, Jozef             static_cast<int>(std::errc::invalid_argument), "Invalid interval");
144cb88cfdfSWludzik, Jozef     }
145bc766b4dSWludzik, Jozef 
146503c1589SWludzik, Jozef     if (readingParams.size() > maxReadingParams)
147e8fc5751SKrzysztof Grobelny 
148bc766b4dSWludzik, Jozef     {
149bc766b4dSWludzik, Jozef         throw sdbusplus::exception::SdBusError(
150bc766b4dSWludzik, Jozef             static_cast<int>(std::errc::argument_list_too_long),
151bc766b4dSWludzik, Jozef             "Too many reading parameters");
152bc766b4dSWludzik, Jozef     }
153e8fc5751SKrzysztof Grobelny 
154e8fc5751SKrzysztof Grobelny     try
155e8fc5751SKrzysztof Grobelny     {
156dcc4e193SKrzysztof Grobelny         namespace ts = utils::tstring;
157dcc4e193SKrzysztof Grobelny 
158dcc4e193SKrzysztof Grobelny         for (const LabeledMetricParameters& item : readingParams)
159e8fc5751SKrzysztof Grobelny         {
160dcc4e193SKrzysztof Grobelny             utils::toOperationType(
161dcc4e193SKrzysztof Grobelny                 utils::toUnderlying(item.at_label<ts::OperationType>()));
162e8fc5751SKrzysztof Grobelny         }
163e8fc5751SKrzysztof Grobelny     }
164e8fc5751SKrzysztof Grobelny     catch (const std::exception& e)
165e8fc5751SKrzysztof Grobelny     {
166e8fc5751SKrzysztof Grobelny         throw sdbusplus::exception::SdBusError(
167e8fc5751SKrzysztof Grobelny             static_cast<int>(std::errc::invalid_argument), e.what());
168e8fc5751SKrzysztof Grobelny     }
169d2238194SKrzysztof Grobelny }
170cb88cfdfSWludzik, Jozef 
171d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
172d2238194SKrzysztof Grobelny     boost::asio::yield_context& yield, const std::string& reportName,
173d2238194SKrzysztof Grobelny     const std::string& reportingType, const bool emitsReadingsUpdate,
174dcc4e193SKrzysztof Grobelny     const bool logToMetricReportsCollection, Milliseconds interval,
1757e098e93SLukasz Kazmierczak     ReadingParameters metricParams, const bool enabled)
176d2238194SKrzysztof Grobelny {
177dcc4e193SKrzysztof Grobelny     auto labeledMetricParams =
178dcc4e193SKrzysztof Grobelny         reportFactory->convertMetricParams(yield, metricParams);
179d2238194SKrzysztof Grobelny 
180dcc4e193SKrzysztof Grobelny     return addReport(reportName, reportingType, emitsReadingsUpdate,
181dcc4e193SKrzysztof Grobelny                      logToMetricReportsCollection, interval,
1827e098e93SLukasz Kazmierczak                      std::move(labeledMetricParams), enabled);
183d2238194SKrzysztof Grobelny }
184d2238194SKrzysztof Grobelny 
185d2238194SKrzysztof Grobelny interfaces::Report& ReportManager::addReport(
186d2238194SKrzysztof Grobelny     const std::string& reportName, const std::string& reportingType,
187d2238194SKrzysztof Grobelny     const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
188dcc4e193SKrzysztof Grobelny     Milliseconds interval,
1897e098e93SLukasz Kazmierczak     std::vector<LabeledMetricParameters> labeledMetricParams,
1907e098e93SLukasz Kazmierczak     const bool enabled)
191d2238194SKrzysztof Grobelny {
192dcc4e193SKrzysztof Grobelny     verifyAddReport(reportName, reportingType, interval, labeledMetricParams);
193d2238194SKrzysztof Grobelny 
194dcc4e193SKrzysztof Grobelny     reports.emplace_back(
195dcc4e193SKrzysztof Grobelny         reportFactory->make(reportName, reportingType, emitsReadingsUpdate,
196dcc4e193SKrzysztof Grobelny                             logToMetricReportsCollection, interval, *this,
1977e098e93SLukasz Kazmierczak                             *reportStorage, labeledMetricParams, enabled));
198d2238194SKrzysztof Grobelny     return *reports.back();
199cb88cfdfSWludzik, Jozef }
200cb88cfdfSWludzik, Jozef 
201e2362796SWludzik, Jozef void ReportManager::loadFromPersistent()
202cb88cfdfSWludzik, Jozef {
203e2362796SWludzik, Jozef     std::vector<interfaces::JsonStorage::FilePath> paths =
204e2362796SWludzik, Jozef         reportStorage->list();
205e2362796SWludzik, Jozef 
206e2362796SWludzik, Jozef     for (const auto& path : paths)
207e2362796SWludzik, Jozef     {
208e2362796SWludzik, Jozef         std::optional<nlohmann::json> data = reportStorage->load(path);
209e2362796SWludzik, Jozef         try
210e2362796SWludzik, Jozef         {
2117e098e93SLukasz Kazmierczak             bool enabled = data->at("Enabled").get<bool>();
212e2362796SWludzik, Jozef             size_t version = data->at("Version").get<size_t>();
213e2362796SWludzik, Jozef             if (version != Report::reportVersion)
214e2362796SWludzik, Jozef             {
215e2362796SWludzik, Jozef                 throw std::logic_error("Invalid version");
216e2362796SWludzik, Jozef             }
217e2362796SWludzik, Jozef             std::string& name = data->at("Name").get_ref<std::string&>();
218e2362796SWludzik, Jozef             std::string& reportingType =
219e2362796SWludzik, Jozef                 data->at("ReportingType").get_ref<std::string&>();
220e2362796SWludzik, Jozef             bool emitsReadingsSignal =
221e2362796SWludzik, Jozef                 data->at("EmitsReadingsUpdate").get<bool>();
222e2362796SWludzik, Jozef             bool logToMetricReportsCollection =
223e2362796SWludzik, Jozef                 data->at("LogToMetricReportsCollection").get<bool>();
224e2362796SWludzik, Jozef             uint64_t interval = data->at("Interval").get<uint64_t>();
225d2238194SKrzysztof Grobelny             auto readingParameters =
226d2238194SKrzysztof Grobelny                 data->at("ReadingParameters")
227d2238194SKrzysztof Grobelny                     .get<std::vector<LabeledMetricParameters>>();
228e2362796SWludzik, Jozef 
229d2238194SKrzysztof Grobelny             addReport(name, reportingType, emitsReadingsSignal,
230dcc4e193SKrzysztof Grobelny                       logToMetricReportsCollection, Milliseconds(interval),
2317e098e93SLukasz Kazmierczak                       std::move(readingParameters), enabled);
232e2362796SWludzik, Jozef         }
233e2362796SWludzik, Jozef         catch (const std::exception& e)
234e2362796SWludzik, Jozef         {
235e2362796SWludzik, Jozef             phosphor::logging::log<phosphor::logging::level::ERR>(
236e2362796SWludzik, Jozef                 "Failed to load report from storage",
237e2362796SWludzik, Jozef                 phosphor::logging::entry(
238982c5b5bSWludzik, Jozef                     "FILENAME=%s",
239e2362796SWludzik, Jozef                     static_cast<std::filesystem::path>(path).c_str()),
240982c5b5bSWludzik, Jozef                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
241e2362796SWludzik, Jozef             reportStorage->remove(path);
242e2362796SWludzik, Jozef         }
243e2362796SWludzik, Jozef     }
24464b75a5bSKrzysztof Grobelny }
245d960e1f3SWludzik, Jozef 
246d960e1f3SWludzik, Jozef void ReportManager::updateReport(const std::string& name)
247d960e1f3SWludzik, Jozef {
248d960e1f3SWludzik, Jozef     for (auto& report : reports)
249d960e1f3SWludzik, Jozef     {
250d960e1f3SWludzik, Jozef         if (report->getName() == name)
251d960e1f3SWludzik, Jozef         {
252d960e1f3SWludzik, Jozef             report->updateReadings();
253d960e1f3SWludzik, Jozef             return;
254d960e1f3SWludzik, Jozef         }
255d960e1f3SWludzik, Jozef     }
256d960e1f3SWludzik, Jozef }
257